aboutsummaryrefslogtreecommitdiffstats
path: root/common/recipes-kernel/linux/linux-yocto-4.9.21/0086-objtool-Improve-detection-of-BUG-and-other-dead-ends.patch
diff options
context:
space:
mode:
Diffstat (limited to 'common/recipes-kernel/linux/linux-yocto-4.9.21/0086-objtool-Improve-detection-of-BUG-and-other-dead-ends.patch')
-rw-r--r--common/recipes-kernel/linux/linux-yocto-4.9.21/0086-objtool-Improve-detection-of-BUG-and-other-dead-ends.patch217
1 files changed, 217 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/linux-yocto-4.9.21/0086-objtool-Improve-detection-of-BUG-and-other-dead-ends.patch b/common/recipes-kernel/linux/linux-yocto-4.9.21/0086-objtool-Improve-detection-of-BUG-and-other-dead-ends.patch
new file mode 100644
index 00000000..f659e885
--- /dev/null
+++ b/common/recipes-kernel/linux/linux-yocto-4.9.21/0086-objtool-Improve-detection-of-BUG-and-other-dead-ends.patch
@@ -0,0 +1,217 @@
+From 655125acee5c084743a8bae4ffe2b723856594ce Mon Sep 17 00:00:00 2001
+From: Josh Poimboeuf <jpoimboe@redhat.com>
+Date: Tue, 21 Feb 2017 15:35:32 -0600
+Subject: [PATCH 86/93] objtool: Improve detection of BUG() and other dead ends
+
+commit d1091c7fa3d52ebce4dd3f15d04155b3469b2f90 upstream.
+
+The BUG() macro's use of __builtin_unreachable() via the unreachable()
+macro tells gcc that the instruction is a dead end, and that it's safe
+to assume the current code path will not execute past the previous
+instruction.
+
+On x86, the BUG() macro is implemented with the 'ud2' instruction. When
+objtool's branch analysis sees that instruction, it knows the current
+code path has come to a dead end.
+
+Peter Zijlstra has been working on a patch to change the WARN macros to
+use 'ud2'. That patch will break objtool's assumption that 'ud2' is
+always a dead end.
+
+Generally it's best for objtool to avoid making those kinds of
+assumptions anyway. The more ignorant it is of kernel code internals,
+the better.
+
+So create a more generic way for objtool to detect dead ends by adding
+an annotation to the unreachable() macro. The annotation stores a
+pointer to the end of the unreachable code path in an '__unreachable'
+section. Objtool can read that section to find the dead ends.
+
+Tested-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Signed-off-by: Josh Poimboeuf <jpoimboe@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/41a6d33971462ebd944a1c60ad4bf5be86c17b77.1487712920.git.jpoimboe@redhat.com
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/kernel/vmlinux.lds.S | 1 +
+ include/linux/compiler-gcc.h | 13 ++++++++-
+ tools/objtool/arch.h | 5 ++--
+ tools/objtool/arch/x86/decode.c | 3 ---
+ tools/objtool/builtin-check.c | 60 ++++++++++++++++++++++++++++++++++++++---
+ 5 files changed, 71 insertions(+), 11 deletions(-)
+
+diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
+index c7194e9..4ef267f 100644
+--- a/arch/x86/kernel/vmlinux.lds.S
++++ b/arch/x86/kernel/vmlinux.lds.S
+@@ -353,6 +353,7 @@ SECTIONS
+ /DISCARD/ : {
+ *(.eh_frame)
+ *(__func_stack_frame_non_standard)
++ *(__unreachable)
+ }
+ }
+
+diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h
+index 362a1e17..b69d102 100644
+--- a/include/linux/compiler-gcc.h
++++ b/include/linux/compiler-gcc.h
+@@ -199,6 +199,17 @@
+ #endif
+ #endif
+
++#ifdef CONFIG_STACK_VALIDATION
++#define annotate_unreachable() ({ \
++ asm("1:\t\n" \
++ ".pushsection __unreachable, \"a\"\t\n" \
++ ".long 1b\t\n" \
++ ".popsection\t\n"); \
++})
++#else
++#define annotate_unreachable()
++#endif
++
+ /*
+ * Mark a position in code as unreachable. This can be used to
+ * suppress control flow warnings after asm blocks that transfer
+@@ -208,7 +219,7 @@
+ * this in the preprocessor, but we can live with this because they're
+ * unreleased. Really, we need to have autoconf for the kernel.
+ */
+-#define unreachable() __builtin_unreachable()
++#define unreachable() annotate_unreachable(); __builtin_unreachable()
+
+ /* Mark a function definition as prohibited from being cloned. */
+ #define __noclone __attribute__((__noclone__, __optimize__("no-tracer")))
+diff --git a/tools/objtool/arch.h b/tools/objtool/arch.h
+index f7350fc..a59e061 100644
+--- a/tools/objtool/arch.h
++++ b/tools/objtool/arch.h
+@@ -31,9 +31,8 @@
+ #define INSN_CALL_DYNAMIC 8
+ #define INSN_RETURN 9
+ #define INSN_CONTEXT_SWITCH 10
+-#define INSN_BUG 11
+-#define INSN_NOP 12
+-#define INSN_OTHER 13
++#define INSN_NOP 11
++#define INSN_OTHER 12
+ #define INSN_LAST INSN_OTHER
+
+ int 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 5e0dea2..9fb487f 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,
+ op2 == 0x35)
+ /* sysenter, sysret */
+ *type = INSN_CONTEXT_SWITCH;
+- else if (op2 == 0x0b || op2 == 0xb9)
+- /* ud2 */
+- *type = INSN_BUG;
+ else if (op2 == 0x0d || op2 == 0x1f)
+ /* nopl/nopw */
+ *type = INSN_NOP;
+diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c
+index 377bff0..ad9eda9 100644
+--- a/tools/objtool/builtin-check.c
++++ b/tools/objtool/builtin-check.c
+@@ -51,7 +51,7 @@ struct instruction {
+ unsigned int len, state;
+ unsigned char type;
+ unsigned long immediate;
+- bool alt_group, visited, ignore_alts;
++ bool alt_group, visited, dead_end, ignore_alts;
+ struct symbol *call_dest;
+ struct instruction *jump_dest;
+ struct list_head alts;
+@@ -330,6 +330,54 @@ static int decode_instructions(struct objtool_file *file)
+ }
+
+ /*
++ * Find all uses of the unreachable() macro, which are code path dead ends.
++ */
++static int add_dead_ends(struct objtool_file *file)
++{
++ struct section *sec;
++ struct rela *rela;
++ struct instruction *insn;
++ bool found;
++
++ sec = find_section_by_name(file->elf, ".rela__unreachable");
++ if (!sec)
++ return 0;
++
++ list_for_each_entry(rela, &sec->rela_list, list) {
++ if (rela->sym->type != STT_SECTION) {
++ WARN("unexpected relocation symbol type in .rela__unreachable");
++ return -1;
++ }
++ insn = find_insn(file, rela->sym->sec, rela->addend);
++ if (insn)
++ insn = list_prev_entry(insn, list);
++ else if (rela->addend == rela->sym->sec->len) {
++ found = false;
++ list_for_each_entry_reverse(insn, &file->insn_list, list) {
++ if (insn->sec == rela->sym->sec) {
++ found = true;
++ break;
++ }
++ }
++
++ if (!found) {
++ WARN("can't find unreachable insn at %s+0x%x",
++ rela->sym->sec->name, rela->addend);
++ return -1;
++ }
++ } else {
++ WARN("can't find unreachable insn at %s+0x%x",
++ rela->sym->sec->name, rela->addend);
++ return -1;
++ }
++
++ insn->dead_end = true;
++ }
++
++ return 0;
++}
++
++/*
+ * Warnings shouldn't be reported for ignored functions.
+ */
+ static void add_ignores(struct objtool_file *file)
+@@ -896,6 +944,10 @@ static int decode_sections(struct objtool_file *file)
+ if (ret)
+ return ret;
+
++ ret = add_dead_ends(file);
++ if (ret)
++ return ret;
++
+ add_ignores(file);
+
+ ret = add_nospec_ignores(file);
+@@ -1094,13 +1146,13 @@ static int validate_branch(struct objtool_file *file,
+
+ return 0;
+
+- case INSN_BUG:
+- return 0;
+-
+ default:
+ break;
+ }
+
++ if (insn->dead_end)
++ return 0;
++
+ insn = next_insn_same_sec(file, insn);
+ if (!insn) {
+ WARN("%s: unexpected end of section", sec->name);
+--
+2.7.4
+