1 /* 2 * Stack trace management functions 3 * 4 * Copyright (C) 2009 Helge Deller <deller@gmx.de> 5 * based on arch/x86/kernel/stacktrace.c by Ingo Molnar <mingo@redhat.com> 6 * and parisc unwind functions by Randolph Chung <tausq@debian.org> 7 * 8 * TODO: Userspace stacktrace (CONFIG_USER_STACKTRACE_SUPPORT) 9 */ 10 #include <linux/module.h> 11 #include <linux/stacktrace.h> 12 13 #include <asm/unwind.h> 14 15 static void dump_trace(struct task_struct *task, struct stack_trace *trace) 16 { 17 struct unwind_frame_info info; 18 19 /* initialize unwind info */ 20 if (task == current) { 21 unsigned long sp; 22 struct pt_regs r; 23 HERE: 24 asm volatile ("copy %%r30, %0" : "=r"(sp)); 25 memset(&r, 0, sizeof(struct pt_regs)); 26 r.iaoq[0] = (unsigned long)&&HERE; 27 r.gr[2] = (unsigned long)__builtin_return_address(0); 28 r.gr[30] = sp; 29 unwind_frame_init(&info, task, &r); 30 } else { 31 unwind_frame_init_from_blocked_task(&info, task); 32 } 33 34 /* unwind stack and save entries in stack_trace struct */ 35 trace->nr_entries = 0; 36 while (trace->nr_entries < trace->max_entries) { 37 if (unwind_once(&info) < 0 || info.ip == 0) 38 break; 39 40 if (__kernel_text_address(info.ip)) 41 trace->entries[trace->nr_entries++] = info.ip; 42 } 43 } 44 45 46 /* 47 * Save stack-backtrace addresses into a stack_trace buffer. 48 */ 49 void save_stack_trace(struct stack_trace *trace) 50 { 51 dump_trace(current, trace); 52 if (trace->nr_entries < trace->max_entries) 53 trace->entries[trace->nr_entries++] = ULONG_MAX; 54 } 55 EXPORT_SYMBOL_GPL(save_stack_trace); 56 57 void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) 58 { 59 dump_trace(tsk, trace); 60 if (trace->nr_entries < trace->max_entries) 61 trace->entries[trace->nr_entries++] = ULONG_MAX; 62 } 63 EXPORT_SYMBOL_GPL(save_stack_trace_tsk); 64