1 | /* |
2 | * Stack trace utility for OpenRISC |
3 | * |
4 | * Copyright (C) 2017 Stafford Horne <shorne@gmail.com> |
5 | * |
6 | * This file is licensed under the terms of the GNU General Public License |
7 | * version 2. This program is licensed "as is" without any warranty of any |
8 | * kind, whether express or implied. |
9 | * |
10 | * Losely based on work from sh and powerpc. |
11 | */ |
12 | |
13 | #include <linux/export.h> |
14 | #include <linux/sched.h> |
15 | #include <linux/sched/debug.h> |
16 | #include <linux/sched/task_stack.h> |
17 | #include <linux/stacktrace.h> |
18 | |
19 | #include <asm/processor.h> |
20 | #include <asm/unwinder.h> |
21 | |
22 | /* |
23 | * Save stack-backtrace addresses into a stack_trace buffer. |
24 | */ |
25 | static void |
26 | save_stack_address(void *data, unsigned long addr, int reliable) |
27 | { |
28 | struct stack_trace *trace = data; |
29 | |
30 | if (!reliable) |
31 | return; |
32 | |
33 | if (trace->skip > 0) { |
34 | trace->skip--; |
35 | return; |
36 | } |
37 | |
38 | if (trace->nr_entries < trace->max_entries) |
39 | trace->entries[trace->nr_entries++] = addr; |
40 | } |
41 | |
42 | void save_stack_trace(struct stack_trace *trace) |
43 | { |
44 | unwind_stack(trace, (unsigned long *) &trace, save_stack_address); |
45 | } |
46 | EXPORT_SYMBOL_GPL(save_stack_trace); |
47 | |
48 | static void |
49 | save_stack_address_nosched(void *data, unsigned long addr, int reliable) |
50 | { |
51 | struct stack_trace *trace = (struct stack_trace *)data; |
52 | |
53 | if (!reliable) |
54 | return; |
55 | |
56 | if (in_sched_functions(addr)) |
57 | return; |
58 | |
59 | if (trace->skip > 0) { |
60 | trace->skip--; |
61 | return; |
62 | } |
63 | |
64 | if (trace->nr_entries < trace->max_entries) |
65 | trace->entries[trace->nr_entries++] = addr; |
66 | } |
67 | |
68 | void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) |
69 | { |
70 | unsigned long *sp = NULL; |
71 | |
72 | if (!try_get_task_stack(tsk)) |
73 | return; |
74 | |
75 | if (tsk == current) |
76 | sp = (unsigned long *) &sp; |
77 | else { |
78 | unsigned long ksp; |
79 | |
80 | /* Locate stack from kernel context */ |
81 | ksp = task_thread_info(tsk)->ksp; |
82 | ksp += STACK_FRAME_OVERHEAD; /* redzone */ |
83 | ksp += sizeof(struct pt_regs); |
84 | |
85 | sp = (unsigned long *) ksp; |
86 | } |
87 | |
88 | unwind_stack(trace, sp, save_stack_address_nosched); |
89 | |
90 | put_task_stack(tsk); |
91 | } |
92 | EXPORT_SYMBOL_GPL(save_stack_trace_tsk); |
93 | |
94 | void |
95 | save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace) |
96 | { |
97 | unwind_stack(trace, (unsigned long *) regs->sp, |
98 | save_stack_address_nosched); |
99 | } |
100 | EXPORT_SYMBOL_GPL(save_stack_trace_regs); |
101 | |