Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v5.3 87 lines 2.0 kB view raw
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * SH specific backtracing code for oprofile 4 * 5 * Copyright 2007 STMicroelectronics Ltd. 6 * 7 * Author: Dave Peverley <dpeverley@mpc-data.co.uk> 8 * 9 * Based on ARM oprofile backtrace code by Richard Purdie and in turn, i386 10 * oprofile backtrace code by John Levon, David Smith 11 */ 12#include <linux/oprofile.h> 13#include <linux/sched.h> 14#include <linux/kallsyms.h> 15#include <linux/mm.h> 16#include <asm/unwinder.h> 17#include <asm/ptrace.h> 18#include <linux/uaccess.h> 19#include <asm/sections.h> 20#include <asm/stacktrace.h> 21 22static int backtrace_stack(void *data, char *name) 23{ 24 /* Yes, we want all stacks */ 25 return 0; 26} 27 28static void backtrace_address(void *data, unsigned long addr, int reliable) 29{ 30 unsigned int *depth = data; 31 32 if ((*depth)--) 33 oprofile_add_trace(addr); 34} 35 36static struct stacktrace_ops backtrace_ops = { 37 .stack = backtrace_stack, 38 .address = backtrace_address, 39}; 40 41/* Limit to stop backtracing too far. */ 42static int backtrace_limit = 20; 43 44static unsigned long * 45user_backtrace(unsigned long *stackaddr, struct pt_regs *regs) 46{ 47 unsigned long buf_stack; 48 49 /* Also check accessibility of address */ 50 if (!access_ok(stackaddr, sizeof(unsigned long))) 51 return NULL; 52 53 if (__copy_from_user_inatomic(&buf_stack, stackaddr, sizeof(unsigned long))) 54 return NULL; 55 56 /* Quick paranoia check */ 57 if (buf_stack & 3) 58 return NULL; 59 60 oprofile_add_trace(buf_stack); 61 62 stackaddr++; 63 64 return stackaddr; 65} 66 67void sh_backtrace(struct pt_regs * const regs, unsigned int depth) 68{ 69 unsigned long *stackaddr; 70 71 /* 72 * Paranoia - clip max depth as we could get lost in the weeds. 73 */ 74 if (depth > backtrace_limit) 75 depth = backtrace_limit; 76 77 stackaddr = (unsigned long *)kernel_stack_pointer(regs); 78 if (!user_mode(regs)) { 79 if (depth) 80 unwind_stack(NULL, regs, stackaddr, 81 &backtrace_ops, &depth); 82 return; 83 } 84 85 while (depth-- && (stackaddr != NULL)) 86 stackaddr = user_backtrace(stackaddr, regs); 87}