0001
0002
0003
0004
0005
0006
0007 #include <linux/perf_event.h>
0008 #include <linux/stacktrace.h>
0009 #include <linux/uaccess.h>
0010
0011 #include <asm/pointer_auth.h>
0012
0013 struct frame_tail {
0014 struct frame_tail __user *fp;
0015 unsigned long lr;
0016 } __attribute__((packed));
0017
0018
0019
0020
0021
0022 static struct frame_tail __user *
0023 user_backtrace(struct frame_tail __user *tail,
0024 struct perf_callchain_entry_ctx *entry)
0025 {
0026 struct frame_tail buftail;
0027 unsigned long err;
0028 unsigned long lr;
0029
0030
0031 if (!access_ok(tail, sizeof(buftail)))
0032 return NULL;
0033
0034 pagefault_disable();
0035 err = __copy_from_user_inatomic(&buftail, tail, sizeof(buftail));
0036 pagefault_enable();
0037
0038 if (err)
0039 return NULL;
0040
0041 lr = ptrauth_strip_insn_pac(buftail.lr);
0042
0043 perf_callchain_store(entry, lr);
0044
0045
0046
0047
0048
0049 if (tail >= buftail.fp)
0050 return NULL;
0051
0052 return buftail.fp;
0053 }
0054
0055 #ifdef CONFIG_COMPAT
0056
0057
0058
0059
0060
0061
0062
0063
0064 struct compat_frame_tail {
0065 compat_uptr_t fp;
0066 u32 sp;
0067 u32 lr;
0068 } __attribute__((packed));
0069
0070 static struct compat_frame_tail __user *
0071 compat_user_backtrace(struct compat_frame_tail __user *tail,
0072 struct perf_callchain_entry_ctx *entry)
0073 {
0074 struct compat_frame_tail buftail;
0075 unsigned long err;
0076
0077
0078 if (!access_ok(tail, sizeof(buftail)))
0079 return NULL;
0080
0081 pagefault_disable();
0082 err = __copy_from_user_inatomic(&buftail, tail, sizeof(buftail));
0083 pagefault_enable();
0084
0085 if (err)
0086 return NULL;
0087
0088 perf_callchain_store(entry, buftail.lr);
0089
0090
0091
0092
0093
0094 if (tail + 1 >= (struct compat_frame_tail __user *)
0095 compat_ptr(buftail.fp))
0096 return NULL;
0097
0098 return (struct compat_frame_tail __user *)compat_ptr(buftail.fp) - 1;
0099 }
0100 #endif
0101
0102 void perf_callchain_user(struct perf_callchain_entry_ctx *entry,
0103 struct pt_regs *regs)
0104 {
0105 if (perf_guest_state()) {
0106
0107 return;
0108 }
0109
0110 perf_callchain_store(entry, regs->pc);
0111
0112 if (!compat_user_mode(regs)) {
0113
0114 struct frame_tail __user *tail;
0115
0116 tail = (struct frame_tail __user *)regs->regs[29];
0117
0118 while (entry->nr < entry->max_stack &&
0119 tail && !((unsigned long)tail & 0x7))
0120 tail = user_backtrace(tail, entry);
0121 } else {
0122 #ifdef CONFIG_COMPAT
0123
0124 struct compat_frame_tail __user *tail;
0125
0126 tail = (struct compat_frame_tail __user *)regs->compat_fp - 1;
0127
0128 while ((entry->nr < entry->max_stack) &&
0129 tail && !((unsigned long)tail & 0x3))
0130 tail = compat_user_backtrace(tail, entry);
0131 #endif
0132 }
0133 }
0134
0135 static bool callchain_trace(void *data, unsigned long pc)
0136 {
0137 struct perf_callchain_entry_ctx *entry = data;
0138 return perf_callchain_store(entry, pc) == 0;
0139 }
0140
0141 void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry,
0142 struct pt_regs *regs)
0143 {
0144 if (perf_guest_state()) {
0145
0146 return;
0147 }
0148
0149 arch_stack_walk(callchain_trace, entry, current, regs);
0150 }
0151
0152 unsigned long perf_instruction_pointer(struct pt_regs *regs)
0153 {
0154 if (perf_guest_state())
0155 return perf_guest_get_ip();
0156
0157 return instruction_pointer(regs);
0158 }
0159
0160 unsigned long perf_misc_flags(struct pt_regs *regs)
0161 {
0162 unsigned int guest_state = perf_guest_state();
0163 int misc = 0;
0164
0165 if (guest_state) {
0166 if (guest_state & PERF_GUEST_USER)
0167 misc |= PERF_RECORD_MISC_GUEST_USER;
0168 else
0169 misc |= PERF_RECORD_MISC_GUEST_KERNEL;
0170 } else {
0171 if (user_mode(regs))
0172 misc |= PERF_RECORD_MISC_USER;
0173 else
0174 misc |= PERF_RECORD_MISC_KERNEL;
0175 }
0176
0177 return misc;
0178 }