summaryrefslogtreecommitdiffstats
path: root/tools/objtool
diff options
context:
space:
mode:
authorPeter Zijlstra <peterz@infradead.org>2019-03-01 05:15:49 -0500
committerIngo Molnar <mingo@kernel.org>2019-04-03 05:02:24 -0400
commit7697eee3ddd768a1fd78c1e687afaa6c5aa5072d (patch)
tree2aa9fcbbf6b43a95793edcbc02dfbc5dd8bb9e3f /tools/objtool
parentaaf5c623b915d64beba676b8c2e9708d1fda94d6 (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.c3
-rw-r--r--tools/objtool/builtin.h2
-rw-r--r--tools/objtool/check.c18
-rw-r--r--tools/objtool/warn.h8
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
32bool no_fp, no_unreachable, retpoline, module; 32bool no_fp, no_unreachable, retpoline, module, backtrace;
33 33
34static const char * const check_usage[] = { 34static 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
22extern const struct option check_options[]; 22extern const struct option check_options[];
23extern bool no_fp, no_unreachable, retpoline, module; 23extern bool no_fp, no_unreachable, retpoline, module, backtrace;
24 24
25extern int cmd_check(int argc, const char **argv); 25extern int cmd_check(int argc, const char **argv);
26extern int cmd_orc(int argc, const char **argv); 26extern 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