Skip to content

Commit f25170a

Browse files
Merge patch series "riscv: stacktrace: Add USER_STACKTRACE support"
Jinjie Ruan <[email protected]> says: Add RISC-V USER_STACKTRACE support, and fix the fp alignment bug in perf_callchain_user() by the way as Björn pointed out. * b4-shazam-merge: riscv: stacktrace: Add USER_STACKTRACE support riscv: Fix fp alignment bug in perf_callchain_user() Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Palmer Dabbelt <[email protected]>
2 parents 5c17847 + 1a74833 commit f25170a

File tree

3 files changed

+47
-43
lines changed

3 files changed

+47
-43
lines changed

arch/riscv/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ config RISCV
201201
select THREAD_INFO_IN_TASK
202202
select TRACE_IRQFLAGS_SUPPORT
203203
select UACCESS_MEMCPY if !MMU
204+
select USER_STACKTRACE_SUPPORT
204205
select ZONE_DMA32 if 64BIT
205206

206207
config CLANG_SUPPORTS_DYNAMIC_FTRACE

arch/riscv/kernel/perf_callchain.c

Lines changed: 3 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -6,37 +6,9 @@
66

77
#include <asm/stacktrace.h>
88

9-
/*
10-
* Get the return address for a single stackframe and return a pointer to the
11-
* next frame tail.
12-
*/
13-
static unsigned long user_backtrace(struct perf_callchain_entry_ctx *entry,
14-
unsigned long fp, unsigned long reg_ra)
9+
static bool fill_callchain(void *entry, unsigned long pc)
1510
{
16-
struct stackframe buftail;
17-
unsigned long ra = 0;
18-
unsigned long __user *user_frame_tail =
19-
(unsigned long __user *)(fp - sizeof(struct stackframe));
20-
21-
/* Check accessibility of one struct frame_tail beyond */
22-
if (!access_ok(user_frame_tail, sizeof(buftail)))
23-
return 0;
24-
if (__copy_from_user_inatomic(&buftail, user_frame_tail,
25-
sizeof(buftail)))
26-
return 0;
27-
28-
if (reg_ra != 0)
29-
ra = reg_ra;
30-
else
31-
ra = buftail.ra;
32-
33-
fp = buftail.fp;
34-
if (ra != 0)
35-
perf_callchain_store(entry, ra);
36-
else
37-
return 0;
38-
39-
return fp;
11+
return perf_callchain_store(entry, pc) == 0;
4012
}
4113

4214
/*
@@ -56,19 +28,7 @@ static unsigned long user_backtrace(struct perf_callchain_entry_ctx *entry,
5628
void perf_callchain_user(struct perf_callchain_entry_ctx *entry,
5729
struct pt_regs *regs)
5830
{
59-
unsigned long fp = 0;
60-
61-
fp = regs->s0;
62-
perf_callchain_store(entry, regs->epc);
63-
64-
fp = user_backtrace(entry, fp, regs->ra);
65-
while (fp && !(fp & 0x3) && entry->nr < entry->max_stack)
66-
fp = user_backtrace(entry, fp, 0);
67-
}
68-
69-
static bool fill_callchain(void *entry, unsigned long pc)
70-
{
71-
return perf_callchain_store(entry, pc) == 0;
31+
arch_stack_walk_user(fill_callchain, entry, regs);
7232
}
7333

7434
void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry,

arch/riscv/kernel/stacktrace.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,3 +162,46 @@ noinline noinstr void arch_stack_walk(stack_trace_consume_fn consume_entry, void
162162
{
163163
walk_stackframe(task, regs, consume_entry, cookie);
164164
}
165+
166+
/*
167+
* Get the return address for a single stackframe and return a pointer to the
168+
* next frame tail.
169+
*/
170+
static unsigned long unwind_user_frame(stack_trace_consume_fn consume_entry,
171+
void *cookie, unsigned long fp,
172+
unsigned long reg_ra)
173+
{
174+
struct stackframe buftail;
175+
unsigned long ra = 0;
176+
unsigned long __user *user_frame_tail =
177+
(unsigned long __user *)(fp - sizeof(struct stackframe));
178+
179+
/* Check accessibility of one struct frame_tail beyond */
180+
if (!access_ok(user_frame_tail, sizeof(buftail)))
181+
return 0;
182+
if (__copy_from_user_inatomic(&buftail, user_frame_tail,
183+
sizeof(buftail)))
184+
return 0;
185+
186+
ra = reg_ra ? : buftail.ra;
187+
188+
fp = buftail.fp;
189+
if (!ra || !consume_entry(cookie, ra))
190+
return 0;
191+
192+
return fp;
193+
}
194+
195+
void arch_stack_walk_user(stack_trace_consume_fn consume_entry, void *cookie,
196+
const struct pt_regs *regs)
197+
{
198+
unsigned long fp = 0;
199+
200+
fp = regs->s0;
201+
if (!consume_entry(cookie, regs->epc))
202+
return;
203+
204+
fp = unwind_user_frame(consume_entry, cookie, fp, regs->ra);
205+
while (fp && !(fp & 0x7))
206+
fp = unwind_user_frame(consume_entry, cookie, fp, 0);
207+
}

0 commit comments

Comments
 (0)