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