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, struct pt_regs *regs) 36 { 37 unsigned long sp = regs->regs[29]; 38 #ifdef CONFIG_KALLSYMS 39 unsigned long ra = regs->regs[31]; 40 unsigned long pc = regs->cp0_epc; 41 42 if (raw_show_trace || !__kernel_text_address(pc)) { 43 unsigned long stack_page = 44 (unsigned long)task_stack_page(current); 45 if (stack_page && sp >= stack_page && 46 sp <= stack_page + THREAD_SIZE - 32) 47 save_raw_context_stack(trace, sp); 48 return; 49 } 50 do { 51 if (trace->skip > 0) 52 trace->skip--; 53 else 54 trace->entries[trace->nr_entries++] = pc; 55 if (trace->nr_entries >= trace->max_entries) 56 break; 57 pc = unwind_stack(current, &sp, pc, &ra); 58 } while (pc); 59 #else 60 save_raw_context_stack(trace, sp); 61 #endif 62 } 63 64 /* 65 * Save stack-backtrace addresses into a stack_trace buffer. 66 */ 67 void save_stack_trace(struct stack_trace *trace) 68 { 69 struct pt_regs dummyregs; 70 struct pt_regs *regs = &dummyregs; 71 72 WARN_ON(trace->nr_entries || !trace->max_entries); 73 74 prepare_frametrace(regs); 75 save_context_stack(trace, regs); 76 } 77 EXPORT_SYMBOL_GPL(save_stack_trace); 78