Commit ae6a45a0 authored by Josh Poimboeuf's avatar Josh Poimboeuf Committed by Thomas Gleixner

x86/unwind/orc: Fall back to using frame pointers for generated code

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: d15d3568 ("perf/x86: Make perf callchains work without CONFIG_FRAME_POINTER")
Reported-by: default avatarSong Liu <songliubraving@fb.com>
Signed-off-by: default avatarJosh Poimboeuf <jpoimboe@redhat.com>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Acked-by: default avatarPeter 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
parent 83f44ae0
...@@ -82,9 +82,9 @@ static struct orc_entry *orc_find(unsigned long ip); ...@@ -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 * But they are copies of the ftrace entries that are static and
* defined in ftrace_*.S, which do have orc entries. * 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 * 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. * the stack will be identical.
*/ */
static struct orc_entry *orc_ftrace_find(unsigned long ip) static struct orc_entry *orc_ftrace_find(unsigned long ip)
...@@ -128,6 +128,16 @@ static struct orc_entry null_orc_entry = { ...@@ -128,6 +128,16 @@ static struct orc_entry null_orc_entry = {
.type = ORC_TYPE_CALL .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_find(unsigned long ip)
{ {
static struct orc_entry *orc; static struct orc_entry *orc;
...@@ -392,8 +402,16 @@ bool unwind_next_frame(struct unwind_state *state) ...@@ -392,8 +402,16 @@ bool unwind_next_frame(struct unwind_state *state)
* calls and calls to noreturn functions. * calls and calls to noreturn functions.
*/ */
orc = orc_find(state->signal ? state->ip : state->ip - 1); orc = orc_find(state->signal ? state->ip : state->ip - 1);
if (!orc) if (!orc) {
goto err; /*
* 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: */ /* End-of-stack check for kernel threads: */
if (orc->sp_reg == ORC_REG_UNDEFINED) { if (orc->sp_reg == ORC_REG_UNDEFINED) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment