1 /* 2 * arch/mips/kernel/stacktrace.c 3 * 4 * Stack trace management functions 5 * 6 * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp> 7 */ 8 #include <linux/sched.h> 9 #include <linux/stacktrace.h> 10 #include <linux/module.h> 11 #include <asm/stacktrace.h> 12 13 /* 14 * Save stack-backtrace addresses into a stack_trace buffer: 15 */ 16 static void save_raw_context_stack(struct stack_trace *trace, 17 unsigned long reg29) 18 { 19 unsigned long *sp = (unsigned long *)reg29; 20 unsigned long addr; 21 22 while (!kstack_end(sp)) { 23 addr = *sp++; 24 if (__kernel_text_address(addr)) { 25 if (trace->skip > 0) 26 trace->skip--; 27 else 28 trace->entries[trace->nr_entries++] = addr; 29 if (trace->nr_entries >= trace->max_entries) 30 break; 31 } 32 } 33 } 34 35 static void save_context_stack(struct stack_trace *trace, 36 struct task_struct *tsk, struct pt_regs *regs) 37 { 38 unsigned long sp = regs->regs[29]; 39 #ifdef CONFIG_KALLSYMS 40 unsigned long ra = regs->regs[31]; 41 unsigned long pc = regs->cp0_epc; 42 43 if (raw_show_trace || !__kernel_text_address(pc)) { 44 unsigned long stack_page = 45 (unsigned long)task_stack_page(tsk); 46 if (stack_page && sp >= stack_page && 47 sp <= stack_page + THREAD_SIZE - 32) 48 save_raw_context_stack(trace, sp); 49 return; 50 } 51 do { 52 if (trace->skip > 0) 53 trace->skip--; 54 else 55 trace->entries[trace->nr_entries++] = pc; 56 if (trace->nr_entries >= trace->max_entries) 57 break; 58 pc = unwind_stack(tsk, &sp, pc, &ra); 59 } while (pc); 60 #else 61 save_raw_context_stack(trace, sp); 62 #endif 63 } 64 65 /* 66 * Save stack-backtrace addresses into a stack_trace buffer. 67 */ 68 void save_stack_trace(struct stack_trace *trace) 69 { 70 save_stack_trace_tsk(current, trace); 71 } 72 EXPORT_SYMBOL_GPL(save_stack_trace); 73 74 void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) 75 { 76 struct pt_regs dummyregs; 77 struct pt_regs *regs = &dummyregs; 78 79 WARN_ON(trace->nr_entries || !trace->max_entries); 80 81 if (tsk != current) { 82 regs->regs[29] = tsk->thread.reg29; 83 regs->regs[31] = 0; 84 regs->cp0_epc = tsk->thread.reg31; 85 } else 86 prepare_frametrace(regs); 87 save_context_stack(trace, tsk, regs); 88 } 89 EXPORT_SYMBOL_GPL(save_stack_trace_tsk); 90