Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Linux performance counter support for MIPS.
0004  *
0005  * Copyright (C) 2010 MIPS Technologies, Inc.
0006  * Author: Deng-Cheng Zhu
0007  *
0008  * This code is based on the implementation for ARM, which is in turn
0009  * based on the sparc64 perf event code and the x86 code. Performance
0010  * counter access is based on the MIPS Oprofile code. And the callchain
0011  * support references the code of MIPS stacktrace.c.
0012  */
0013 
0014 #include <linux/perf_event.h>
0015 #include <linux/sched/task_stack.h>
0016 
0017 #include <asm/stacktrace.h>
0018 
0019 /* Callchain handling code. */
0020 
0021 /*
0022  * Leave userspace callchain empty for now. When we find a way to trace
0023  * the user stack callchains, we will add it here.
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 }