aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/vmlinux.lds.S1
-rw-r--r--include/linux/compiler-gcc.h13
-rw-r--r--tools/objtool/arch.h5
-rw-r--r--tools/objtool/arch/x86/decode.c3
-rw-r--r--tools/objtool/builtin-check.c60
5 files changed, 71 insertions, 11 deletions
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
index e79f15f108a8..ad0118fbce90 100644
--- a/arch/x86/kernel/vmlinux.lds.S
+++ b/arch/x86/kernel/vmlinux.lds.S
@@ -346,6 +346,7 @@ SECTIONS
346 /DISCARD/ : { 346 /DISCARD/ : {
347 *(.eh_frame) 347 *(.eh_frame)
348 *(__func_stack_frame_non_standard) 348 *(__func_stack_frame_non_standard)
349 *(__unreachable)
349 } 350 }
350} 351}
351 352
diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h
index 0444b1336268..8ea159fc489d 100644
--- a/include/linux/compiler-gcc.h
+++ b/include/linux/compiler-gcc.h
@@ -195,6 +195,17 @@
195#endif 195#endif
196#endif 196#endif
197 197
198#ifdef CONFIG_STACK_VALIDATION
199#define annotate_unreachable() ({ \
200 asm("1:\t\n" \
201 ".pushsection __unreachable, \"a\"\t\n" \
202 ".long 1b\t\n" \
203 ".popsection\t\n"); \
204})
205#else
206#define annotate_unreachable()
207#endif
208
198/* 209/*
199 * Mark a position in code as unreachable. This can be used to 210 * Mark a position in code as unreachable. This can be used to
200 * suppress control flow warnings after asm blocks that transfer 211 * suppress control flow warnings after asm blocks that transfer
@@ -204,7 +215,7 @@
204 * this in the preprocessor, but we can live with this because they're 215 * this in the preprocessor, but we can live with this because they're
205 * unreleased. Really, we need to have autoconf for the kernel. 216 * unreleased. Really, we need to have autoconf for the kernel.
206 */ 217 */
207#define unreachable() __builtin_unreachable() 218#define unreachable() annotate_unreachable(); __builtin_unreachable()
208 219
209/* Mark a function definition as prohibited from being cloned. */ 220/* Mark a function definition as prohibited from being cloned. */
210#define __noclone __attribute__((__noclone__, __optimize__("no-tracer"))) 221#define __noclone __attribute__((__noclone__, __optimize__("no-tracer")))
diff --git a/tools/objtool/arch.h b/tools/objtool/arch.h
index f7350fcedc70..a59e061c0b4a 100644
--- a/tools/objtool/arch.h
+++ b/tools/objtool/arch.h
@@ -31,9 +31,8 @@
31#define INSN_CALL_DYNAMIC 8 31#define INSN_CALL_DYNAMIC 8
32#define INSN_RETURN 9 32#define INSN_RETURN 9
33#define INSN_CONTEXT_SWITCH 10 33#define INSN_CONTEXT_SWITCH 10
34#define INSN_BUG 11 34#define INSN_NOP 11
35#define INSN_NOP 12 35#define INSN_OTHER 12
36#define INSN_OTHER 13
37#define INSN_LAST INSN_OTHER 36#define INSN_LAST INSN_OTHER
38 37
39int arch_decode_instruction(struct elf *elf, struct section *sec, 38int arch_decode_instruction(struct elf *elf, struct section *sec,
diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c
index 039636ffb6c8..6ac99e3266eb 100644
--- a/tools/objtool/arch/x86/decode.c
+++ b/tools/objtool/arch/x86/decode.c
@@ -118,9 +118,6 @@ int arch_decode_instruction(struct elf *elf, struct section *sec,
118 op2 == 0x35) 118 op2 == 0x35)
119 /* sysenter, sysret */ 119 /* sysenter, sysret */
120 *type = INSN_CONTEXT_SWITCH; 120 *type = INSN_CONTEXT_SWITCH;
121 else if (op2 == 0x0b || op2 == 0xb9)
122 /* ud2 */
123 *type = INSN_BUG;
124 else if (op2 == 0x0d || op2 == 0x1f) 121 else if (op2 == 0x0d || op2 == 0x1f)
125 /* nopl/nopw */ 122 /* nopl/nopw */
126 *type = INSN_NOP; 123 *type = INSN_NOP;
diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c
index e8a1f699058a..5fc52ee3264c 100644
--- a/tools/objtool/builtin-check.c
+++ b/tools/objtool/builtin-check.c
@@ -51,7 +51,7 @@ struct instruction {
51 unsigned int len, state; 51 unsigned int len, state;
52 unsigned char type; 52 unsigned char type;
53 unsigned long immediate; 53 unsigned long immediate;
54 bool alt_group, visited; 54 bool alt_group, visited, dead_end;
55 struct symbol *call_dest; 55 struct symbol *call_dest;
56 struct instruction *jump_dest; 56 struct instruction *jump_dest;
57 struct list_head alts; 57 struct list_head alts;
@@ -330,6 +330,54 @@ static int decode_instructions(struct objtool_file *file)
330} 330}
331 331
332/* 332/*
333 * Find all uses of the unreachable() macro, which are code path dead ends.
334 */
335static int add_dead_ends(struct objtool_file *file)
336{
337 struct section *sec;
338 struct rela *rela;
339 struct instruction *insn;
340 bool found;
341
342 sec = find_section_by_name(file->elf, ".rela__unreachable");
343 if (!sec)
344 return 0;
345
346 list_for_each_entry(rela, &sec->rela_list, list) {
347 if (rela->sym->type != STT_SECTION) {
348 WARN("unexpected relocation symbol type in .rela__unreachable");
349 return -1;
350 }
351 insn = find_insn(file, rela->sym->sec, rela->addend);
352 if (insn)
353 insn = list_prev_entry(insn, list);
354 else if (rela->addend == rela->sym->sec->len) {
355 found = false;
356 list_for_each_entry_reverse(insn, &file->insn_list, list) {
357 if (insn->sec == rela->sym->sec) {
358 found = true;
359 break;
360 }
361 }
362
363 if (!found) {
364 WARN("can't find unreachable insn at %s+0x%x",
365 rela->sym->sec->name, rela->addend);
366 return -1;
367 }
368 } else {
369 WARN("can't find unreachable insn at %s+0x%x",
370 rela->sym->sec->name, rela->addend);
371 return -1;
372 }
373
374 insn->dead_end = true;
375 }
376
377 return 0;
378}
379
380/*
333 * Warnings shouldn't be reported for ignored functions. 381 * Warnings shouldn't be reported for ignored functions.
334 */ 382 */
335static void add_ignores(struct objtool_file *file) 383static void add_ignores(struct objtool_file *file)
@@ -843,6 +891,10 @@ static int decode_sections(struct objtool_file *file)
843 if (ret) 891 if (ret)
844 return ret; 892 return ret;
845 893
894 ret = add_dead_ends(file);
895 if (ret)
896 return ret;
897
846 add_ignores(file); 898 add_ignores(file);
847 899
848 ret = add_jump_destinations(file); 900 ret = add_jump_destinations(file);
@@ -1037,13 +1089,13 @@ static int validate_branch(struct objtool_file *file,
1037 1089
1038 return 0; 1090 return 0;
1039 1091
1040 case INSN_BUG:
1041 return 0;
1042
1043 default: 1092 default:
1044 break; 1093 break;
1045 } 1094 }
1046 1095
1096 if (insn->dead_end)
1097 return 0;
1098
1047 insn = next_insn_same_sec(file, insn); 1099 insn = next_insn_same_sec(file, insn);
1048 if (!insn) { 1100 if (!insn) {
1049 WARN("%s: unexpected end of section", sec->name); 1101 WARN("%s: unexpected end of section", sec->name);