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/sched/debug.h> 8 #include <linux/sched/task_stack.h> 9 #include <linux/stacktrace.h> 10 #include <linux/export.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, int savesched) 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 (savesched || !in_sched_functions(addr))) { 26 if (trace->skip > 0) 27 trace->skip--; 28 else 29 trace->entries[trace->nr_entries++] = addr; 30 if (trace->nr_entries >= trace->max_entries) 31 break; 32 } 33 } 34 } 35 36 static void save_context_stack(struct stack_trace *trace, 37 struct task_struct *tsk, struct pt_regs *regs, int savesched) 38 { 39 unsigned long sp = regs->regs[29]; 40 #ifdef CONFIG_KALLSYMS 41 unsigned long ra = regs->regs[31]; 42 unsigned long pc = regs->cp0_epc; 43 44 if (raw_show_trace || !__kernel_text_address(pc)) { 45 unsigned long stack_page = 46 (unsigned long)task_stack_page(tsk); 47 if (stack_page && sp >= stack_page && 48 sp <= stack_page + THREAD_SIZE - 32) 49 save_raw_context_stack(trace, sp, savesched); 50 return; 51 } 52 do { 53 if (savesched || !in_sched_functions(pc)) { 54 if (trace->skip > 0) 55 trace->skip--; 56 else 57 trace->entries[trace->nr_entries++] = pc; 58 if (trace->nr_entries >= trace->max_entries) 59 break; 60 } 61 pc = unwind_stack(tsk, &sp, pc, &ra); 62 } while (pc); 63 #else 64 save_raw_context_stack(trace, sp, savesched); 65 #endif 66 } 67 68 /* 69 * Save stack-backtrace addresses into a stack_trace buffer. 70 */ 71 void save_stack_trace(struct stack_trace *trace) 72 { 73 save_stack_trace_tsk(current, trace); 74 } 75 EXPORT_SYMBOL_GPL(save_stack_trace); 76 77 void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) 78 { 79 struct pt_regs dummyregs; 80 struct pt_regs *regs = &dummyregs; 81 82 WARN_ON(trace->nr_entries || !trace->max_entries); 83 84 if (tsk != current) { 85 regs->regs[29] = tsk->thread.reg29; 86 regs->regs[31] = 0; 87 regs->cp0_epc = tsk->thread.reg31; 88 } else 89 prepare_frametrace(regs); 90 save_context_stack(trace, tsk, regs, tsk == current); 91 } 92 EXPORT_SYMBOL_GPL(save_stack_trace_tsk); 93