at v4.5 1.5 kB view raw
1#include <linux/sched.h> 2#include <linux/stacktrace.h> 3#include <linux/stacktrace.h> 4#include <asm/stacktrace.h> 5 6void walk_stackframe(unsigned long sp, 7 int (*fn)(unsigned long addr, void *data), 8 void *data) 9{ 10 unsigned long high = ALIGN(sp, THREAD_SIZE); 11 12 for (; sp <= high - 4; sp += 4) { 13 unsigned long addr = *(unsigned long *) sp; 14 15 if (!kernel_text_address(addr)) 16 continue; 17 18 if (fn(addr, data)) 19 break; 20 } 21} 22 23struct stack_trace_data { 24 struct stack_trace *trace; 25 unsigned int no_sched_functions; 26 unsigned int skip; 27}; 28 29#ifdef CONFIG_STACKTRACE 30 31static int save_trace(unsigned long addr, void *d) 32{ 33 struct stack_trace_data *data = d; 34 struct stack_trace *trace = data->trace; 35 36 if (data->no_sched_functions && in_sched_functions(addr)) 37 return 0; 38 39 if (data->skip) { 40 data->skip--; 41 return 0; 42 } 43 44 trace->entries[trace->nr_entries++] = addr; 45 46 return trace->nr_entries >= trace->max_entries; 47} 48 49void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) 50{ 51 struct stack_trace_data data; 52 unsigned long sp; 53 54 data.trace = trace; 55 data.skip = trace->skip; 56 57 if (tsk != current) { 58 data.no_sched_functions = 1; 59 sp = tsk->thread.ksp; 60 } else { 61 data.no_sched_functions = 0; 62 sp = rdsp(); 63 } 64 65 walk_stackframe(sp, save_trace, &data); 66 if (trace->nr_entries < trace->max_entries) 67 trace->entries[trace->nr_entries++] = ULONG_MAX; 68} 69 70void save_stack_trace(struct stack_trace *trace) 71{ 72 save_stack_trace_tsk(current, trace); 73} 74EXPORT_SYMBOL_GPL(save_stack_trace); 75 76#endif /* CONFIG_STACKTRACE */