objtool: warning improvements
Josh Poimboeuf
maintainercover objtool: warning improvements
Add some user-friendliness to the warnings:
- Add OBJTOOL_ARGS="--verbose" option for making it easier to debug objtool warnings over email
- Remove per-file rate limiting (doesn't make sense for vmlinux.o)
- Add "missing __noreturn" warning
Josh Poimboeuf (5):
objtool: Add '--verbose' option for disassembling affected functions
objtool: Combine '--backtrace' with '--verbose'
objtool: Remove superfluous dead_end_function() check
objtool: Add per-function rate limiting for unreachable warnings
objtool: Add "missing __noreturn" warning
tools/objtool/Documentation/objtool.txt | 12 ++++++ tools/objtool/builtin-check.c | 2 +- tools/objtool/check.c | 45 ++++++++++++--------- tools/objtool/include/objtool/builtin.h | 2 +- tools/objtool/include/objtool/elf.h | 1 + tools/objtool/include/objtool/warn.h | 52 ++++++++++++++++++++++--- 6 files changed, 88 insertions(+), 26 deletions(-)
Signature · 1 line
2.39.2
Josh Poimboeuf
maintainerPATCH 1/5 objtool: Add '--verbose' option for disassembling affected functions
When a warning is associated with a function, add an option to disassemble that function.
This makes it easier for reporters to submit the information needed to diagnose objtool warnings.
--- tools/objtool/Documentation/objtool.txt | 5 ++++ tools/objtool/builtin-check.c | 1 + tools/objtool/include/objtool/builtin.h | 1 + tools/objtool/include/objtool/warn.h | 38 +++++++++++++++++++++++++ 4 files changed, 45 insertions(+)
tools/objtool/Documentation/objtool.txt +5 -0
@@ -244,6 +244,11 @@ To achieve the validation, objtool enforces the following rules: Objtool warnings ---------------- +NOTE: When requesting help with an objtool warning, please re-run the +kernel build with `OBJTOOL_ARGS="--verbose" make <whatever>` and send +the full warning output (including any function disassembly below the +warning) to the objtool maintainers. + For asm files, if you're getting an error which doesn't make sense, first make sure that the affected code follows the above rules.
tools/objtool/builtin-check.c +1 -0
@@ -93,6 +93,7 @@ static const struct option check_options[] = {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 ('v' ,"verbose" , &opts.verbose,"verbose warnings" ), OPT_END(), };
tools/objtool/include/objtool/builtin.h +1 -0
@@ -37,6 +37,7 @@ struct opts {bool no_unreachable;bool sec_address;bool stats; +bool verbose; };extern struct opts opts;
tools/objtool/include/objtool/warn.h +38 -0
@@ -11,6 +11,7 @@#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> +#include <unistd.h> #include <objtool/builtin.h> #include <objtool/elf.h>
@@ -41,6 +42,41 @@ static inline char *offstr(struct section *sec, unsigned long offset)return str; } +static inline void objdump_func (struct section *sec,unsigned long offset) +{ +struct symbol *sym =find_func_containing (sec, offset); +const char *script_relative ="scripts/objdump-func" ; +bool is_text = (sec->sh.sh_flags &SHF_EXECINSTR ); +char *cmd, *srctree, *script; + +if (is_text) + sym =find_func_containing (sec, offset); +if (!sym) + sym =find_symbol_containing (sec, offset); +if (!sym) +return ; + + srctree =getenv ("abs_srctree" ); +if (!srctree) +return ; + + script =malloc (strlen (srctree) +strlen (script_relative) +2 ); +if (!script) +return ; + +sprintf (script,"%s/%s" , srctree, script_relative); + +if (access (script,X_OK )) +return ; + + cmd =malloc (strlen (script) +strlen (objname) +strlen (sym->name) +10 ); +if (!cmd) +return ; + +sprintf (cmd,"%s %s %s 1>&2" , script, objname, sym->name); +system (cmd); +} +#define WARN (format, ...) \ fprintf(stderr, \ "%s: warning: objtool: " format "\n", \
@@ -51,6 +87,8 @@ static inline char *offstr(struct section *sec, unsigned long offset)char *_str =offstr (sec, offset); \ WARN("%s: " format, _str, ##__VA_ARGS__); \free (_str); \ +if (opts.verbose) \ +objdump_func (sec, offset); \ })#define BT_FUNC (format, insn, ...) \
Signature · 1 line
2.39.2
Re: [PATCH 1/5] objtool: Add '--verbose' option for disassembling affected functions
tools/objtool/include/objtool/warn.h static inline char *offstr(struct section *sec, unsigned long offset) · line 47
Quoted 3 lines
tools/objtool/include/objtool/warn.h +3
-0+static inline void objdump_func (struct section *sec,unsigned long offset) +{ +struct symbol *sym =find_func_containing (sec, offset);
Unnecessary assignment?
tools/objtool/include/objtool/warn.h static inline char *offstr(struct section *sec, unsigned long offset) · line 57
Quoted 10 lines
tools/objtool/include/objtool/warn.h +10
-0+const char *script_relative ="scripts/objdump-func" ; +bool is_text = (sec->sh.sh_flags &SHF_EXECINSTR ); +char *cmd, *srctree, *script; + +if (is_text) + sym =find_func_containing (sec, offset); +if (!sym) + sym =find_symbol_containing (sec, offset); +if (!sym) +return ;
Miroslav
Josh Poimboeuf
maintainerPATCH 2/5 objtool: Combine '--backtrace' with '--verbose'
In reply to Josh PoimboeufGet rid of the '--backtrace' option, instead including that functionality in '--verbose'. This makes it easy to gather all the information needed for diagnosing objtool warnings.
--- tools/objtool/Documentation/objtool.txt | 4 ++-- tools/objtool/builtin-check.c | 1 - tools/objtool/check.c | 22 ++++++++-------------- tools/objtool/include/objtool/builtin.h | 1 - tools/objtool/include/objtool/warn.h | 14 ++++++++------ 5 files changed, 18 insertions(+), 24 deletions(-)
tools/objtool/Documentation/objtool.txt +2 -2
@@ -246,8 +246,8 @@ Objtool warnings NOTE: When requesting help with an objtool warning, please re-run the kernel build with `OBJTOOL_ARGS="--verbose" make <whatever>` and send -the full warning output (including any function disassembly below the -warning) to the objtool maintainers. +the full warning output (including any function disassembly or objtool +backtrace below the warning) to the objtool maintainers. For asm files, if you're getting an error which doesn't make sense, first make sure that the affected code follows the above rules.
tools/objtool/builtin-check.c +0 -1
@@ -84,7 +84,6 @@ static const struct option check_options[] = {OPT_CALLBACK_OPTARG (0 ,"dump" ,NULL ,NULL ,"orc" ,"dump metadata" , parse_dump),OPT_GROUP ("Options:" ), -OPT_BOOLEAN (0 ,"backtrace" , &opts.backtrace,"unwind on error" ),OPT_BOOLEAN (0 ,"backup" , &opts.backup,"create .orig files before modification" ),OPT_BOOLEAN (0 ,"dry-run" , &opts.dryrun,"don't write modifications" ), OPT_BOOLEAN(0, "link", &opts.link, "object is a linked object"),
tools/objtool/check.c +8 -14
@@ -3708,8 +3708,7 @@ static int validate_branch(struct objtool_file *file, struct symbol *func, ret =validate_branch (file, func, alt->insn, state);if (ret) { -if (opts.backtrace) -BT_FUNC ("(alt)" , insn); +BT_FUNC ("(alt)" , insn);return ret; } }
@@ -3755,8 +3754,7 @@ static int validate_branch(struct objtool_file *file, struct symbol *func, ret =validate_branch (file, func, insn->jump_dest, state);if (ret) { -if (opts.backtrace) -BT_FUNC ("(branch)" , insn); +BT_FUNC ("(branch)" , insn);return ret; } }
@@ -3855,7 +3853,7 @@ static int validate_unwind_hint(struct objtool_file *file, {if (insn->hint && !insn->visited && !insn->ignore) {int ret =validate_branch (file,insn_func (insn), insn, *state); -if (ret && opts.backtrace) +if (ret)BT_FUNC ("<=== (hint)" , insn);return ret; }
@@ -3914,8 +3912,7 @@ static int validate_unret(struct objtool_file *file, struct instruction *insn) ret =validate_unret (file, alt->insn);if (ret) { -if (opts.backtrace) -BT_FUNC ("(alt)" , insn); +BT_FUNC ("(alt)" , insn);return ret; } }
@@ -3942,10 +3939,8 @@ static int validate_unret(struct objtool_file *file, struct instruction *insn) } ret =validate_unret (file, insn->jump_dest);if (ret) { -if (opts.backtrace) { -BT_FUNC ("(branch%s)" , insn, - insn->type ==INSN_JUMP_CONDITIONAL ?"-cond" :"" ); - } +BT_FUNC ("(branch%s)" , insn, + insn->type ==INSN_JUMP_CONDITIONAL ?"-cond" :"" );return ret; }
@@ -3967,8 +3962,7 @@ static int validate_unret(struct objtool_file *file, struct instruction *insn) ret =validate_unret (file, dest);if (ret) { -if (opts.backtrace) -BT_FUNC ("(call)" , insn); +BT_FUNC ("(call)" , insn);return ret; }/*
@@ -4254,7 +4248,7 @@ static int validate_symbol(struct objtool_file *file, struct section *sec, state->uaccess = sym->uaccess_safe; ret =validate_branch (file,insn_func (insn), insn, *state); -if (ret && opts.backtrace) +if (ret)BT_FUNC ("<=== (sym)" , insn);return ret; }
tools/objtool/include/objtool/builtin.h +0 -1
@@ -28,7 +28,6 @@ struct opts {bool cfi;/* options: */ -bool backtrace;bool backup;bool dryrun;bool link;
tools/objtool/include/objtool/warn.h +8 -6
@@ -91,12 +91,14 @@ static inline void objdump_func(struct section *sec, unsigned long offset)objdump_func (sec, offset); \ }) -#define BT_FUNC (format, insn, ...) \ -({ \ - struct instruction *_insn = (insn); \ - char *_str = offstr(_insn->sec, _insn->offset); \ - WARN(" %s: " format, _str, ##__VA_ARGS__); \ - free(_str); \ +#define BT_FUNC (format, insn, ...) \ +({ \ + if (opts.verbose) { \ + struct instruction *_insn = (insn); \ + char *_str = offstr(_insn->sec, _insn->offset); \ + WARN(" %s: " format, _str, ##__VA_ARGS__); \ + free(_str); \ + } \ })#define WARN_ELF (format, ...) \
Signature · 1 line
2.39.2
Peter Zijlstra
maintainerRe: [PATCH 2/5] objtool: Combine '--backtrace' with '--verbose'
Quoted 3 lines · Josh Poimboeuf
Get rid of the '--backtrace' option, instead including that functionality in '--verbose'. This makes it easy to gather all the information needed for diagnosing objtool warnings.
Hurmm.. can't we have verbose imply backtrace but keep the separate option? I'm not sure if I always want the objdump thing -- esp with multiple warnings on vmlinux that's going to be really slow -- better to dump the whole of vmlinux.o once at the end.
Josh Poimboeuf
maintainerRe: [PATCH 2/5] objtool: Combine '--backtrace' with '--verbose'
Quoted 9 lines · Peter Zijlstra
Quoted 3 lines · Josh Poimboeuf
Get rid of the '--backtrace' option, instead including that functionality in '--verbose'. This makes it easy to gather all the information needed for diagnosing objtool warnings.
Hurmm.. can't we have verbose imply backtrace but keep the separate option? I'm not sure if I always want the objdump thing -- esp with multiple warnings on vmlinux that's going to be really slow -- better to dump the whole of vmlinux.o once at the end.
That's a good point, vmlinux would be unbearable for multiple warnings.
We could accumulate a list of affected functions and then supply that to objdump-func.sh at the end and dump them all at the same time.
objdump-func.sh would need to be changed to look for multiple funcs at once.
If I do that, do you still want the separate backtrace option?
Signature · 1 line
Josh
Peter Zijlstra
maintainerRe: [PATCH 2/5] objtool: Combine '--backtrace' with '--verbose'
Quoted 13 lines · Josh Poimboeuf
Quoted 9 lines · Peter Zijlstra
Quoted 3 lines · Josh Poimboeuf
Get rid of the '--backtrace' option, instead including that functionality in '--verbose'. This makes it easy to gather all the information needed for diagnosing objtool warnings.
Hurmm.. can't we have verbose imply backtrace but keep the separate option? I'm not sure if I always want the objdump thing -- esp with multiple warnings on vmlinux that's going to be really slow -- better to dump the whole of vmlinux.o once at the end.
That's a good point, vmlinux would be unbearable for multiple warnings.
Quoted 7 lines
We could accumulate a list of affected functions and then supply that to
objdump-func.shat the end and dump them all at the same time.
objdump-func.shwould need to be changed to look for multiple funcs at once.If I do that, do you still want the separate backtrace option?
For now, lets keep the orthogonal options -- we can always remove it later if we find they go unused. This automagic stuff is going to take a bit of getting used to I recon ;-)
Josh Poimboeuf
maintainerPATCH 3/5 objtool: Remove superfluous dead_end_function() check
In reply to Josh Poimboeufannotate_call_site() already sets 'insn->dead_end' for calls to dead end functions.
--- tools/objtool/check.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
tools/objtool/check.c +1 -2
@@ -4140,8 +4140,7 @@ static bool ignore_unreachable_insn(struct objtool_file *file, struct instructio* It may also insert a UD2 after calling a __noreturn function. */ prev_insn =prev_insn_same_sec (file, insn); -if ((prev_insn->dead_end || -dead_end_function (file,insn_call_dest (prev_insn))) && +if (prev_insn->dead_end && (insn->type ==INSN_BUG || (insn->type ==INSN_JUMP_UNCONDITIONAL && insn->jump_dest && insn->jump_dest->type ==INSN_BUG )))
Signature · 1 line
2.39.2
Josh Poimboeuf
maintainerPATCH 4/5 objtool: Add per-function rate limiting for unreachable warnings
In reply to Josh PoimboeufUnreachable instruction warnings are rate limited to once per object file. That no longer makes sense for vmlinux validation, which might have other unreachable instructions lurking in other places. Change it to once per function.
--- tools/objtool/check.c | 4 ++++ tools/objtool/include/objtool/elf.h | 1 + 2 files changed, 5 insertions(+)
tools/objtool/check.c +4 -0
@@ -4557,6 +4557,10 @@ static int validate_reachable_instructions(struct objtool_file *file)if (insn->visited ||ignore_unreachable_insn (file, insn))continue ; +if (insn->sym->warned) +continue ; + insn->sym->warned =1 ; +WARN_FUNC ("unreachable instruction" , insn->sec, insn->offset);return 1 ; }
tools/objtool/include/objtool/elf.h +1 -0
@@ -61,6 +61,7 @@ struct symbol { u8 return_thunk : 1; u8 fentry : 1; u8 profiling_func : 1; + u8 warned : 1;struct list_head pv_target;struct list_head reloc_list; };
Signature · 1 line
2.39.2
Peter Zijlstra
maintainerRe: [PATCH 4/5] objtool: Add per-function rate limiting for unreachable warnings
Quoted 4 lines · Josh Poimboeuf
Unreachable instruction warnings are rate limited to once per object file. That no longer makes sense for vmlinux validation, which might have other unreachable instructions lurking in other places. Change it to once per function.
Do we want a negative option to disable this? --no-ratelimit or such?
Josh Poimboeuf
maintainerRe: [PATCH 4/5] objtool: Add per-function rate limiting for unreachable warnings
Quoted 7 lines · Peter Zijlstra
Quoted 4 lines · Josh Poimboeuf
Unreachable instruction warnings are rate limited to once per object file. That no longer makes sense for vmlinux validation, which might have other unreachable instructions lurking in other places. Change it to once per function.
Do we want a negative option to disable this? --no-ratelimit or such?
Per-function rate-limiting is almost always the right thing, personally I don't envision needing to disable it.
Signature · 1 line
Josh
Peter Zijlstra
maintainerRe: [PATCH 4/5] objtool: Add per-function rate limiting for unreachable warnings
Quoted 11 lines · Josh Poimboeuf
Quoted 7 lines · Peter Zijlstra
Quoted 4 lines · Josh Poimboeuf
Unreachable instruction warnings are rate limited to once per object file. That no longer makes sense for vmlinux validation, which might have other unreachable instructions lurking in other places. Change it to once per function.
Do we want a negative option to disable this? --no-ratelimit or such?
Per-function rate-limiting is almost always the right thing, personally I don't envision needing to disable it.
Ok, fair enough. I'll let you know if I ever come across the need to disable it :-)
Re: [PATCH 4/5] objtool: Add per-function rate limiting for unreachable warnings
In reply to Josh PoimboeufQuoted 16 lines · Josh Poimboeuf
Unreachable instruction warnings are rate limited to once per object file. That no longer makes sense for vmlinux validation, which might have other unreachable instructions lurking in other places. Change it to once per function.
Signed-off-by Josh Poimboeuf <[email protected]>--- tools/objtool/check.c | 4 ++++ tools/objtool/include/objtool/elf.h | 1 + 2 files changed, 5 insertions(+)tools/objtool/check.c +0
-0
tools/objtool/check.c static int validate_reachable_instructions(struct objtool_file *file) · line 4563
Quoted 7 lines
tools/objtool/check.c +4
-0@@ -4557,6 +4557,10 @@ static int validate_reachable_instructions(struct objtool_file *file)if (insn->visited ||ignore_unreachable_insn (file, insn))continue ; +if (insn->sym->warned) +continue ; + insn->sym->warned =1 ; +
Ok
tools/objtool/check.c static int validate_reachable_instructions(struct objtool_file *file) · line 4565
Quoted 2 lines
tools/objtool/check.c +0
-0WARN_FUNC ("unreachable instruction" , insn->sec, insn->offset);return 1 ;
But we still return here when an unreachable instruction is encountered and warned about. Or maybe I am just misunderstanding the purpose.
If not, would it be better to just collect the number of warnings per object as we do elsewhere?
warnings++;
and then at the end
return warnings;
Miroslav
Josh Poimboeuf
maintainerPATCH 5/5 objtool: Add "missing __noreturn" warning
In reply to Josh PoimboeufMost "unreachable instruction" warnings these days seem to actually be the result of a missing __noreturn annotation. Add an explicit check for that.
--- tools/objtool/Documentation/objtool.txt | 7 +++++++ tools/objtool/check.c | 16 ++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-)
tools/objtool/Documentation/objtool.txt +7 -0
@@ -423,6 +423,13 @@ the objtool maintainers. names and does not use module_init() / module_exit() macros to create them. +13. file.o: warning: func(): missing __noreturn + + Objtool has detected that the function doesn't return, but is missing + the __noreturn annotation. NOTE: In addition to adding the + __noreturn annotation, the function name also needs to be added to + 'global_noreturns' in tools/objtool/check.c. + If the error doesn't seem to make sense, it could be a bug in objtool. Feel free to ask the objtool maintainer for help.
tools/objtool/check.c +14 -2
@@ -4548,7 +4548,8 @@ static int validate_sls(struct objtool_file *file)static int validate_reachable_instructions (struct objtool_file *file) { -struct instruction *insn; +struct instruction *insn, *prev_insn; +struct symbol *call_dest;if (file->ignore_unreachables)return 0 ;
@@ -4561,8 +4562,19 @@ static int validate_reachable_instructions(struct objtool_file *file)continue ; insn->sym->warned =1 ; + prev_insn =prev_insn_same_sec (file, insn); +if (prev_insn) + call_dest =insn_call_dest (prev_insn); +if (prev_insn && prev_insn->dead_end && call_dest) { +if (call_dest->warned) +continue ; + call_dest->warned =1 ; + +WARN ("%s(): missing __noreturn" , call_dest->name); +continue ; + } +WARN_FUNC ("unreachable instruction" , insn->sec, insn->offset); -return 1 ; }return 0 ;
Signature · 1 line
2.39.2
Re: [PATCH 5/5] objtool: Add "missing __noreturn" warning
tools/objtool/check.c static int validate_reachable_instructions(struct objtool_file *file) · line 4565
Quoted 2 lines
tools/objtool/check.c +0
-1WARN_FUNC ("unreachable instruction" , insn->sec, insn->offset); -return 1 ;
I knew I should have read the whole set first...
Miroslav
Josh Poimboeuf
maintainerRe: [PATCH 5/5] objtool: Add "missing __noreturn" warning
Quoted 4 lines · Miroslav Benes
tools/objtool/check.c static int validate_reachable_instructions(struct objtool_file *file) · line 4565
Quoted 2 lines
tools/objtool/check.c +0
-1WARN_FUNC ("unreachable instruction" , insn->sec, insn->offset); -return 1 ;I knew I should have read the whole set first...
Oops, guess that is in the wrong patch.
Signature · 1 line
Josh