]> Git Repo - linux.git/commitdiff
x86/unwind/orc: Fall back to using frame pointers for generated code
authorJosh Poimboeuf <[email protected]>
Thu, 27 Jun 2019 00:33:55 +0000 (19:33 -0500)
committerThomas Gleixner <[email protected]>
Thu, 27 Jun 2019 22:11:21 +0000 (00:11 +0200)
The ORC unwinder can't unwind through BPF JIT generated code because
there are no ORC entries associated with the code.

If an ORC entry isn't available, try to fall back to frame pointers.  If
BPF and other generated code always do frame pointer setup (even with
CONFIG_FRAME_POINTERS=n) then this will allow ORC to unwind through most
generated code despite there being no corresponding ORC entries.

Fixes: d15d356887e7 ("perf/x86: Make perf callchains work without CONFIG_FRAME_POINTER")
Reported-by: Song Liu <[email protected]>
Signed-off-by: Josh Poimboeuf <[email protected]>
Signed-off-by: Thomas Gleixner <[email protected]>
Acked-by: Peter Zijlstra (Intel) <[email protected]>
Cc: Kairui Song <[email protected]>
Cc: Steven Rostedt <[email protected]>
Cc: Borislav Petkov <[email protected]>
Link: https://lkml.kernel.org/r/b6f69208ddff4343d56b7bfac1fc7cfcd62689e8.1561595111.git.jpoimboe@redhat.com
arch/x86/kernel/unwind_orc.c

index 33b66b5c5aec3244a11f565ed0334383b8c29fae..72b997eaa1fc6efd1ff1d214934d9ee452f2f0c1 100644 (file)
@@ -82,9 +82,9 @@ static struct orc_entry *orc_find(unsigned long ip);
  * But they are copies of the ftrace entries that are static and
  * defined in ftrace_*.S, which do have orc entries.
  *
- * If the undwinder comes across a ftrace trampoline, then find the
+ * If the unwinder comes across a ftrace trampoline, then find the
  * ftrace function that was used to create it, and use that ftrace
- * function's orc entrie, as the placement of the return code in
+ * function's orc entry, as the placement of the return code in
  * the stack will be identical.
  */
 static struct orc_entry *orc_ftrace_find(unsigned long ip)
@@ -128,6 +128,16 @@ static struct orc_entry null_orc_entry = {
        .type = ORC_TYPE_CALL
 };
 
+/* Fake frame pointer entry -- used as a fallback for generated code */
+static struct orc_entry orc_fp_entry = {
+       .type           = ORC_TYPE_CALL,
+       .sp_reg         = ORC_REG_BP,
+       .sp_offset      = 16,
+       .bp_reg         = ORC_REG_PREV_SP,
+       .bp_offset      = -16,
+       .end            = 0,
+};
+
 static struct orc_entry *orc_find(unsigned long ip)
 {
        static struct orc_entry *orc;
@@ -392,8 +402,16 @@ bool unwind_next_frame(struct unwind_state *state)
         * calls and calls to noreturn functions.
         */
        orc = orc_find(state->signal ? state->ip : state->ip - 1);
-       if (!orc)
-               goto err;
+       if (!orc) {
+               /*
+                * As a fallback, try to assume this code uses a frame pointer.
+                * This is useful for generated code, like BPF, which ORC
+                * doesn't know about.  This is just a guess, so the rest of
+                * the unwind is no longer considered reliable.
+                */
+               orc = &orc_fp_entry;
+               state->error = true;
+       }
 
        /* End-of-stack check for kernel threads: */
        if (orc->sp_reg == ORC_REG_UNDEFINED) {
This page took 0.058544 seconds and 4 git commands to generate.