From nobody Wed Dec 17 20:41:17 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B5F6220A5DE for ; Fri, 14 Mar 2025 19:29:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741980572; cv=none; b=M0rWL6VGouZQOQR5AuBdzBKW/+KhlvZcbcY7tLiRd/hjSiTCsN9w1PPB9WQvZyVKTK2TNsfiGK8Ve5TVD6DWqVzFz/JjLcWIYX8hA5uClKNOi4myv9e4TvKObBF9FRh0RwA1S64WKs/AHVjqrWY7nZY56+6P+HPp3cOi0KFmGxk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741980572; c=relaxed/simple; bh=KyZF3sb610UPzWkHD9K7JAZK25xgze011L6w0Ci3vzk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=IOrZdj9pmjqfg/L5Yzl3pLQdzzM0yxkbfr+O/oD0nElBCcmO1EFt2GFeDp+6mYeWr4xep+NbBheaKHgs7/PbGMt+gIJlOhxpRAPxUasVJ+9n1580mJrihUTlPf7UgHISTJ7HVyDvraHFHAr+YJMKR7z9sC1iNal3jrVqxF7bfAw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=QdO/gDMV; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="QdO/gDMV" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 0DEEBC4CEF0; Fri, 14 Mar 2025 19:29:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1741980572; bh=KyZF3sb610UPzWkHD9K7JAZK25xgze011L6w0Ci3vzk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=QdO/gDMVZrIFMYTUvBe3omaxZEZfrPtvwZXNakSbQwfrzuLXKtEQt3/1fQxi9UNET Q4oO3Zjxcsm2fCyr+ivzQLSRr1nD/2Y2WuHMuVatgxX3dV1S2YeMg42ey7/ce3V2dI o6+hWfbC/XXbzy/mTXoKpwcmSdA0LCLUKt3KO/gYsfKJGHnMBBpxFGV1lSXpMx07wX 9u1rJThjMcfNgEQGIHnH/HUuLjZ4yEYdh+ueqGREohxrbELGF7cDTNft78F4w6OuXx qfCpmTwRZvSTSLHwl91nTO8X8yedEzUQVSaT3ZuptG7HUA1PFbGn2pRPfUPEbC1oCI WBJ19rLqhHbqg== From: Josh Poimboeuf To: x86@kernel.org Cc: linux-kernel@vger.kernel.org, Peter Zijlstra , Brendan Jackman , Nathan Chancellor Subject: [PATCH 09/13] objtool: Add --output option Date: Fri, 14 Mar 2025 12:29:07 -0700 Message-ID: <0da308d42d82b3bbed16a31a72d6bde52afcd6bd.1741975349.git.jpoimboe@kernel.org> X-Mailer: git-send-email 2.48.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add option to allow writing the changed binary to a separate file rather than changing it in place. Libelf makes this suprisingly hard, so take the easy way out and just copy the file before editing it. Also steal the -o short option from --orc. Nobody will notice ;-) Signed-off-by: Josh Poimboeuf Reviewed-by: Miroslav Benes --- tools/objtool/builtin-check.c | 98 ++++++++++++++++++++----- tools/objtool/elf.c | 3 - tools/objtool/include/objtool/builtin.h | 1 + tools/objtool/objtool.c | 15 ++-- tools/objtool/orc_dump.c | 7 +- 5 files changed, 89 insertions(+), 35 deletions(-) diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c index 79843512a51b..3de3afa0a19c 100644 --- a/tools/objtool/builtin-check.c +++ b/tools/objtool/builtin-check.c @@ -6,6 +6,10 @@ #include #include #include +#include +#include +#include +#include #include #include =20 @@ -14,6 +18,8 @@ "error: objtool: " format "\n", \ ##__VA_ARGS__) =20 +const char *objname; + struct opts opts; =20 static const char * const check_usage[] =3D { @@ -71,7 +77,7 @@ static const struct option check_options[] =3D { OPT_BOOLEAN('i', "ibt", &opts.ibt, "validate and annotate IBT"), OPT_BOOLEAN('m', "mcount", &opts.mcount, "annotate mcount/fentry calls fo= r ftrace"), OPT_BOOLEAN('n', "noinstr", &opts.noinstr, "validate noinstr rules"), - OPT_BOOLEAN('o', "orc", &opts.orc, "generate ORC metadata"), + OPT_BOOLEAN(0, "orc", &opts.orc, "generate ORC metadata"), OPT_BOOLEAN('r', "retpoline", &opts.retpoline, "validate and annotate ret= poline usage"), OPT_BOOLEAN(0, "rethunk", &opts.rethunk, "validate and annotate rethunk= usage"), OPT_BOOLEAN(0, "unret", &opts.unret, "validate entry unret placement"), @@ -84,15 +90,16 @@ static const struct option check_options[] =3D { OPT_CALLBACK_OPTARG(0, "dump", NULL, NULL, "orc", "dump metadata", parse_= dump), =20 OPT_GROUP("Options:"), - OPT_BOOLEAN(0, "backtrace", &opts.backtrace, "unwind on error"), - OPT_BOOLEAN(0, "backup", &opts.backup, "create .orig files before modific= ation"), - OPT_BOOLEAN(0, "dry-run", &opts.dryrun, "don't write modifications"), - OPT_BOOLEAN(0, "link", &opts.link, "object is a linked object"), - OPT_BOOLEAN(0, "module", &opts.module, "object is part of a kernel module= "), - OPT_BOOLEAN(0, "mnop", &opts.mnop, "nop out mcount call sites"), - OPT_BOOLEAN(0, "no-unreachable", &opts.no_unreachable, "skip 'unreachable= instruction' warnings"), - OPT_BOOLEAN(0, "sec-address", &opts.sec_address, "print section addresses= in warnings"), - OPT_BOOLEAN(0, "stats", &opts.stats, "print statistics"), + OPT_BOOLEAN(0, "backtrace", &opts.backtrace, "unwind on error"), + OPT_BOOLEAN(0, "backup", &opts.backup, "create .orig files before modif= ication"), + OPT_BOOLEAN(0, "dry-run", &opts.dryrun, "don't write modifications"), + OPT_BOOLEAN(0, "link", &opts.link, "object is a linked object"), + OPT_BOOLEAN(0, "module", &opts.module, "object is part of a kernel modu= le"), + OPT_BOOLEAN(0, "mnop", &opts.mnop, "nop out mcount call sites"), + OPT_BOOLEAN(0, "no-unreachable", &opts.no_unreachable, "skip 'unreachab= le instruction' warnings"), + OPT_STRING('o', "output", &opts.output, "file", "output file name"), + OPT_BOOLEAN(0, "sec-address", &opts.sec_address, "print section address= es in warnings"), + OPT_BOOLEAN(0, "stats", &opts.stats, "print statistics"), OPT_BOOLEAN('v', "verbose", &opts.verbose, "verbose warnings"), =20 OPT_END(), @@ -178,24 +185,75 @@ static bool opts_valid(void) return false; } =20 +static int copy_file(const char *src, const char *dst) +{ + size_t to_copy, copied; + int dst_fd, src_fd; + struct stat stat; + off_t offset =3D 0; + + src_fd =3D open(src, O_RDONLY); + if (src_fd =3D=3D -1) { + ERROR("can't open '%s' for reading", src); + return 1; + } + + dst_fd =3D open(dst, O_WRONLY | O_CREAT | O_TRUNC); + if (dst_fd =3D=3D -1) { + ERROR("can't open '%s' for writing", dst); + return 1; + } + + if (fstat(src_fd, &stat) =3D=3D -1) { + perror("fstat"); + return 1; + } + + if (fchmod(dst_fd, stat.st_mode) =3D=3D -1) { + perror("fchmod"); + return 1; + } + + for (to_copy =3D stat.st_size; to_copy > 0; to_copy -=3D copied) { + copied =3D sendfile(dst_fd, src_fd, &offset, to_copy); + if (copied =3D=3D -1) { + perror("sendfile"); + return 1; + } + } + + close(dst_fd); + close(src_fd); + return 0; +} + int objtool_run(int argc, const char **argv) { - const char *objname; struct objtool_file *file; int ret; =20 - argc =3D cmd_parse_options(argc, argv, check_usage); - objname =3D argv[0]; + cmd_parse_options(argc, argv, check_usage); =20 if (!opts_valid()) return 1; =20 + objname =3D argv[0]; + if (opts.dump_orc) return orc_dump(objname); =20 + if (!opts.dryrun && opts.output) { + /* copy original .o file to output file */ + if (copy_file(objname, opts.output)) + return 1; + + /* from here on, work directly on the output file */ + objname =3D opts.output; + } + file =3D objtool_open_read(objname); if (!file) - return 1; + goto err; =20 if (!opts.link && has_multiple_files(file->elf)) { ERROR("Linked object requires --link"); @@ -204,10 +262,16 @@ int objtool_run(int argc, const char **argv) =20 ret =3D check(file); if (ret) - return ret; + goto err; =20 - if (file->elf->changed) - return elf_write(file->elf); + if (!opts.dryrun && file->elf->changed && elf_write(file->elf)) + goto err; =20 return 0; + +err: + if (opts.output) + unlink(opts.output); + + return 1; } diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 6f64d611faea..be4f4b62730c 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -1302,9 +1302,6 @@ int elf_write(struct elf *elf) struct section *sec; Elf_Scn *s; =20 - if (opts.dryrun) - return 0; - /* Update changed relocation sections and section headers: */ list_for_each_entry(sec, &elf->sections, list) { if (sec->truncate) diff --git a/tools/objtool/include/objtool/builtin.h b/tools/objtool/includ= e/objtool/builtin.h index fcca6662c8b4..25cfa01758b9 100644 --- a/tools/objtool/include/objtool/builtin.h +++ b/tools/objtool/include/objtool/builtin.h @@ -35,6 +35,7 @@ struct opts { bool mnop; bool module; bool no_unreachable; + const char *output; bool sec_address; bool stats; bool verbose; diff --git a/tools/objtool/objtool.c b/tools/objtool/objtool.c index f40febdd6e36..53cd881c6b95 100644 --- a/tools/objtool/objtool.c +++ b/tools/objtool/objtool.c @@ -18,7 +18,6 @@ =20 bool help; =20 -const char *objname; static struct objtool_file file; =20 static bool objtool_create_backup(const char *_objname) @@ -79,18 +78,14 @@ static bool objtool_create_backup(const char *_objname) return true; } =20 -struct objtool_file *objtool_open_read(const char *_objname) +struct objtool_file *objtool_open_read(const char *filename) { - if (objname) { - if (strcmp(objname, _objname)) { - WARN("won't handle more than one file at a time"); - return NULL; - } - return &file; + if (file.elf) { + WARN("won't handle more than one file at a time"); + return NULL; } - objname =3D _objname; =20 - file.elf =3D elf_open_read(objname, O_RDWR); + file.elf =3D elf_open_read(filename, O_RDWR); if (!file.elf) return NULL; =20 diff --git a/tools/objtool/orc_dump.c b/tools/objtool/orc_dump.c index a62247efb64f..05ef0e297837 100644 --- a/tools/objtool/orc_dump.c +++ b/tools/objtool/orc_dump.c @@ -10,7 +10,7 @@ #include #include =20 -int orc_dump(const char *_objname) +int orc_dump(const char *filename) { int fd, nr_entries, i, *orc_ip =3D NULL, orc_size =3D 0; struct orc_entry *orc =3D NULL; @@ -26,12 +26,9 @@ int orc_dump(const char *_objname) Elf_Data *data, *symtab =3D NULL, *rela_orc_ip =3D NULL; struct elf dummy_elf =3D {}; =20 - - objname =3D _objname; - elf_version(EV_CURRENT); =20 - fd =3D open(objname, O_RDONLY); + fd =3D open(filename, O_RDONLY); if (fd =3D=3D -1) { perror("open"); return -1; --=20 2.48.1