From nobody Thu Dec 18 11:31:34 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 989141F0E33 for ; Mon, 24 Mar 2025 21:56:25 +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=1742853385; cv=none; b=E9Y+/49q7sYhbskZmbmAmm6QFMve4BqSIakSezOwOFrYLnYyqxFBvPxJLCcaU1/sJYc+D/dFRSg6uO3W2qh5uNOZaNkW2LX+bdrdgnKTIsiI+sDavKFwHspqRlTdQdDweeVFBrV0pKmsn5or6rqqJj8jaE0/wrzy+5OD07cdLw4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1742853385; c=relaxed/simple; bh=htKuAgBtxznk8XoKZ/fdDpVaxG/T+dMhv3XQNAQjdaY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=j4eBpIasRUrW81oVNNPDVjGjjLWptM5WmT2P4/z3TMCzrDSEW6iDREff/mnKxWqWtD6qWoxztKLeCbWqQem/QLCQwaJz8r/B+xJiklMrAw/RWUQMQFQCIwNXIcL/ARxT7Iy5VwQ+nmzkSvGadsdAo+WGoSgShE2uFv/U99oQg8c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=OIGBRRpP; 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="OIGBRRpP" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2D0B3C4CEED; Mon, 24 Mar 2025 21:56:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1742853385; bh=htKuAgBtxznk8XoKZ/fdDpVaxG/T+dMhv3XQNAQjdaY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=OIGBRRpPcoSKUudNP1yKTBSw8t5ViV2P4e13+4YbxQOZebUh59d4Bd3O17M+2M3fW l2JopXAAMoLbCCQiUw4P9UbfDnWj5k10OvpFAQN+tgXf6S9iWHvN28TZU+UmaiKBc1 xgXuvOTO+RIiIJaBDMCm6IziKd1qUMrzt3QpPCJWCh+MSJE8cuVScdtJ5Lm7UoHAOX RhhHyLGVPcb9HJ27VZMf+DHqs1o75H2Bt/UGZpO6Yum/iNLpkdbC5v1WUdnQWtEgG5 mDgGAmammvroj1DpHULUYKyrVHStoHHyUnUXh0BZZS4F1sW/dMyjqCyxi9WRNhEjFm Q5Un0WmAt3PeQ== From: Josh Poimboeuf To: x86@kernel.org Cc: linux-kernel@vger.kernel.org, Peter Zijlstra , Ingo Molnar , Miroslav Benes , Brendan Jackman , Nathan Chancellor Subject: [PATCH 09/22] objtool: Improve error handling Date: Mon, 24 Mar 2025 14:55:59 -0700 Message-ID: <3094bb4463dad29b6bd1bea03848d1571ace771c.1742852846.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" Fix some error handling issues, improve error messages, properly distinguish betwee errors and warnings, and generally try to make all the error handling more consistent. Signed-off-by: Josh Poimboeuf --- tools/objtool/builtin-check.c | 37 ++- tools/objtool/check.c | 370 ++++++++++++------------ tools/objtool/elf.c | 22 +- tools/objtool/include/objtool/objtool.h | 2 +- tools/objtool/include/objtool/warn.h | 13 +- tools/objtool/objtool.c | 11 +- 6 files changed, 233 insertions(+), 222 deletions(-) diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c index 5f761f420b8c..c973a751fb7d 100644 --- a/tools/objtool/builtin-check.c +++ b/tools/objtool/builtin-check.c @@ -8,15 +8,12 @@ #include #include #include +#include #include #include #include #include - -#define ERROR(format, ...) \ - fprintf(stderr, \ - "error: objtool: " format "\n", \ - ##__VA_ARGS__) +#include =20 const char *objname; =20 @@ -139,22 +136,22 @@ int cmd_parse_options(int argc, const char **argv, co= nst char * const usage[]) static bool opts_valid(void) { if (opts.mnop && !opts.mcount) { - ERROR("--mnop requires --mcount"); + WARN("--mnop requires --mcount"); return false; } =20 if (opts.noinstr && !opts.link) { - ERROR("--noinstr requires --link"); + WARN("--noinstr requires --link"); return false; } =20 if (opts.ibt && !opts.link) { - ERROR("--ibt requires --link"); + WARN("--ibt requires --link"); return false; } =20 if (opts.unret && !opts.link) { - ERROR("--unret requires --link"); + WARN("--unret requires --link"); return false; } =20 @@ -171,7 +168,7 @@ static bool opts_valid(void) opts.static_call || opts.uaccess) { if (opts.dump_orc) { - ERROR("--dump can't be combined with other actions"); + WARN("--dump can't be combined with other actions"); return false; } =20 @@ -181,7 +178,7 @@ static bool opts_valid(void) if (opts.dump_orc) return true; =20 - ERROR("At least one action required"); + WARN("At least one action required"); return false; } =20 @@ -194,30 +191,30 @@ static int copy_file(const char *src, const char *dst) =20 src_fd =3D open(src, O_RDONLY); if (src_fd =3D=3D -1) { - ERROR("can't open '%s' for reading", src); + WARN("can't open %s for reading: %s", src, strerror(errno)); return 1; } =20 dst_fd =3D open(dst, O_WRONLY | O_CREAT | O_TRUNC, 0400); if (dst_fd =3D=3D -1) { - ERROR("can't open '%s' for writing", dst); + WARN("can't open %s for writing: %s", dst, strerror(errno)); return 1; } =20 if (fstat(src_fd, &stat) =3D=3D -1) { - perror("fstat"); + WARN_GLIBC("fstat"); return 1; } =20 if (fchmod(dst_fd, stat.st_mode) =3D=3D -1) { - perror("fchmod"); + WARN_GLIBC("fchmod"); return 1; } =20 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"); + WARN_GLIBC("sendfile"); return 1; } } @@ -233,14 +230,14 @@ static char **save_argv(int argc, const char **argv) =20 orig_argv =3D calloc(argc, sizeof(char *)); if (!orig_argv) { - perror("calloc"); + WARN_GLIBC("calloc"); return NULL; } =20 for (int i =3D 0; i < argc; i++) { orig_argv[i] =3D strdup(argv[i]); if (!orig_argv[i]) { - perror("strdup"); + WARN_GLIBC("strdup(%s)", orig_argv[i]); return NULL; } }; @@ -285,7 +282,7 @@ int objtool_run(int argc, const char **argv) goto err; =20 if (!opts.link && has_multiple_files(file->elf)) { - ERROR("Linked object requires --link"); + WARN("Linked object requires --link"); goto err; } =20 @@ -313,7 +310,7 @@ int objtool_run(int argc, const char **argv) */ backup =3D malloc(strlen(objname) + strlen(ORIG_SUFFIX) + 1); if (!backup) { - perror("malloc"); + WARN_GLIBC("malloc"); return 1; } =20 diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 3966fc81a77e..fbe2a5ef2c40 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -353,7 +353,7 @@ static struct cfi_state *cfi_alloc(void) { struct cfi_state *cfi =3D calloc(1, sizeof(struct cfi_state)); if (!cfi) { - WARN("calloc failed"); + WARN_GLIBC("calloc"); exit(1); } nr_cfi++; @@ -409,7 +409,7 @@ static void *cfi_hash_alloc(unsigned long size) PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); if (cfi_hash =3D=3D (void *)-1L) { - WARN("mmap fail cfi_hash"); + WARN_GLIBC("mmap fail cfi_hash"); cfi_hash =3D NULL; } else if (opts.stats) { printf("cfi_bits: %d\n", cfi_bits); @@ -465,7 +465,7 @@ static int decode_instructions(struct objtool_file *fil= e) if (!insns || idx =3D=3D INSN_CHUNK_MAX) { insns =3D calloc(sizeof(*insn), INSN_CHUNK_SIZE); if (!insns) { - WARN("malloc failed"); + WARN_GLIBC("calloc"); return -1; } idx =3D 0; @@ -567,14 +567,21 @@ static int add_pv_ops(struct objtool_file *file, cons= t char *symname) if (!reloc) break; =20 + idx =3D (reloc_offset(reloc) - sym->offset) / sizeof(unsigned long); + func =3D reloc->sym; if (func->type =3D=3D STT_SECTION) func =3D find_symbol_by_offset(reloc->sym->sec, reloc_addend(reloc)); + if (!func) { + WARN_FUNC("can't find func at %s[%d]", + reloc->sym->sec, reloc_addend(reloc), + symname, idx); + return -1; + } =20 - idx =3D (reloc_offset(reloc) - sym->offset) / sizeof(unsigned long); - - objtool_pv_add(file, idx, func); + if (objtool_pv_add(file, idx, func)) + return -1; =20 off =3D reloc_offset(reloc) + 1; if (off > end) @@ -598,7 +605,7 @@ static int init_pv_ops(struct objtool_file *file) }; const char *pv_ops; struct symbol *sym; - int idx, nr; + int idx, nr, ret; =20 if (!opts.noinstr) return 0; @@ -611,14 +618,19 @@ static int init_pv_ops(struct objtool_file *file) =20 nr =3D sym->len / sizeof(unsigned long); file->pv_ops =3D calloc(sizeof(struct pv_state), nr); - if (!file->pv_ops) + if (!file->pv_ops) { + WARN_GLIBC("calloc"); return -1; + } =20 for (idx =3D 0; idx < nr; idx++) INIT_LIST_HEAD(&file->pv_ops[idx].targets); =20 - for (idx =3D 0; (pv_ops =3D pv_ops_tables[idx]); idx++) - add_pv_ops(file, pv_ops); + for (idx =3D 0; (pv_ops =3D pv_ops_tables[idx]); idx++) { + ret =3D add_pv_ops(file, pv_ops); + if (ret) + return ret; + } =20 return 0; } @@ -666,13 +678,12 @@ static int create_static_call_sections(struct objtool= _file *file) /* find key symbol */ key_name =3D strdup(insn_call_dest(insn)->name); if (!key_name) { - perror("strdup"); + WARN_GLIBC("strdup"); return -1; } if (strncmp(key_name, STATIC_CALL_TRAMP_PREFIX_STR, STATIC_CALL_TRAMP_PREFIX_LEN)) { WARN("static_call: trampoline name malformed: %s", key_name); - free(key_name); return -1; } tmp =3D key_name + STATIC_CALL_TRAMP_PREFIX_LEN - STATIC_CALL_KEY_PREFIX= _LEN; @@ -682,7 +693,6 @@ static int create_static_call_sections(struct objtool_f= ile *file) if (!key_sym) { if (!opts.module) { WARN("static_call: can't find static_call_key symbol: %s", tmp); - free(key_name); return -1; } =20 @@ -697,7 +707,6 @@ static int create_static_call_sections(struct objtool_f= ile *file) */ key_sym =3D insn_call_dest(insn); } - free(key_name); =20 /* populate reloc for 'key' */ if (!elf_init_reloc_data_sym(file->elf, sec, @@ -981,7 +990,7 @@ static int create_direct_call_sections(struct objtool_f= ile *file) /* * Warnings shouldn't be reported for ignored functions. */ -static void add_ignores(struct objtool_file *file) +static int add_ignores(struct objtool_file *file) { struct section *rsec; struct symbol *func; @@ -989,7 +998,7 @@ static void add_ignores(struct objtool_file *file) =20 rsec =3D find_section_by_name(file->elf, ".rela.discard.func_stack_frame_= non_standard"); if (!rsec) - return; + return 0; =20 for_each_reloc(rsec, reloc) { switch (reloc->sym->type) { @@ -1006,11 +1015,13 @@ static void add_ignores(struct objtool_file *file) default: WARN("unexpected relocation symbol type in %s: %d", rsec->name, reloc->sym->type); - continue; + return -1; } =20 func->ignore =3D true; } + + return 0; } =20 /* @@ -1275,7 +1286,7 @@ static void remove_insn_ops(struct instruction *insn) insn->stack_ops =3D NULL; } =20 -static void annotate_call_site(struct objtool_file *file, +static int annotate_call_site(struct objtool_file *file, struct instruction *insn, bool sibling) { struct reloc *reloc =3D insn_reloc(file, insn); @@ -1291,16 +1302,16 @@ static void annotate_call_site(struct objtool_file = *file, * original instruction if/when it ever makes sense to do so.) */ if (!strcmp(insn->sec->name, ".altinstr_replacement")) - return; + return 0; =20 if (sym->static_call_tramp) { list_add_tail(&insn->call_node, &file->static_call_list); - return; + return 0; } =20 if (sym->retpoline_thunk) { list_add_tail(&insn->call_node, &file->retpoline_call_list); - return; + return 0; } =20 /* @@ -1312,10 +1323,12 @@ static void annotate_call_site(struct objtool_file = *file, if (reloc) set_reloc_type(file->elf, reloc, R_NONE); =20 - elf_write_insn(file->elf, insn->sec, - insn->offset, insn->len, - sibling ? arch_ret_insn(insn->len) - : arch_nop_insn(insn->len)); + if (elf_write_insn(file->elf, insn->sec, + insn->offset, insn->len, + sibling ? arch_ret_insn(insn->len) + : arch_nop_insn(insn->len))) { + return -1; + } =20 insn->type =3D sibling ? INSN_RETURN : INSN_NOP; =20 @@ -1329,7 +1342,7 @@ static void annotate_call_site(struct objtool_file *f= ile, insn->retpoline_safe =3D true; } =20 - return; + return 0; } =20 if (opts.mcount && sym->fentry) { @@ -1339,15 +1352,17 @@ static void annotate_call_site(struct objtool_file = *file, if (reloc) set_reloc_type(file->elf, reloc, R_NONE); =20 - elf_write_insn(file->elf, insn->sec, - insn->offset, insn->len, - arch_nop_insn(insn->len)); + if (elf_write_insn(file->elf, insn->sec, + insn->offset, insn->len, + arch_nop_insn(insn->len))) { + return -1; + } =20 insn->type =3D INSN_NOP; } =20 list_add_tail(&insn->call_node, &file->mcount_loc_list); - return; + return 0; } =20 if (insn->type =3D=3D INSN_CALL && !insn->sec->init) @@ -1355,14 +1370,16 @@ static void annotate_call_site(struct objtool_file = *file, =20 if (!sibling && dead_end_function(file, sym)) insn->dead_end =3D true; + + return 0; } =20 -static void add_call_dest(struct objtool_file *file, struct instruction *i= nsn, +static int add_call_dest(struct objtool_file *file, struct instruction *in= sn, struct symbol *dest, bool sibling) { insn->_call_dest =3D dest; if (!dest) - return; + return 0; =20 /* * Whatever stack impact regular CALLs have, should be undone @@ -1373,10 +1390,10 @@ static void add_call_dest(struct objtool_file *file= , struct instruction *insn, */ remove_insn_ops(insn); =20 - annotate_call_site(file, insn, sibling); + return annotate_call_site(file, insn, sibling); } =20 -static void add_retpoline_call(struct objtool_file *file, struct instructi= on *insn) +static int add_retpoline_call(struct objtool_file *file, struct instructio= n *insn) { /* * Retpoline calls/jumps are really dynamic calls/jumps in disguise, @@ -1393,7 +1410,7 @@ static void add_retpoline_call(struct objtool_file *f= ile, struct instruction *in insn->type =3D INSN_JUMP_DYNAMIC_CONDITIONAL; break; default: - return; + return 0; } =20 insn->retpoline_safe =3D true; @@ -1407,7 +1424,7 @@ static void add_retpoline_call(struct objtool_file *f= ile, struct instruction *in */ remove_insn_ops(insn); =20 - annotate_call_site(file, insn, false); + return annotate_call_site(file, insn, false); } =20 static void add_return_call(struct objtool_file *file, struct instruction = *insn, bool add) @@ -1476,6 +1493,7 @@ static int add_jump_destinations(struct objtool_file = *file) struct reloc *reloc; struct section *dest_sec; unsigned long dest_off; + int ret; =20 for_each_insn(file, insn) { if (insn->jump_dest) { @@ -1496,7 +1514,9 @@ static int add_jump_destinations(struct objtool_file = *file) dest_sec =3D reloc->sym->sec; dest_off =3D arch_dest_reloc_offset(reloc_addend(reloc)); } else if (reloc->sym->retpoline_thunk) { - add_retpoline_call(file, insn); + ret =3D add_retpoline_call(file, insn); + if (ret) + return ret; continue; } else if (reloc->sym->return_thunk) { add_return_call(file, insn, true); @@ -1506,7 +1526,9 @@ static int add_jump_destinations(struct objtool_file = *file) * External sibling call or internal sibling call with * STT_FUNC reloc. */ - add_call_dest(file, insn, reloc->sym, true); + ret =3D add_call_dest(file, insn, reloc->sym, true); + if (ret) + return ret; continue; } else if (reloc->sym->sec->idx) { dest_sec =3D reloc->sym->sec; @@ -1546,7 +1568,9 @@ static int add_jump_destinations(struct objtool_file = *file) */ if (jump_dest->sym && jump_dest->offset =3D=3D jump_dest->sym->offset) { if (jump_dest->sym->retpoline_thunk) { - add_retpoline_call(file, insn); + ret =3D add_retpoline_call(file, insn); + if (ret) + return ret; continue; } if (jump_dest->sym->return_thunk) { @@ -1588,7 +1612,9 @@ static int add_jump_destinations(struct objtool_file = *file) * Internal sibling call without reloc or with * STT_SECTION reloc. */ - add_call_dest(file, insn, insn_func(jump_dest), true); + ret =3D add_call_dest(file, insn, insn_func(jump_dest), true); + if (ret) + return ret; continue; } =20 @@ -1618,6 +1644,7 @@ static int add_call_destinations(struct objtool_file = *file) unsigned long dest_off; struct symbol *dest; struct reloc *reloc; + int ret; =20 for_each_insn(file, insn) { struct symbol *func =3D insn_func(insn); @@ -1629,7 +1656,9 @@ static int add_call_destinations(struct objtool_file = *file) dest_off =3D arch_jump_destination(insn); dest =3D find_call_destination(insn->sec, dest_off); =20 - add_call_dest(file, insn, dest, false); + ret =3D add_call_dest(file, insn, dest, false); + if (ret) + return ret; =20 if (func && func->ignore) continue; @@ -1653,13 +1682,20 @@ static int add_call_destinations(struct objtool_fil= e *file) return -1; } =20 - add_call_dest(file, insn, dest, false); + ret =3D add_call_dest(file, insn, dest, false); + if (ret) + return ret; =20 } else if (reloc->sym->retpoline_thunk) { - add_retpoline_call(file, insn); + ret =3D add_retpoline_call(file, insn); + if (ret) + return ret; =20 - } else - add_call_dest(file, insn, reloc->sym, false); + } else { + ret =3D add_call_dest(file, insn, reloc->sym, false); + if (ret) + return ret; + } } =20 return 0; @@ -1682,15 +1718,15 @@ static int handle_group_alt(struct objtool_file *fi= le, if (!orig_alt_group) { struct instruction *last_orig_insn =3D NULL; =20 - orig_alt_group =3D malloc(sizeof(*orig_alt_group)); + orig_alt_group =3D calloc(1, sizeof(*orig_alt_group)); if (!orig_alt_group) { - WARN("malloc failed"); + WARN_GLIBC("calloc"); return -1; } orig_alt_group->cfi =3D calloc(special_alt->orig_len, sizeof(struct cfi_state *)); if (!orig_alt_group->cfi) { - WARN("calloc failed"); + WARN_GLIBC("calloc"); return -1; } =20 @@ -1719,9 +1755,9 @@ static int handle_group_alt(struct objtool_file *file, } } =20 - new_alt_group =3D malloc(sizeof(*new_alt_group)); + new_alt_group =3D calloc(1, sizeof(*new_alt_group)); if (!new_alt_group) { - WARN("malloc failed"); + WARN_GLIBC("calloc"); return -1; } =20 @@ -1733,9 +1769,9 @@ static int handle_group_alt(struct objtool_file *file, * instruction affects the stack, the instruction after it (the * nop) will propagate the new state to the shared CFI array. */ - nop =3D malloc(sizeof(*nop)); + nop =3D calloc(1, sizeof(*nop)); if (!nop) { - WARN("malloc failed"); + WARN_GLIBC("calloc"); return -1; } memset(nop, 0, sizeof(*nop)); @@ -1835,9 +1871,13 @@ static int handle_jump_alt(struct objtool_file *file, =20 if (reloc) set_reloc_type(file->elf, reloc, R_NONE); - elf_write_insn(file->elf, orig_insn->sec, - orig_insn->offset, orig_insn->len, - arch_nop_insn(orig_insn->len)); + + if (elf_write_insn(file->elf, orig_insn->sec, + orig_insn->offset, orig_insn->len, + arch_nop_insn(orig_insn->len))) { + return -1; + } + orig_insn->type =3D INSN_NOP; } =20 @@ -1873,9 +1913,8 @@ static int add_special_section_alts(struct objtool_fi= le *file) struct alternative *alt; int ret; =20 - ret =3D special_get_alts(file->elf, &special_alts); - if (ret) - return ret; + if (special_get_alts(file->elf, &special_alts)) + return -1; =20 list_for_each_entry_safe(special_alt, tmp, &special_alts, list) { =20 @@ -1884,8 +1923,7 @@ static int add_special_section_alts(struct objtool_fi= le *file) if (!orig_insn) { WARN_FUNC("special: can't find orig instruction", special_alt->orig_sec, special_alt->orig_off); - ret =3D -1; - goto out; + return -1; } =20 new_insn =3D NULL; @@ -1896,8 +1934,7 @@ static int add_special_section_alts(struct objtool_fi= le *file) WARN_FUNC("special: can't find new instruction", special_alt->new_sec, special_alt->new_off); - ret =3D -1; - goto out; + return -1; } } =20 @@ -1910,19 +1947,19 @@ static int add_special_section_alts(struct objtool_= file *file) ret =3D handle_group_alt(file, special_alt, orig_insn, &new_insn); if (ret) - goto out; + return ret; + } else if (special_alt->jump_or_nop) { ret =3D handle_jump_alt(file, special_alt, orig_insn, &new_insn); if (ret) - goto out; + return ret; } =20 - alt =3D malloc(sizeof(*alt)); + alt =3D calloc(1, sizeof(*alt)); if (!alt) { - WARN("malloc failed"); - ret =3D -1; - goto out; + WARN_GLIBC("calloc"); + return -1; } =20 alt->insn =3D new_insn; @@ -1939,8 +1976,7 @@ static int add_special_section_alts(struct objtool_fi= le *file) printf("long:\t%ld\t%ld\n", file->jl_nop_long, file->jl_long); } =20 -out: - return ret; + return 0; } =20 __weak unsigned long arch_jump_table_sym_offset(struct reloc *reloc, struc= t reloc *table) @@ -1997,9 +2033,9 @@ static int add_jump_table(struct objtool_file *file, = struct instruction *insn) if (!insn_func(dest_insn) || insn_func(dest_insn)->pfunc !=3D pfunc) break; =20 - alt =3D malloc(sizeof(*alt)); + alt =3D calloc(1, sizeof(*alt)); if (!alt) { - WARN("malloc failed"); + WARN_GLIBC("calloc"); return -1; } =20 @@ -2047,7 +2083,7 @@ static void find_jump_table(struct objtool_file *file= , struct symbol *func, insn->jump_dest && (insn->jump_dest->offset <=3D insn->offset || insn->jump_dest->offset > orig_insn->offset)) - break; + break; =20 table_reloc =3D arch_find_switch_table(file, insn, &table_size); if (!table_reloc) @@ -2111,7 +2147,6 @@ static int add_func_jump_tables(struct objtool_file *= file, if (!insn_jump_table(insn)) continue; =20 - ret =3D add_jump_table(file, insn); if (ret) return ret; @@ -2229,6 +2264,7 @@ static int read_unwind_hints(struct objtool_file *fil= e) if (sym && sym->bind =3D=3D STB_GLOBAL) { if (opts.ibt && insn->type !=3D INSN_ENDBR && !insn->noendbr) { WARN_INSN(insn, "UNWIND_HINT_IRET_REGS without ENDBR"); + return -1; } } } @@ -2398,7 +2434,7 @@ static int __annotate_late(struct objtool_file *file,= int type, struct instructi =20 default: WARN_INSN(insn, "Unknown annotation type: %d", type); - break; + return -1; } =20 return 0; @@ -2511,7 +2547,10 @@ static int decode_sections(struct objtool_file *file) if (ret) return ret; =20 - add_ignores(file); + ret =3D add_ignores(file); + if (ret) + return ret; + add_uaccess_safe(file); =20 ret =3D read_annotate(file, __annotate_early); @@ -2731,7 +2770,7 @@ static int update_cfi_state(struct instruction *insn, if (cfa->base =3D=3D CFI_UNDEFINED) { if (insn_func(insn)) { WARN_INSN(insn, "undefined stack state"); - return -1; + return 1; } return 0; } @@ -3174,9 +3213,8 @@ static int propagate_alt_cfi(struct objtool_file *fil= e, struct instruction *insn if (cficmp(alt_cfi[group_off], insn->cfi)) { struct alt_group *orig_group =3D insn->alt_group->orig_group ?: insn->a= lt_group; struct instruction *orig =3D orig_group->first_insn; - char *where =3D offstr(insn->sec, insn->offset); - WARN_INSN(orig, "stack layout conflict in alternatives: %s", where); - free(where); + WARN_INSN(orig, "stack layout conflict in alternatives: %s", + offstr(insn->sec, insn->offset)); return -1; } } @@ -3189,11 +3227,13 @@ static int handle_insn_ops(struct instruction *insn, struct insn_state *state) { struct stack_op *op; + int ret; =20 for (op =3D insn->stack_ops; op; op =3D op->next) { =20 - if (update_cfi_state(insn, next_insn, &state->cfi, op)) - return 1; + ret =3D update_cfi_state(insn, next_insn, &state->cfi, op); + if (ret) + return ret; =20 if (!opts.uaccess || !insn->alt_group) continue; @@ -3237,36 +3277,41 @@ static bool insn_cfi_match(struct instruction *insn= , struct cfi_state *cfi2) WARN_INSN(insn, "stack state mismatch: cfa1=3D%d%+d cfa2=3D%d%+d", cfi1->cfa.base, cfi1->cfa.offset, cfi2->cfa.base, cfi2->cfa.offset); + return false; =20 - } else if (memcmp(&cfi1->regs, &cfi2->regs, sizeof(cfi1->regs))) { + } + + if (memcmp(&cfi1->regs, &cfi2->regs, sizeof(cfi1->regs))) { for (i =3D 0; i < CFI_NUM_REGS; i++) { - if (!memcmp(&cfi1->regs[i], &cfi2->regs[i], - sizeof(struct cfi_reg))) + + if (!memcmp(&cfi1->regs[i], &cfi2->regs[i], sizeof(struct cfi_reg))) continue; =20 WARN_INSN(insn, "stack state mismatch: reg1[%d]=3D%d%+d reg2[%d]=3D%d%+= d", i, cfi1->regs[i].base, cfi1->regs[i].offset, i, cfi2->regs[i].base, cfi2->regs[i].offset); - break; } + return false; + } =20 - } else if (cfi1->type !=3D cfi2->type) { + if (cfi1->type !=3D cfi2->type) { =20 WARN_INSN(insn, "stack state mismatch: type1=3D%d type2=3D%d", cfi1->type, cfi2->type); + return false; + } =20 - } else if (cfi1->drap !=3D cfi2->drap || + if (cfi1->drap !=3D cfi2->drap || (cfi1->drap && cfi1->drap_reg !=3D cfi2->drap_reg) || (cfi1->drap && cfi1->drap_offset !=3D cfi2->drap_offset)) { =20 WARN_INSN(insn, "stack state mismatch: drap1=3D%d(%d,%d) drap2=3D%d(%d,%= d)", cfi1->drap, cfi1->drap_reg, cfi1->drap_offset, cfi2->drap, cfi2->drap_reg, cfi2->drap_offset); + return false; + } =20 - } else - return true; - - return false; + return true; } =20 static inline bool func_uaccess_safe(struct symbol *func) @@ -3498,6 +3543,8 @@ static int validate_branch(struct objtool_file *file,= struct symbol *func, =20 WARN("%s() falls through to next function %s()", func->name, insn_func(insn)->name); + func->warnings++; + return 1; } =20 @@ -3605,9 +3652,6 @@ static int validate_branch(struct objtool_file *file,= struct symbol *func, return 1; } =20 - if (insn->dead_end) - return 0; - break; =20 case INSN_JUMP_CONDITIONAL: @@ -3714,7 +3758,9 @@ static int validate_branch(struct objtool_file *file,= struct symbol *func, if (file->ignore_unreachables) return 0; =20 - WARN("%s: unexpected end of section", sec->name); + WARN("%s%sunexpected end of section %s", + func ? func->name : "", func ? ": " : "", + sec->name); return 1; } =20 @@ -3804,7 +3850,7 @@ static int validate_unret(struct objtool_file *file, = struct instruction *insn) if (!is_sibling_call(insn)) { if (!insn->jump_dest) { WARN_INSN(insn, "unresolved jump target after linking?!?"); - return -1; + return 1; } ret =3D validate_unret(file, insn->jump_dest); if (ret) { @@ -3826,7 +3872,7 @@ static int validate_unret(struct objtool_file *file, = struct instruction *insn) if (!dest) { WARN("Unresolved function after linking!?: %s", insn_call_dest(insn)->name); - return -1; + return 1; } =20 ret =3D validate_unret(file, dest); @@ -3855,7 +3901,7 @@ static int validate_unret(struct objtool_file *file, = struct instruction *insn) =20 if (!next) { WARN_INSN(insn, "teh end!"); - return -1; + return 1; } insn =3D next; } @@ -3870,18 +3916,13 @@ static int validate_unret(struct objtool_file *file= , struct instruction *insn) static int validate_unrets(struct objtool_file *file) { struct instruction *insn; - int ret, warnings =3D 0; + int warnings =3D 0; =20 for_each_insn(file, insn) { if (!insn->unret) continue; =20 - ret =3D validate_unret(file, insn); - if (ret < 0) { - WARN_INSN(insn, "Failed UNRET validation"); - return ret; - } - warnings +=3D ret; + warnings +=3D validate_unret(file, insn); } =20 return warnings; @@ -3907,13 +3948,13 @@ static int validate_retpoline(struct objtool_file *= file) if (insn->type =3D=3D INSN_RETURN) { if (opts.rethunk) { WARN_INSN(insn, "'naked' return found in MITIGATION_RETHUNK build"); - } else - continue; - } else { - WARN_INSN(insn, "indirect %s found in MITIGATION_RETPOLINE build", - insn->type =3D=3D INSN_JUMP_DYNAMIC ? "jump" : "call"); + warnings++; + } + continue; } =20 + WARN_INSN(insn, "indirect %s found in MITIGATION_RETPOLINE build", + insn->type =3D=3D INSN_JUMP_DYNAMIC ? "jump" : "call"); warnings++; } =20 @@ -4480,7 +4521,7 @@ static int validate_reachable_instructions(struct obj= tool_file *file) } =20 /* 'funcs' is a space-separated list of function names */ -static int disas_funcs(const char *funcs) +static void disas_funcs(const char *funcs) { const char *objdump_str, *cross_compile; int size, ret; @@ -4513,7 +4554,7 @@ static int disas_funcs(const char *funcs) size =3D snprintf(NULL, 0, objdump_str, cross_compile, objname, funcs) + = 1; if (size <=3D 0) { WARN("objdump string size calculation failed"); - return -1; + return; } =20 cmd =3D malloc(size); @@ -4523,13 +4564,11 @@ static int disas_funcs(const char *funcs) ret =3D system(cmd); if (ret) { WARN("disassembly failed: %d", ret); - return -1; + return; } - - return 0; } =20 -static int disas_warned_funcs(struct objtool_file *file) +static void disas_warned_funcs(struct objtool_file *file) { struct symbol *sym; char *funcs =3D NULL, *tmp; @@ -4538,9 +4577,17 @@ static int disas_warned_funcs(struct objtool_file *f= ile) if (sym->warnings) { if (!funcs) { funcs =3D malloc(strlen(sym->name) + 1); + if (!funcs) { + WARN_GLIBC("malloc"); + return; + } strcpy(funcs, sym->name); } else { tmp =3D malloc(strlen(funcs) + strlen(sym->name) + 2); + if (!tmp) { + WARN_GLIBC("malloc"); + return; + } sprintf(tmp, "%s %s", funcs, sym->name); free(funcs); funcs =3D tmp; @@ -4550,8 +4597,6 @@ static int disas_warned_funcs(struct objtool_file *fi= le) =20 if (funcs) disas_funcs(funcs); - - return 0; } =20 struct insn_chunk { @@ -4584,7 +4629,7 @@ static void free_insns(struct objtool_file *file) =20 int check(struct objtool_file *file) { - int ret, warnings =3D 0; + int ret =3D 0, warnings =3D 0; =20 arch_initial_func_cfi_state(&initial_func_cfi); init_cfi_state(&init_cfi); @@ -4602,44 +4647,27 @@ int check(struct objtool_file *file) cfi_hash_add(&func_cfi); =20 ret =3D decode_sections(file); - if (ret < 0) + if (ret) goto out; =20 - warnings +=3D ret; - if (!nr_insns) goto out; =20 - if (opts.retpoline) { - ret =3D validate_retpoline(file); - if (ret < 0) - goto out; - warnings +=3D ret; - } + if (opts.retpoline) + warnings +=3D validate_retpoline(file); =20 if (opts.stackval || opts.orc || opts.uaccess) { - ret =3D validate_functions(file); - if (ret < 0) - goto out; - warnings +=3D ret; + int w =3D 0; =20 - ret =3D validate_unwind_hints(file, NULL); - if (ret < 0) - goto out; - warnings +=3D ret; + w +=3D validate_functions(file); + w +=3D validate_unwind_hints(file, NULL); + if (!w) + w +=3D validate_reachable_instructions(file); =20 - if (!warnings) { - ret =3D validate_reachable_instructions(file); - if (ret < 0) - goto out; - warnings +=3D ret; - } + warnings +=3D w; =20 } else if (opts.noinstr) { - ret =3D validate_noinstr_sections(file); - if (ret < 0) - goto out; - warnings +=3D ret; + warnings +=3D validate_noinstr_sections(file); } =20 if (opts.unret) { @@ -4647,87 +4675,67 @@ int check(struct objtool_file *file) * Must be after validate_branch() and friends, it plays * further games with insn->visited. */ - ret =3D validate_unrets(file); - if (ret < 0) - goto out; - warnings +=3D ret; + warnings +=3D validate_unrets(file); } =20 - if (opts.ibt) { - ret =3D validate_ibt(file); - if (ret < 0) - goto out; - warnings +=3D ret; - } + if (opts.ibt) + warnings +=3D validate_ibt(file); =20 - if (opts.sls) { - ret =3D validate_sls(file); - if (ret < 0) - goto out; - warnings +=3D ret; - } + if (opts.sls) + warnings +=3D validate_sls(file); =20 if (opts.static_call) { ret =3D create_static_call_sections(file); - if (ret < 0) + if (ret) goto out; - warnings +=3D ret; } =20 if (opts.retpoline) { ret =3D create_retpoline_sites_sections(file); - if (ret < 0) + if (ret) goto out; - warnings +=3D ret; } =20 if (opts.cfi) { ret =3D create_cfi_sections(file); - if (ret < 0) + if (ret) goto out; - warnings +=3D ret; } =20 if (opts.rethunk) { ret =3D create_return_sites_sections(file); - if (ret < 0) + if (ret) goto out; - warnings +=3D ret; =20 if (opts.hack_skylake) { ret =3D create_direct_call_sections(file); - if (ret < 0) + if (ret) goto out; - warnings +=3D ret; } } =20 if (opts.mcount) { ret =3D create_mcount_loc_sections(file); - if (ret < 0) + if (ret) goto out; - warnings +=3D ret; } =20 if (opts.prefix) { ret =3D add_prefix_symbols(file); - if (ret < 0) + if (ret) goto out; - warnings +=3D ret; } =20 if (opts.ibt) { ret =3D create_ibt_endbr_seal_sections(file); - if (ret < 0) + if (ret) goto out; - warnings +=3D ret; } =20 if (opts.orc && nr_insns) { ret =3D orc_create(file); - if (ret < 0) + if (ret) goto out; - warnings +=3D ret; } =20 free_insns(file); diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 0f38167bd840..b352a78b596c 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -331,7 +331,7 @@ static int read_sections(struct elf *elf) =20 elf->section_data =3D calloc(sections_nr, sizeof(*sec)); if (!elf->section_data) { - perror("calloc"); + WARN_GLIBC("calloc"); return -1; } for (i =3D 0; i < sections_nr; i++) { @@ -467,7 +467,7 @@ static int read_symbols(struct elf *elf) =20 elf->symbol_data =3D calloc(symbols_nr, sizeof(*sym)); if (!elf->symbol_data) { - perror("calloc"); + WARN_GLIBC("calloc"); return -1; } for (i =3D 0; i < symbols_nr; i++) { @@ -799,7 +799,7 @@ elf_create_section_symbol(struct elf *elf, struct secti= on *sec) struct symbol *sym =3D calloc(1, sizeof(*sym)); =20 if (!sym) { - perror("malloc"); + WARN_GLIBC("malloc"); return NULL; } =20 @@ -829,7 +829,7 @@ elf_create_prefix_symbol(struct elf *elf, struct symbol= *orig, long size) char *name =3D malloc(namelen); =20 if (!sym || !name) { - perror("malloc"); + WARN_GLIBC("malloc"); return NULL; } =20 @@ -963,7 +963,7 @@ static int read_relocs(struct elf *elf) nr_reloc =3D 0; rsec->relocs =3D calloc(sec_num_entries(rsec), sizeof(*reloc)); if (!rsec->relocs) { - perror("calloc"); + WARN_GLIBC("calloc"); return -1; } for (i =3D 0; i < sec_num_entries(rsec); i++) { @@ -1005,7 +1005,7 @@ struct elf *elf_open_read(const char *name, int flags) =20 elf =3D malloc(sizeof(*elf)); if (!elf) { - perror("malloc"); + WARN_GLIBC("malloc"); return NULL; } memset(elf, 0, sizeof(*elf)); @@ -1099,7 +1099,7 @@ struct section *elf_create_section(struct elf *elf, c= onst char *name, =20 sec =3D malloc(sizeof(*sec)); if (!sec) { - perror("malloc"); + WARN_GLIBC("malloc"); return NULL; } memset(sec, 0, sizeof(*sec)); @@ -1114,7 +1114,7 @@ struct section *elf_create_section(struct elf *elf, c= onst char *name, =20 sec->name =3D strdup(name); if (!sec->name) { - perror("strdup"); + WARN_GLIBC("strdup"); return NULL; } =20 @@ -1132,7 +1132,7 @@ struct section *elf_create_section(struct elf *elf, c= onst char *name, if (size) { sec->data->d_buf =3D malloc(size); if (!sec->data->d_buf) { - perror("malloc"); + WARN_GLIBC("malloc"); return NULL; } memset(sec->data->d_buf, 0, size); @@ -1179,7 +1179,7 @@ static struct section *elf_create_rela_section(struct= elf *elf, =20 rsec_name =3D malloc(strlen(sec->name) + strlen(".rela") + 1); if (!rsec_name) { - perror("malloc"); + WARN_GLIBC("malloc"); return NULL; } strcpy(rsec_name, ".rela"); @@ -1199,7 +1199,7 @@ static struct section *elf_create_rela_section(struct= elf *elf, =20 rsec->relocs =3D calloc(sec_num_entries(rsec), sizeof(struct reloc)); if (!rsec->relocs) { - perror("calloc"); + WARN_GLIBC("calloc"); return NULL; } =20 diff --git a/tools/objtool/include/objtool/objtool.h b/tools/objtool/includ= e/objtool/objtool.h index 94a33ee7b363..c0dc86a78ff6 100644 --- a/tools/objtool/include/objtool/objtool.h +++ b/tools/objtool/include/objtool/objtool.h @@ -41,7 +41,7 @@ struct objtool_file { =20 struct objtool_file *objtool_open_read(const char *_objname); =20 -void objtool_pv_add(struct objtool_file *file, int idx, struct symbol *fun= c); +int objtool_pv_add(struct objtool_file *file, int idx, struct symbol *func= ); =20 int check(struct objtool_file *file); int orc_dump(const char *objname); diff --git a/tools/objtool/include/objtool/warn.h b/tools/objtool/include/o= bjtool/warn.h index e72b9d630551..b29ac144e4f5 100644 --- a/tools/objtool/include/objtool/warn.h +++ b/tools/objtool/include/objtool/warn.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include =20 @@ -43,8 +44,9 @@ static inline char *offstr(struct section *sec, unsigned = long offset) =20 #define WARN(format, ...) \ fprintf(stderr, \ - "%s: %s: objtool: " format "\n", \ - objname, \ + "%s%s%s: objtool: " format "\n", \ + objname ?: "", \ + objname ? ": " : "", \ opts.werror ? "error" : "warning", \ ##__VA_ARGS__) =20 @@ -83,7 +85,10 @@ static inline char *offstr(struct section *sec, unsigned= long offset) } \ }) =20 -#define WARN_ELF(format, ...) \ - WARN(format ": %s", ##__VA_ARGS__, elf_errmsg(-1)) +#define WARN_ELF(format, ...) \ + WARN("%s: " format " failed: %s", __func__, ##__VA_ARGS__, elf_errmsg(-1)) + +#define WARN_GLIBC(format, ...) \ + WARN("%s: " format " failed: %s", __func__, ##__VA_ARGS__, strerror(errno= )) =20 #endif /* _WARN_H */ diff --git a/tools/objtool/objtool.c b/tools/objtool/objtool.c index 1c73fb62fd57..e4b49c534e4d 100644 --- a/tools/objtool/objtool.c +++ b/tools/objtool/objtool.c @@ -44,14 +44,14 @@ struct objtool_file *objtool_open_read(const char *file= name) return &file; } =20 -void objtool_pv_add(struct objtool_file *f, int idx, struct symbol *func) +int objtool_pv_add(struct objtool_file *f, int idx, struct symbol *func) { if (!opts.noinstr) - return; + return 0; =20 if (!f->pv_ops) { WARN("paravirt confusion"); - return; + return -1; } =20 /* @@ -60,14 +60,15 @@ void objtool_pv_add(struct objtool_file *f, int idx, st= ruct symbol *func) */ if (!strcmp(func->name, "_paravirt_nop") || !strcmp(func->name, "_paravirt_ident_64")) - return; + return 0; =20 /* already added this function */ if (!list_empty(&func->pv_target)) - return; + return 0; =20 list_add(&func->pv_target, &f->pv_ops[idx].targets); f->pv_ops[idx].clean =3D false; + return 0; } =20 int main(int argc, const char **argv) --=20 2.48.1