0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include <linux/perf_event.h>
0015 #include <linux/sched/task_stack.h>
0016
0017 #include <asm/stacktrace.h>
0018
0019
0020
0021
0022
0023
0024
0025
0026 static void save_raw_perf_callchain(struct perf_callchain_entry_ctx *entry,
0027 unsigned long reg29)
0028 {
0029 unsigned long *sp = (unsigned long *)reg29;
0030 unsigned long addr;
0031
0032 while (!kstack_end(sp)) {
0033 addr = *sp++;
0034 if (__kernel_text_address(addr)) {
0035 perf_callchain_store(entry, addr);
0036 if (entry->nr >= entry->max_stack)
0037 break;
0038 }
0039 }
0040 }
0041
0042 void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry,
0043 struct pt_regs *regs)
0044 {
0045 unsigned long sp = regs->regs[29];
0046 #ifdef CONFIG_KALLSYMS
0047 unsigned long ra = regs->regs[31];
0048 unsigned long pc = regs->cp0_epc;
0049
0050 if (raw_show_trace || !__kernel_text_address(pc)) {
0051 unsigned long stack_page =
0052 (unsigned long)task_stack_page(current);
0053 if (stack_page && sp >= stack_page &&
0054 sp <= stack_page + THREAD_SIZE - 32)
0055 save_raw_perf_callchain(entry, sp);
0056 return;
0057 }
0058 do {
0059 perf_callchain_store(entry, pc);
0060 if (entry->nr >= entry->max_stack)
0061 break;
0062 pc = unwind_stack(current, &sp, pc, &ra);
0063 } while (pc);
0064 #else
0065 save_raw_perf_callchain(entry, sp);
0066 #endif
0067 }