summaryrefslogtreecommitdiff
path: root/tools/objtool/check.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/objtool/check.c')
-rw-r--r--tools/objtool/check.c95
1 files changed, 40 insertions, 55 deletions
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index ce973d9d8e6d..ca3435acc326 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -1284,15 +1284,6 @@ static void annotate_call_site(struct objtool_file *file,
if (!sym)
sym = reloc->sym;
- /*
- * Alternative replacement code is just template code which is
- * sometimes copied to the original instruction. For now, don't
- * annotate it. (In the future we might consider annotating the
- * original instruction if/when it ever makes sense to do so.)
- */
- if (!strcmp(insn->sec->name, ".altinstr_replacement"))
- return;
-
if (sym->static_call_tramp) {
list_add_tail(&insn->call_node, &file->static_call_list);
return;
@@ -1350,7 +1341,8 @@ static void annotate_call_site(struct objtool_file *file,
return;
}
- if (insn->type == INSN_CALL && !insn->sec->init)
+ if (insn->type == INSN_CALL && !insn->sec->init &&
+ !insn->_call_dest->embedded_insn)
list_add_tail(&insn->call_node, &file->call_list);
if (!sibling && dead_end_function(file, sym))
@@ -1944,6 +1936,11 @@ out:
return ret;
}
+__weak unsigned long arch_jump_table_sym_offset(struct reloc *reloc, struct reloc *table)
+{
+ return reloc->sym->offset + reloc_addend(reloc);
+}
+
static int add_jump_table(struct objtool_file *file, struct instruction *insn,
struct reloc *next_table)
{
@@ -1954,6 +1951,7 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn,
unsigned int prev_offset = 0;
struct reloc *reloc = table;
struct alternative *alt;
+ unsigned long sym_offset;
/*
* Each @reloc is a switch table relocation which points to the target
@@ -1968,12 +1966,13 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn,
break;
/* Make sure the table entries are consecutive: */
- if (prev_offset && reloc_offset(reloc) != prev_offset + 8)
+ if (prev_offset && reloc_offset(reloc) != prev_offset + arch_reloc_size(reloc))
break;
+ sym_offset = arch_jump_table_sym_offset(reloc, table);
+
/* Detect function pointers from contiguous objects: */
- if (reloc->sym->sec == pfunc->sec &&
- reloc_addend(reloc) == pfunc->offset)
+ if (reloc->sym->sec == pfunc->sec && sym_offset == pfunc->offset)
break;
/*
@@ -1981,10 +1980,10 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn,
* which point to the end of the function. Ignore them.
*/
if (reloc->sym->sec == pfunc->sec &&
- reloc_addend(reloc) == pfunc->offset + pfunc->len)
+ sym_offset == pfunc->offset + pfunc->len)
goto next;
- dest_insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc));
+ dest_insn = find_insn(file, reloc->sym->sec, sym_offset);
if (!dest_insn)
break;
@@ -2023,6 +2022,7 @@ static void find_jump_table(struct objtool_file *file, struct symbol *func,
struct reloc *table_reloc;
struct instruction *dest_insn, *orig_insn = insn;
unsigned long table_size;
+ unsigned long sym_offset;
/*
* Backward search using the @first_jump_src links, these help avoid
@@ -2046,7 +2046,10 @@ static void find_jump_table(struct objtool_file *file, struct symbol *func,
table_reloc = arch_find_switch_table(file, insn, &table_size);
if (!table_reloc)
continue;
- dest_insn = find_insn(file, table_reloc->sym->sec, reloc_addend(table_reloc));
+
+ sym_offset = table_reloc->sym->offset + reloc_addend(table_reloc);
+
+ dest_insn = find_insn(file, table_reloc->sym->sec, sym_offset);
if (!dest_insn || !insn_func(dest_insn) || insn_func(dest_insn)->pfunc != func)
continue;
@@ -4449,35 +4452,6 @@ static int validate_sls(struct objtool_file *file)
return warnings;
}
-static bool ignore_noreturn_call(struct instruction *insn)
-{
- struct symbol *call_dest = insn_call_dest(insn);
-
- /*
- * FIXME: hack, we need a real noreturn solution
- *
- * Problem is, exc_double_fault() may or may not return, depending on
- * whether CONFIG_X86_ESPFIX64 is set. But objtool has no visibility
- * to the kernel config.
- *
- * Other potential ways to fix it:
- *
- * - have compiler communicate __noreturn functions somehow
- * - remove CONFIG_X86_ESPFIX64
- * - read the .config file
- * - add a cmdline option
- * - create a generic objtool annotation format (vs a bunch of custom
- * formats) and annotate it
- */
- if (!strcmp(call_dest->name, "exc_double_fault")) {
- /* prevent further unreachable warnings for the caller */
- insn->sym->warned = 1;
- return true;
- }
-
- return false;
-}
-
static int validate_reachable_instructions(struct objtool_file *file)
{
struct instruction *insn, *prev_insn;
@@ -4494,8 +4468,8 @@ static int validate_reachable_instructions(struct objtool_file *file)
prev_insn = prev_insn_same_sec(file, insn);
if (prev_insn && prev_insn->dead_end) {
call_dest = insn_call_dest(prev_insn);
- if (call_dest && !ignore_noreturn_call(prev_insn)) {
- WARN_INSN(insn, "%s() is missing a __noreturn annotation",
+ if (call_dest) {
+ WARN_INSN(insn, "%s() missing __noreturn in .c/.h or NORETURN() in noreturns.h",
call_dest->name);
warnings++;
continue;
@@ -4565,7 +4539,7 @@ static int disas_warned_funcs(struct objtool_file *file)
char *funcs = NULL, *tmp;
for_each_sym(file, sym) {
- if (sym->warned) {
+ if (sym->warnings) {
if (!funcs) {
funcs = malloc(strlen(sym->name) + 1);
strcpy(funcs, sym->name);
@@ -4623,8 +4597,10 @@ int check(struct objtool_file *file)
init_cfi_state(&force_undefined_cfi);
force_undefined_cfi.force_undefined = true;
- if (!cfi_hash_alloc(1UL << (file->elf->symbol_bits - 3)))
+ if (!cfi_hash_alloc(1UL << (file->elf->symbol_bits - 3))) {
+ ret = -1;
goto out;
+ }
cfi_hash_add(&init_cfi);
cfi_hash_add(&func_cfi);
@@ -4641,7 +4617,7 @@ int check(struct objtool_file *file)
if (opts.retpoline) {
ret = validate_retpoline(file);
if (ret < 0)
- return ret;
+ goto out;
warnings += ret;
}
@@ -4677,7 +4653,7 @@ int check(struct objtool_file *file)
*/
ret = validate_unrets(file);
if (ret < 0)
- return ret;
+ goto out;
warnings += ret;
}
@@ -4740,7 +4716,7 @@ int check(struct objtool_file *file)
if (opts.prefix) {
ret = add_prefix_symbols(file);
if (ret < 0)
- return ret;
+ goto out;
warnings += ret;
}
@@ -4772,9 +4748,18 @@ int check(struct objtool_file *file)
out:
/*
- * For now, don't fail the kernel build on fatal warnings. These
- * errors are still fairly common due to the growing matrix of
- * supported toolchains and their recent pace of change.
+ * CONFIG_OBJTOOL_WERROR upgrades all warnings (and errors) to actual
+ * errors.
+ *
+ * Note that even "fatal" type errors don't actually return an error
+ * without CONFIG_OBJTOOL_WERROR. That probably needs improved at some
+ * point.
*/
+ if (opts.werror && (ret || warnings)) {
+ if (warnings)
+ WARN("%d warning(s) upgraded to errors", warnings);
+ return 1;
+ }
+
return 0;
}