]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
x86/unwind/orc: Fall back to using frame pointers for generated code
authorJosh Poimboeuf <jpoimboe@redhat.com>
Thu, 27 Jun 2019 00:33:55 +0000 (19:33 -0500)
committerThomas Gleixner <tglx@linutronix.de>
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 <songliubraving@fb.com>
Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Kairui Song <kasong@redhat.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Borislav Petkov <bp@alien8.de>
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) {