]> Git Repo - linux.git/blob - arch/sh/oprofile/backtrace.c
enetc: Migrate to PHYLINK and PCS_LYNX
[linux.git] / arch / sh / oprofile / backtrace.c
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 <[email protected]>
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
22 static void backtrace_address(void *data, unsigned long addr, int reliable)
23 {
24         unsigned int *depth = data;
25
26         if ((*depth)--)
27                 oprofile_add_trace(addr);
28 }
29
30 static struct stacktrace_ops backtrace_ops = {
31         .address = backtrace_address,
32 };
33
34 /* Limit to stop backtracing too far. */
35 static int backtrace_limit = 20;
36
37 static unsigned long *
38 user_backtrace(unsigned long *stackaddr, struct pt_regs *regs)
39 {
40         unsigned long buf_stack;
41
42         /* Also check accessibility of address */
43         if (!access_ok(stackaddr, sizeof(unsigned long)))
44                 return NULL;
45
46         if (__copy_from_user_inatomic(&buf_stack, stackaddr, sizeof(unsigned long)))
47                 return NULL;
48
49         /* Quick paranoia check */
50         if (buf_stack & 3)
51                 return NULL;
52
53         oprofile_add_trace(buf_stack);
54
55         stackaddr++;
56
57         return stackaddr;
58 }
59
60 void sh_backtrace(struct pt_regs * const regs, unsigned int depth)
61 {
62         unsigned long *stackaddr;
63
64         /*
65          * Paranoia - clip max depth as we could get lost in the weeds.
66          */
67         if (depth > backtrace_limit)
68                 depth = backtrace_limit;
69
70         stackaddr = (unsigned long *)kernel_stack_pointer(regs);
71         if (!user_mode(regs)) {
72                 if (depth)
73                         unwind_stack(NULL, regs, stackaddr,
74                                      &backtrace_ops, &depth);
75                 return;
76         }
77
78         while (depth-- && (stackaddr != NULL))
79                 stackaddr = user_backtrace(stackaddr, regs);
80 }
This page took 0.035641 seconds and 4 git commands to generate.