GNU Linux-libre 4.19.245-gnu1
[releases.git] / arch / openrisc / kernel / stacktrace.c
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);