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