0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/perf_event.h>
0011 #include <linux/uaccess.h>
0012
0013 #include <asm/stacktrace.h>
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023 struct frame_tail {
0024 struct frame_tail __user *fp;
0025 unsigned long sp;
0026 unsigned long lr;
0027 } __attribute__((packed));
0028
0029
0030
0031
0032
0033 static struct frame_tail __user *
0034 user_backtrace(struct frame_tail __user *tail,
0035 struct perf_callchain_entry_ctx *entry)
0036 {
0037 struct frame_tail buftail;
0038 unsigned long err;
0039
0040 if (!access_ok(tail, sizeof(buftail)))
0041 return NULL;
0042
0043 pagefault_disable();
0044 err = __copy_from_user_inatomic(&buftail, tail, sizeof(buftail));
0045 pagefault_enable();
0046
0047 if (err)
0048 return NULL;
0049
0050 perf_callchain_store(entry, buftail.lr);
0051
0052
0053
0054
0055
0056 if (tail + 1 >= buftail.fp)
0057 return NULL;
0058
0059 return buftail.fp - 1;
0060 }
0061
0062 void
0063 perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs)
0064 {
0065 struct frame_tail __user *tail;
0066
0067 perf_callchain_store(entry, regs->ARM_pc);
0068
0069 if (!current->mm)
0070 return;
0071
0072 tail = (struct frame_tail __user *)regs->ARM_fp - 1;
0073
0074 while ((entry->nr < entry->max_stack) &&
0075 tail && !((unsigned long)tail & 0x3))
0076 tail = user_backtrace(tail, entry);
0077 }
0078
0079
0080
0081
0082
0083
0084 static int
0085 callchain_trace(struct stackframe *fr,
0086 void *data)
0087 {
0088 struct perf_callchain_entry_ctx *entry = data;
0089 perf_callchain_store(entry, fr->pc);
0090 return 0;
0091 }
0092
0093 void
0094 perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs)
0095 {
0096 struct stackframe fr;
0097
0098 arm_get_current_stackframe(regs, &fr);
0099 walk_stackframe(&fr, callchain_trace, entry);
0100 }
0101
0102 unsigned long perf_instruction_pointer(struct pt_regs *regs)
0103 {
0104 return instruction_pointer(regs);
0105 }
0106
0107 unsigned long perf_misc_flags(struct pt_regs *regs)
0108 {
0109 int misc = 0;
0110
0111 if (user_mode(regs))
0112 misc |= PERF_RECORD_MISC_USER;
0113 else
0114 misc |= PERF_RECORD_MISC_KERNEL;
0115
0116 return misc;
0117 }