Skip to content

Commit 8094df1

Browse files
mrutland-armctmarinas
authored andcommitted
arm64: stacktrace: report recovered PCs
When analysing a stacktrace it can be useful to know whether an unwound PC has been rewritten by fgraph or kretprobes, as in some situations these may be suspect or be known to be unreliable. This patch adds flags to track when an unwind entry has recovered the PC from fgraph and/or kretprobes, and updates dump_backtrace() to log when this is the case. The flags recorded are: "F" - the PC was recovered from fgraph "K" - the PC was recovered from kretprobes These flags are recorded and logged in addition to the original source of the unwound PC. For example, with the ftrace_graph profiler enabled globally, and kretprobes installed on generic_handle_domain_irq() and do_interrupt_handler(), a backtrace triggered by magic-sysrq + L reports: | Call trace: | show_stack+0x20/0x40 (CF) | dump_stack_lvl+0x60/0x80 (F) | dump_stack+0x18/0x28 | nmi_cpu_backtrace+0xfc/0x140 | nmi_trigger_cpumask_backtrace+0x1c8/0x200 | arch_trigger_cpumask_backtrace+0x20/0x40 | sysrq_handle_showallcpus+0x24/0x38 (F) | __handle_sysrq+0xa8/0x1b0 (F) | handle_sysrq+0x38/0x50 (F) | pl011_int+0x460/0x5a8 (F) | __handle_irq_event_percpu+0x60/0x220 (F) | handle_irq_event+0x54/0xc0 (F) | handle_fasteoi_irq+0xa8/0x1d0 (F) | generic_handle_domain_irq+0x34/0x58 (F) | gic_handle_irq+0x54/0x140 (FK) | call_on_irq_stack+0x24/0x58 (F) | do_interrupt_handler+0x88/0xa0 | el1_interrupt+0x34/0x68 (FK) | el1h_64_irq_handler+0x18/0x28 | el1h_64_irq+0x64/0x68 | default_idle_call+0x34/0x180 | do_idle+0x204/0x268 | cpu_startup_entry+0x40/0x50 (F) | rest_init+0xe4/0xf0 | start_kernel+0x744/0x750 | __primary_switched+0x80/0x90 Note that as these flags are reported next to the recovered PC value, they appear on the callers of instrumented functions. For example gic_handle_irq() has a "K" marker because generic_handle_domain_irq() was instrumented with kretprobes and had its return address rewritten. Signed-off-by: Mark Rutland <mark.rutland@arm.com> Reviewed-by: Mark Brown <broonie@kernel.org> Reviewed-by: Miroslav Benes <mbenes@suse.cz> Reviewed-by: Puranjay Mohan <puranjay12@gmail.com> Cc: Ard Biesheuvel <ardb@kernel.org> Cc: Josh Poimboeuf <jpoimboe@kernel.org> Cc: Kalesh Singh <kaleshsingh@google.com> Cc: Madhavan T. Venkataraman <madvenka@linux.microsoft.com> Cc: Marc Zyngier <maz@kernel.org> Cc: Will Deacon <will@kernel.org> Link: https://lore.kernel.org/r/20241017092538.1859841-9-mark.rutland@arm.com Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
1 parent bdf8eaf commit 8094df1

File tree

1 file changed

+23
-3
lines changed

1 file changed

+23
-3
lines changed

arch/arm64/kernel/stacktrace.c

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,14 @@ enum kunwind_source {
2828
KUNWIND_SOURCE_REGS_PC,
2929
};
3030

31+
union unwind_flags {
32+
unsigned long all;
33+
struct {
34+
unsigned long fgraph : 1,
35+
kretprobe : 1;
36+
};
37+
};
38+
3139
/*
3240
* Kernel unwind state
3341
*
@@ -46,6 +54,7 @@ struct kunwind_state {
4654
struct llist_node *kr_cur;
4755
#endif
4856
enum kunwind_source source;
57+
union unwind_flags flags;
4958
};
5059

5160
static __always_inline void
@@ -55,6 +64,7 @@ kunwind_init(struct kunwind_state *state,
5564
unwind_init_common(&state->common);
5665
state->task = task;
5766
state->source = KUNWIND_SOURCE_UNKNOWN;
67+
state->flags.all = 0;
5868
}
5969

6070
/*
@@ -127,6 +137,7 @@ kunwind_recover_return_address(struct kunwind_state *state)
127137
if (WARN_ON_ONCE(state->common.pc == orig_pc))
128138
return -EINVAL;
129139
state->common.pc = orig_pc;
140+
state->flags.fgraph = 1;
130141
}
131142
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
132143

@@ -137,6 +148,7 @@ kunwind_recover_return_address(struct kunwind_state *state)
137148
(void *)state->common.fp,
138149
&state->kr_cur);
139150
state->common.pc = orig_pc;
151+
state->flags.kretprobe = 1;
140152
}
141153
#endif /* CONFIG_KRETPROBES */
142154

@@ -157,6 +169,8 @@ kunwind_next(struct kunwind_state *state)
157169
unsigned long fp = state->common.fp;
158170
int err;
159171

172+
state->flags.all = 0;
173+
160174
/* Final frame; nothing to unwind */
161175
if (fp == (unsigned long)&task_pt_regs(tsk)->stackframe)
162176
return -ENOENT;
@@ -331,12 +345,18 @@ static const char *state_source_string(const struct kunwind_state *state)
331345
static bool dump_backtrace_entry(const struct kunwind_state *state, void *arg)
332346
{
333347
const char *source = state_source_string(state);
348+
union unwind_flags flags = state->flags;
349+
bool has_info = source || flags.all;
334350
char *loglvl = arg;
335-
printk("%s %pSb%s%s%s\n", loglvl,
351+
352+
printk("%s %pSb%s%s%s%s%s\n", loglvl,
336353
(void *)state->common.pc,
337-
source ? " (" : "",
354+
has_info ? " (" : "",
338355
source ? source : "",
339-
source ? ")" : "");
356+
flags.fgraph ? "F" : "",
357+
flags.kretprobe ? "K" : "",
358+
has_info ? ")" : "");
359+
340360
return true;
341361
}
342362

0 commit comments

Comments
 (0)