stacktrace.c (2175B)
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 */ 25static void 26save_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 42void save_stack_trace(struct stack_trace *trace) 43{ 44 unwind_stack(trace, (unsigned long *) &trace, save_stack_address); 45} 46EXPORT_SYMBOL_GPL(save_stack_trace); 47 48static void 49save_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 68void 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} 92EXPORT_SYMBOL_GPL(save_stack_trace_tsk); 93 94void 95save_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} 100EXPORT_SYMBOL_GPL(save_stack_trace_regs);