^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * ARM callchain support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2009 picoChip Designs, Ltd., Jamie Iles
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2010 ARM Ltd., Will Deacon <will.deacon@arm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * This code is based on the ARM OProfile backtrace code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/perf_event.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <asm/stacktrace.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * The registers we're interested in are at the end of the variable
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * length saved register structure. The fp points at the end of this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * structure so the address of this struct is:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * (struct frame_tail *)(xxx->fp)-1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * This code has been adapted from the ARM OProfile support.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) struct frame_tail {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) struct frame_tail __user *fp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) unsigned long sp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) unsigned long lr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) } __attribute__((packed));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * Get the return address for a single stackframe and return a pointer to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * next frame tail.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) static struct frame_tail __user *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) user_backtrace(struct frame_tail __user *tail,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) struct perf_callchain_entry_ctx *entry)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) struct frame_tail buftail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) unsigned long err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) if (!access_ok(tail, sizeof(buftail)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) pagefault_disable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) err = __copy_from_user_inatomic(&buftail, tail, sizeof(buftail));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) pagefault_enable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) perf_callchain_store(entry, buftail.lr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) * Frame pointers should strictly progress back up the stack
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * (towards higher addresses).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) if (tail + 1 >= buftail.fp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) return buftail.fp - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) struct frame_tail __user *tail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) if (guest_cbs && guest_cbs->is_in_guest()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) /* We don't support guest os callchain now */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) perf_callchain_store(entry, regs->ARM_pc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) if (!current->mm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) tail = (struct frame_tail __user *)regs->ARM_fp - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) while ((entry->nr < entry->max_stack) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) tail && !((unsigned long)tail & 0x3))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) tail = user_backtrace(tail, entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) * Gets called by walk_stackframe() for every stackframe. This will be called
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) * whist unwinding the stackframe and is like a subroutine return so we use
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) * the PC.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) callchain_trace(struct stackframe *fr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) struct perf_callchain_entry_ctx *entry = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) perf_callchain_store(entry, fr->pc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) struct stackframe fr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) if (guest_cbs && guest_cbs->is_in_guest()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) /* We don't support guest os callchain now */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) arm_get_current_stackframe(regs, &fr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) walk_stackframe(&fr, callchain_trace, entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) unsigned long perf_instruction_pointer(struct pt_regs *regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) if (guest_cbs && guest_cbs->is_in_guest())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) return guest_cbs->get_guest_ip();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) return instruction_pointer(regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) unsigned long perf_misc_flags(struct pt_regs *regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) int misc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) if (guest_cbs && guest_cbs->is_in_guest()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) if (guest_cbs->is_user_mode())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) misc |= PERF_RECORD_MISC_GUEST_USER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) misc |= PERF_RECORD_MISC_GUEST_KERNEL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) if (user_mode(regs))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) misc |= PERF_RECORD_MISC_USER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) misc |= PERF_RECORD_MISC_KERNEL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) return misc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) }