]>
git.ipfire.org Git - people/arne_f/kernel.git/blob - arch/metag/kernel/perf_callchain.c
1 // SPDX-License-Identifier: GPL-2.0
3 * Perf callchain handling code.
5 * Based on the ARM perf implementation.
8 #include <linux/kernel.h>
9 #include <linux/sched.h>
10 #include <linux/perf_event.h>
11 #include <linux/uaccess.h>
12 #include <asm/ptrace.h>
13 #include <asm/stacktrace.h>
15 static bool is_valid_call(unsigned long calladdr
)
17 unsigned int callinsn
;
19 /* Check the possible return address is aligned. */
20 if (!(calladdr
& 0x3)) {
21 if (!get_user(callinsn
, (unsigned int *)calladdr
)) {
22 /* Check for CALLR or SWAP PC,D1RtP. */
23 if ((callinsn
& 0xff000000) == 0xab000000 ||
24 callinsn
== 0xa3200aa0)
31 static struct metag_frame __user
*
32 user_backtrace(struct metag_frame __user
*user_frame
,
33 struct perf_callchain_entry_ctx
*entry
)
35 struct metag_frame frame
;
36 unsigned long calladdr
;
38 /* We cannot rely on having frame pointers in user code. */
40 /* Also check accessibility of one struct frame beyond */
41 if (!access_ok(VERIFY_READ
, user_frame
, sizeof(frame
)))
43 if (__copy_from_user_inatomic(&frame
, user_frame
,
49 calladdr
= frame
.lr
- 4;
50 if (is_valid_call(calladdr
)) {
51 perf_callchain_store(entry
, calladdr
);
60 perf_callchain_user(struct perf_callchain_entry_ctx
*entry
, struct pt_regs
*regs
)
62 unsigned long sp
= regs
->ctx
.AX
[0].U0
;
63 struct metag_frame __user
*frame
;
65 frame
= (struct metag_frame __user
*)sp
;
69 while ((entry
->nr
< entry
->max_stack
) && frame
)
70 frame
= user_backtrace(frame
, entry
);
74 * Gets called by walk_stackframe() for every stackframe. This will be called
75 * whist unwinding the stackframe and is like a subroutine return so we use
79 callchain_trace(struct stackframe
*fr
,
82 struct perf_callchain_entry_ctx
*entry
= data
;
83 perf_callchain_store(entry
, fr
->pc
);
88 perf_callchain_kernel(struct perf_callchain_entry_ctx
*entry
, struct pt_regs
*regs
)
92 fr
.fp
= regs
->ctx
.AX
[1].U0
;
93 fr
.sp
= regs
->ctx
.AX
[0].U0
;
94 fr
.lr
= regs
->ctx
.DX
[4].U1
;
95 fr
.pc
= regs
->ctx
.CurrPC
;
96 walk_stackframe(&fr
, callchain_trace
, entry
);