1 #include <linux/module.h> 2 #include <linux/sched.h> 3 #include <linux/stacktrace.h> 4 5 #include "stacktrace.h" 6 7 int walk_stackframe(unsigned long fp, unsigned long low, unsigned long high, 8 int (*fn)(struct stackframe *, void *), void *data) 9 { 10 struct stackframe *frame; 11 12 do { 13 /* 14 * Check current frame pointer is within bounds 15 */ 16 if (fp < (low + 12) || fp + 4 >= high) 17 break; 18 19 frame = (struct stackframe *)(fp - 12); 20 21 if (fn(frame, data)) 22 break; 23 24 /* 25 * Update the low bound - the next frame must always 26 * be at a higher address than the current frame. 27 */ 28 low = fp + 4; 29 fp = frame->fp; 30 } while (fp); 31 32 return 0; 33 } 34 EXPORT_SYMBOL(walk_stackframe); 35 36 #ifdef CONFIG_STACKTRACE 37 struct stack_trace_data { 38 struct stack_trace *trace; 39 unsigned int no_sched_functions; 40 unsigned int skip; 41 }; 42 43 static int save_trace(struct stackframe *frame, void *d) 44 { 45 struct stack_trace_data *data = d; 46 struct stack_trace *trace = data->trace; 47 unsigned long addr = frame->lr; 48 49 if (data->no_sched_functions && in_sched_functions(addr)) 50 return 0; 51 if (data->skip) { 52 data->skip--; 53 return 0; 54 } 55 56 trace->entries[trace->nr_entries++] = addr; 57 58 return trace->nr_entries >= trace->max_entries; 59 } 60 61 void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) 62 { 63 struct stack_trace_data data; 64 unsigned long fp, base; 65 66 data.trace = trace; 67 data.skip = trace->skip; 68 base = (unsigned long)task_stack_page(tsk); 69 70 if (tsk != current) { 71 #ifdef CONFIG_SMP 72 /* 73 * What guarantees do we have here that 'tsk' 74 * is not running on another CPU? 75 */ 76 BUG(); 77 #else 78 data.no_sched_functions = 1; 79 fp = thread_saved_fp(tsk); 80 #endif 81 } else { 82 data.no_sched_functions = 0; 83 asm("mov %0, fp" : "=r" (fp)); 84 } 85 86 walk_stackframe(fp, base, base + THREAD_SIZE, save_trace, &data); 87 if (trace->nr_entries < trace->max_entries) 88 trace->entries[trace->nr_entries++] = ULONG_MAX; 89 } 90 91 void save_stack_trace(struct stack_trace *trace) 92 { 93 save_stack_trace_tsk(current, trace); 94 } 95 EXPORT_SYMBOL_GPL(save_stack_trace); 96 #endif 97