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 skip; 40 }; 41 42 static int save_trace(struct stackframe *frame, void *d) 43 { 44 struct stack_trace_data *data = d; 45 struct stack_trace *trace = data->trace; 46 47 if (data->skip) { 48 data->skip--; 49 return 0; 50 } 51 52 trace->entries[trace->nr_entries++] = frame->lr; 53 54 return trace->nr_entries >= trace->max_entries; 55 } 56 57 void save_stack_trace(struct stack_trace *trace) 58 { 59 struct stack_trace_data data; 60 unsigned long fp, base; 61 62 data.trace = trace; 63 data.skip = trace->skip; 64 base = (unsigned long)task_stack_page(current); 65 asm("mov %0, fp" : "=r" (fp)); 66 67 walk_stackframe(fp, base, base + THREAD_SIZE, save_trace, &data); 68 } 69 #endif 70