aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorJosh Poimboeuf <jpoimboe@redhat.com>2016-04-15 10:17:10 -0400
committerIngo Molnar <mingo@kernel.org>2016-04-16 05:14:17 -0400
commitb1547d3101e74e809b9790174b27f1080747b009 (patch)
treef5eeb80c700d7dcaf512338063a07751d79d281d /tools
parent7e578441a4a3bba2a79426ca0f709c801210d08e (diff)
objtool: Detect falling through to the next function
There are several cases in compiled C code where a function may not return at the end, and may instead fall through to the next function. That may indicate a bug in the code, or a gcc bug, or even an objtool bug. But in each case, objtool reports an unhelpful warning, something like: drivers/scsi/qla2xxx/qla_attr.o: warning: objtool: qla2x00_get_fc_host_stats()+0x0: duplicate frame pointer save drivers/scsi/qla2xxx/qla_attr.o: warning: objtool: qla2x00_get_fc_host_stats()+0x0: frame pointer state mismatch Detect this situation and print a more useful error message: drivers/scsi/qla2xxx/qla_attr.o: warning: objtool: qla2x00_get_host_fabric_name() falls through to next function qla2x00_get_starget_node_name() Also add some information about this warning and its potential causes to the documentation. Reported-by: kbuild test robot <fengguang.wu@intel.com> Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Andy Lutomirski <luto@amacapital.net> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Borislav Petkov <bp@alien8.de> Cc: Brian Gerst <brgerst@gmail.com> Cc: Denys Vlasenko <dvlasenk@redhat.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Link: http://lkml.kernel.org/r/caa4ec6c687931db805e692d4e4bf06cd87d33e6.1460729697.git.jpoimboe@redhat.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools')
-rw-r--r--tools/objtool/Documentation/stack-validation.txt38
-rw-r--r--tools/objtool/builtin-check.c46
2 files changed, 61 insertions, 23 deletions
diff --git a/tools/objtool/Documentation/stack-validation.txt b/tools/objtool/Documentation/stack-validation.txt
index 5a95896105bc..55a60d331f47 100644
--- a/tools/objtool/Documentation/stack-validation.txt
+++ b/tools/objtool/Documentation/stack-validation.txt
@@ -299,18 +299,38 @@ they mean, and suggestions for how to fix them.
299Errors in .c files 299Errors in .c files
300------------------ 300------------------
301 301
302If you're getting an objtool error in a compiled .c file, chances are 3021. c_file.o: warning: objtool: funcA() falls through to next function funcB()
303the file uses an asm() statement which has a "call" instruction. An
304asm() statement with a call instruction must declare the use of the
305stack pointer in its output operand. For example, on x86_64:
306 303
307 register void *__sp asm("rsp"); 304 This means that funcA() doesn't end with a return instruction or an
308 asm volatile("call func" : "+r" (__sp)); 305 unconditional jump, and that objtool has determined that the function
306 can fall through into the next function. There could be different
307 reasons for this:
309 308
310Otherwise the stack frame may not get created before the call. 309 1) funcA()'s last instruction is a call to a "noreturn" function like
310 panic(). In this case the noreturn function needs to be added to
311 objtool's hard-coded global_noreturns array. Feel free to bug the
312 objtool maintainer, or you can submit a patch.
311 313
312Another possible cause for errors in C code is if the Makefile removes 314 2) funcA() uses the unreachable() annotation in a section of code
313-fno-omit-frame-pointer or adds -fomit-frame-pointer to the gcc options. 315 that is actually reachable.
316
317 3) If funcA() calls an inline function, the object code for funcA()
318 might be corrupt due to a gcc bug. For more details, see:
319 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70646
320
3212. If you're getting any other objtool error in a compiled .c file, it
322 may be because the file uses an asm() statement which has a "call"
323 instruction. An asm() statement with a call instruction must declare
324 the use of the stack pointer in its output operand. For example, on
325 x86_64:
326
327 register void *__sp asm("rsp");
328 asm volatile("call func" : "+r" (__sp));
329
330 Otherwise the stack frame may not get created before the call.
331
3323. Another possible cause for errors in C code is if the Makefile removes
333 -fno-omit-frame-pointer or adds -fomit-frame-pointer to the gcc options.
314 334
315Also see the above section for .S file errors for more information what 335Also see the above section for .S file errors for more information what
316the individual error messages mean. 336the individual error messages mean.
diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c
index 157a0f96d64d..e8a1e69eb92c 100644
--- a/tools/objtool/builtin-check.c
+++ b/tools/objtool/builtin-check.c
@@ -54,6 +54,7 @@ struct instruction {
54 struct symbol *call_dest; 54 struct symbol *call_dest;
55 struct instruction *jump_dest; 55 struct instruction *jump_dest;
56 struct list_head alts; 56 struct list_head alts;
57 struct symbol *func;
57}; 58};
58 59
59struct alternative { 60struct alternative {
@@ -66,7 +67,7 @@ struct objtool_file {
66 struct list_head insn_list; 67 struct list_head insn_list;
67 DECLARE_HASHTABLE(insn_hash, 16); 68 DECLARE_HASHTABLE(insn_hash, 16);
68 struct section *rodata, *whitelist; 69 struct section *rodata, *whitelist;
69 bool ignore_unreachables; 70 bool ignore_unreachables, c_file;
70}; 71};
71 72
72const char *objname; 73const char *objname;
@@ -229,7 +230,7 @@ static int __dead_end_function(struct objtool_file *file, struct symbol *func,
229 } 230 }
230 } 231 }
231 232
232 if (insn->type == INSN_JUMP_DYNAMIC) 233 if (insn->type == INSN_JUMP_DYNAMIC && list_empty(&insn->alts))
233 /* sibling call */ 234 /* sibling call */
234 return 0; 235 return 0;
235 } 236 }
@@ -249,6 +250,7 @@ static int dead_end_function(struct objtool_file *file, struct symbol *func)
249static int decode_instructions(struct objtool_file *file) 250static int decode_instructions(struct objtool_file *file)
250{ 251{
251 struct section *sec; 252 struct section *sec;
253 struct symbol *func;
252 unsigned long offset; 254 unsigned long offset;
253 struct instruction *insn; 255 struct instruction *insn;
254 int ret; 256 int ret;
@@ -282,6 +284,21 @@ static int decode_instructions(struct objtool_file *file)
282 hash_add(file->insn_hash, &insn->hash, insn->offset); 284 hash_add(file->insn_hash, &insn->hash, insn->offset);
283 list_add_tail(&insn->list, &file->insn_list); 285 list_add_tail(&insn->list, &file->insn_list);
284 } 286 }
287
288 list_for_each_entry(func, &sec->symbol_list, list) {
289 if (func->type != STT_FUNC)
290 continue;
291
292 if (!find_insn(file, sec, func->offset)) {
293 WARN("%s(): can't find starting instruction",
294 func->name);
295 return -1;
296 }
297
298 func_for_each_insn(file, func, insn)
299 if (!insn->func)
300 insn->func = func;
301 }
285 } 302 }
286 303
287 return 0; 304 return 0;
@@ -824,6 +841,7 @@ static int validate_branch(struct objtool_file *file,
824 struct alternative *alt; 841 struct alternative *alt;
825 struct instruction *insn; 842 struct instruction *insn;
826 struct section *sec; 843 struct section *sec;
844 struct symbol *func = NULL;
827 unsigned char state; 845 unsigned char state;
828 int ret; 846 int ret;
829 847
@@ -838,6 +856,16 @@ static int validate_branch(struct objtool_file *file,
838 } 856 }
839 857
840 while (1) { 858 while (1) {
859 if (file->c_file && insn->func) {
860 if (func && func != insn->func) {
861 WARN("%s() falls through to next function %s()",
862 func->name, insn->func->name);
863 return 1;
864 }
865
866 func = insn->func;
867 }
868
841 if (insn->visited) { 869 if (insn->visited) {
842 if (frame_state(insn->state) != frame_state(state)) { 870 if (frame_state(insn->state) != frame_state(state)) {
843 WARN_FUNC("frame pointer state mismatch", 871 WARN_FUNC("frame pointer state mismatch",
@@ -848,13 +876,6 @@ static int validate_branch(struct objtool_file *file,
848 return 0; 876 return 0;
849 } 877 }
850 878
851 /*
852 * Catch a rare case where a noreturn function falls through to
853 * the next function.
854 */
855 if (is_fentry_call(insn) && (state & STATE_FENTRY))
856 return 0;
857
858 insn->visited = true; 879 insn->visited = true;
859 insn->state = state; 880 insn->state = state;
860 881
@@ -1060,12 +1081,8 @@ static int validate_functions(struct objtool_file *file)
1060 continue; 1081 continue;
1061 1082
1062 insn = find_insn(file, sec, func->offset); 1083 insn = find_insn(file, sec, func->offset);
1063 if (!insn) { 1084 if (!insn)
1064 WARN("%s(): can't find starting instruction",
1065 func->name);
1066 warnings++;
1067 continue; 1085 continue;
1068 }
1069 1086
1070 ret = validate_branch(file, insn, 0); 1087 ret = validate_branch(file, insn, 0);
1071 warnings += ret; 1088 warnings += ret;
@@ -1162,6 +1179,7 @@ int cmd_check(int argc, const char **argv)
1162 file.whitelist = find_section_by_name(file.elf, "__func_stack_frame_non_standard"); 1179 file.whitelist = find_section_by_name(file.elf, "__func_stack_frame_non_standard");
1163 file.rodata = find_section_by_name(file.elf, ".rodata"); 1180 file.rodata = find_section_by_name(file.elf, ".rodata");
1164 file.ignore_unreachables = false; 1181 file.ignore_unreachables = false;
1182 file.c_file = find_section_by_name(file.elf, ".comment");
1165 1183
1166 ret = decode_sections(&file); 1184 ret = decode_sections(&file);
1167 if (ret < 0) 1185 if (ret < 0)