2 * Perf callchain handling code.
4 * Based on the ARM perf implementation.
7 #include <linux/kernel.h>
8 #include <linux/sched.h>
9 #include <linux/perf_event.h>
10 #include <linux/uaccess.h>
11 #include <asm/ptrace.h>
12 #include <asm/stacktrace.h>
14 static bool is_valid_call(unsigned long calladdr
)
16 unsigned int callinsn
;
18 /* Check the possible return address is aligned. */
19 if (!(calladdr
& 0x3)) {
20 if (!get_user(callinsn
, (unsigned int *)calladdr
)) {
21 /* Check for CALLR or SWAP PC,D1RtP. */
22 if ((callinsn
& 0xff000000) == 0xab000000 ||
23 callinsn
== 0xa3200aa0)
30 static struct metag_frame __user
*
31 user_backtrace(struct metag_frame __user
*user_frame
,
32 struct perf_callchain_entry
*entry
)
34 struct metag_frame frame
;
35 unsigned long calladdr
;
37 /* We cannot rely on having frame pointers in user code. */
39 /* Also check accessibility of one struct frame beyond */
40 if (!access_ok(VERIFY_READ
, user_frame
, sizeof(frame
)))
42 if (__copy_from_user_inatomic(&frame
, user_frame
,
48 calladdr
= frame
.lr
- 4;
49 if (is_valid_call(calladdr
)) {
50 perf_callchain_store(entry
, calladdr
);
59 perf_callchain_user(struct perf_callchain_entry
*entry
, struct pt_regs
*regs
)
61 unsigned long sp
= regs
->ctx
.AX
[0].U0
;
62 struct metag_frame __user
*frame
;
64 frame
= (struct metag_frame __user
*)sp
;
68 while ((entry
->nr
< sysctl_perf_event_max_stack
) && frame
)
69 frame
= user_backtrace(frame
, entry
);
73 * Gets called by walk_stackframe() for every stackframe. This will be called
74 * whist unwinding the stackframe and is like a subroutine return so we use
78 callchain_trace(struct stackframe
*fr
,
81 struct perf_callchain_entry
*entry
= data
;
82 perf_callchain_store(entry
, fr
->pc
);
87 perf_callchain_kernel(struct perf_callchain_entry
*entry
, struct pt_regs
*regs
)
91 fr
.fp
= regs
->ctx
.AX
[1].U0
;
92 fr
.sp
= regs
->ctx
.AX
[0].U0
;
93 fr
.lr
= regs
->ctx
.DX
[4].U1
;
94 fr
.pc
= regs
->ctx
.CurrPC
;
95 walk_stackframe(&fr
, callchain_trace
, entry
);