diff options
author | Peter Zijlstra <peterz@infradead.org> | 2019-03-01 05:15:49 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2019-04-03 05:02:24 -0400 |
commit | 7697eee3ddd768a1fd78c1e687afaa6c5aa5072d (patch) | |
tree | 2aa9fcbbf6b43a95793edcbc02dfbc5dd8bb9e3f /tools/objtool | |
parent | aaf5c623b915d64beba676b8c2e9708d1fda94d6 (diff) |
objtool: Add --backtrace support
For when you want to know the path that reached your fail state:
$ ./objtool check --no-fp --backtrace arch/x86/lib/usercopy_64.o
arch/x86/lib/usercopy_64.o: warning: objtool: .altinstr_replacement+0x3: UACCESS disable without MEMOPs: __clear_user()
arch/x86/lib/usercopy_64.o: warning: objtool: __clear_user()+0x3a: (alt)
arch/x86/lib/usercopy_64.o: warning: objtool: __clear_user()+0x2e: (branch)
arch/x86/lib/usercopy_64.o: warning: objtool: __clear_user()+0x18: (branch)
arch/x86/lib/usercopy_64.o: warning: objtool: .altinstr_replacement+0xffffffffffffffff: (branch)
arch/x86/lib/usercopy_64.o: warning: objtool: __clear_user()+0x5: (alt)
arch/x86/lib/usercopy_64.o: warning: objtool: __clear_user()+0x0: <=== (func)
0000000000000000 <__clear_user>:
0: e8 00 00 00 00 callq 5 <__clear_user+0x5>
1: R_X86_64_PLT32 __fentry__-0x4
5: 90 nop
6: 90 nop
7: 90 nop
8: 48 89 f0 mov %rsi,%rax
b: 48 c1 ee 03 shr $0x3,%rsi
f: 83 e0 07 and $0x7,%eax
12: 48 89 f1 mov %rsi,%rcx
15: 48 85 c9 test %rcx,%rcx
18: 74 0f je 29 <__clear_user+0x29>
1a: 48 c7 07 00 00 00 00 movq $0x0,(%rdi)
21: 48 83 c7 08 add $0x8,%rdi
25: ff c9 dec %ecx
27: 75 f1 jne 1a <__clear_user+0x1a>
29: 48 89 c1 mov %rax,%rcx
2c: 85 c9 test %ecx,%ecx
2e: 74 0a je 3a <__clear_user+0x3a>
30: c6 07 00 movb $0x0,(%rdi)
33: 48 ff c7 inc %rdi
36: ff c9 dec %ecx
38: 75 f6 jne 30 <__clear_user+0x30>
3a: 90 nop
3b: 90 nop
3c: 90 nop
3d: 48 89 c8 mov %rcx,%rax
40: c3 retq
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools/objtool')
-rw-r--r-- | tools/objtool/builtin-check.c | 3 | ||||
-rw-r--r-- | tools/objtool/builtin.h | 2 | ||||
-rw-r--r-- | tools/objtool/check.c | 18 | ||||
-rw-r--r-- | tools/objtool/warn.h | 8 |
4 files changed, 25 insertions, 6 deletions
diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c index 694abc628e9b..99f10c585cbe 100644 --- a/tools/objtool/builtin-check.c +++ b/tools/objtool/builtin-check.c | |||
@@ -29,7 +29,7 @@ | |||
29 | #include "builtin.h" | 29 | #include "builtin.h" |
30 | #include "check.h" | 30 | #include "check.h" |
31 | 31 | ||
32 | bool no_fp, no_unreachable, retpoline, module; | 32 | bool no_fp, no_unreachable, retpoline, module, backtrace; |
33 | 33 | ||
34 | static const char * const check_usage[] = { | 34 | static const char * const check_usage[] = { |
35 | "objtool check [<options>] file.o", | 35 | "objtool check [<options>] file.o", |
@@ -41,6 +41,7 @@ const struct option check_options[] = { | |||
41 | OPT_BOOLEAN('u', "no-unreachable", &no_unreachable, "Skip 'unreachable instruction' warnings"), | 41 | OPT_BOOLEAN('u', "no-unreachable", &no_unreachable, "Skip 'unreachable instruction' warnings"), |
42 | OPT_BOOLEAN('r', "retpoline", &retpoline, "Validate retpoline assumptions"), | 42 | OPT_BOOLEAN('r', "retpoline", &retpoline, "Validate retpoline assumptions"), |
43 | OPT_BOOLEAN('m', "module", &module, "Indicates the object will be part of a kernel module"), | 43 | OPT_BOOLEAN('m', "module", &module, "Indicates the object will be part of a kernel module"), |
44 | OPT_BOOLEAN('b', "backtrace", &backtrace, "unwind on error"), | ||
44 | OPT_END(), | 45 | OPT_END(), |
45 | }; | 46 | }; |
46 | 47 | ||
diff --git a/tools/objtool/builtin.h b/tools/objtool/builtin.h index 28ff40e19a14..65fd3cc3c98b 100644 --- a/tools/objtool/builtin.h +++ b/tools/objtool/builtin.h | |||
@@ -20,7 +20,7 @@ | |||
20 | #include <subcmd/parse-options.h> | 20 | #include <subcmd/parse-options.h> |
21 | 21 | ||
22 | extern const struct option check_options[]; | 22 | extern const struct option check_options[]; |
23 | extern bool no_fp, no_unreachable, retpoline, module; | 23 | extern bool no_fp, no_unreachable, retpoline, module, backtrace; |
24 | 24 | ||
25 | extern int cmd_check(int argc, const char **argv); | 25 | extern int cmd_check(int argc, const char **argv); |
26 | extern int cmd_orc(int argc, const char **argv); | 26 | extern int cmd_orc(int argc, const char **argv); |
diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 8d8191f25381..ccc66af5907f 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c | |||
@@ -1885,8 +1885,11 @@ static int validate_branch(struct objtool_file *file, struct instruction *first, | |||
1885 | if (!insn->ignore_alts) { | 1885 | if (!insn->ignore_alts) { |
1886 | list_for_each_entry(alt, &insn->alts, list) { | 1886 | list_for_each_entry(alt, &insn->alts, list) { |
1887 | ret = validate_branch(file, alt->insn, state); | 1887 | ret = validate_branch(file, alt->insn, state); |
1888 | if (ret) | 1888 | if (ret) { |
1889 | return 1; | 1889 | if (backtrace) |
1890 | BT_FUNC("(alt)", insn); | ||
1891 | return ret; | ||
1892 | } | ||
1890 | } | 1893 | } |
1891 | } | 1894 | } |
1892 | 1895 | ||
@@ -1933,8 +1936,11 @@ static int validate_branch(struct objtool_file *file, struct instruction *first, | |||
1933 | insn->jump_dest->func->pfunc == func)) { | 1936 | insn->jump_dest->func->pfunc == func)) { |
1934 | ret = validate_branch(file, insn->jump_dest, | 1937 | ret = validate_branch(file, insn->jump_dest, |
1935 | state); | 1938 | state); |
1936 | if (ret) | 1939 | if (ret) { |
1937 | return 1; | 1940 | if (backtrace) |
1941 | BT_FUNC("(branch)", insn); | ||
1942 | return ret; | ||
1943 | } | ||
1938 | 1944 | ||
1939 | } else if (func && has_modified_stack_frame(&state)) { | 1945 | } else if (func && has_modified_stack_frame(&state)) { |
1940 | WARN_FUNC("sibling call from callable instruction with modified stack frame", | 1946 | WARN_FUNC("sibling call from callable instruction with modified stack frame", |
@@ -2005,6 +2011,8 @@ static int validate_unwind_hints(struct objtool_file *file) | |||
2005 | for_each_insn(file, insn) { | 2011 | for_each_insn(file, insn) { |
2006 | if (insn->hint && !insn->visited) { | 2012 | if (insn->hint && !insn->visited) { |
2007 | ret = validate_branch(file, insn, state); | 2013 | ret = validate_branch(file, insn, state); |
2014 | if (ret && backtrace) | ||
2015 | BT_FUNC("<=== (hint)", insn); | ||
2008 | warnings += ret; | 2016 | warnings += ret; |
2009 | } | 2017 | } |
2010 | } | 2018 | } |
@@ -2133,6 +2141,8 @@ static int validate_functions(struct objtool_file *file) | |||
2133 | continue; | 2141 | continue; |
2134 | 2142 | ||
2135 | ret = validate_branch(file, insn, state); | 2143 | ret = validate_branch(file, insn, state); |
2144 | if (ret && backtrace) | ||
2145 | BT_FUNC("<=== (func)", insn); | ||
2136 | warnings += ret; | 2146 | warnings += ret; |
2137 | } | 2147 | } |
2138 | } | 2148 | } |
diff --git a/tools/objtool/warn.h b/tools/objtool/warn.h index afd9f7a05f6d..f4fbb972b611 100644 --- a/tools/objtool/warn.h +++ b/tools/objtool/warn.h | |||
@@ -64,6 +64,14 @@ static inline char *offstr(struct section *sec, unsigned long offset) | |||
64 | free(_str); \ | 64 | free(_str); \ |
65 | }) | 65 | }) |
66 | 66 | ||
67 | #define BT_FUNC(format, insn, ...) \ | ||
68 | ({ \ | ||
69 | struct instruction *_insn = (insn); \ | ||
70 | char *_str = offstr(_insn->sec, _insn->offset); \ | ||
71 | WARN(" %s: " format, _str, ##__VA_ARGS__); \ | ||
72 | free(_str); \ | ||
73 | }) | ||
74 | |||
67 | #define WARN_ELF(format, ...) \ | 75 | #define WARN_ELF(format, ...) \ |
68 | WARN(format ": %s", ##__VA_ARGS__, elf_errmsg(-1)) | 76 | WARN(format ": %s", ##__VA_ARGS__, elf_errmsg(-1)) |
69 | 77 | ||