1 #include <linux/sched.h> 2 #include <linux/stacktrace.h> 3 4 #include "stacktrace.h" 5 6 int walk_stackframe(unsigned long fp, unsigned long low, unsigned long high, 7 int (*fn)(struct stackframe *, void *), void *data) 8 { 9 struct stackframe *frame; 10 11 do { 12 /* 13 * Check current frame pointer is within bounds 14 */ 15 if ((fp - 12) < low || fp + 4 >= high) 16 break; 17 18 frame = (struct stackframe *)(fp - 12); 19 20 if (fn(frame, data)) 21 break; 22 23 /* 24 * Update the low bound - the next frame must always 25 * be at a higher address than the current frame. 26 */ 27 low = fp + 4; 28 fp = frame->fp; 29 } while (fp); 30 31 return 0; 32 } 33 34 #ifdef CONFIG_STACKTRACE 35 struct stack_trace_data { 36 struct stack_trace *trace; 37 unsigned int skip; 38 }; 39 40 static int save_trace(struct stackframe *frame, void *d) 41 { 42 struct stack_trace_data *data = d; 43 struct stack_trace *trace = data->trace; 44 45 if (data->skip) { 46 data->skip--; 47 return 0; 48 } 49 50 trace->entries[trace->nr_entries++] = frame->lr; 51 52 return trace->nr_entries >= trace->max_entries; 53 } 54 55 void save_stack_trace(struct stack_trace *trace, struct task_struct *task) 56 { 57 struct stack_trace_data data; 58 unsigned long fp, base; 59 60 data.trace = trace; 61 data.skip = trace->skip; 62 63 if (task) { 64 base = (unsigned long)task_stack_page(task); 65 fp = 0; /* FIXME */ 66 } else { 67 base = (unsigned long)task_stack_page(current); 68 asm("mov %0, fp" : "=r" (fp)); 69 } 70 71 walk_stackframe(fp, base, base + THREAD_SIZE, save_trace, &data); 72 } 73 #endif 74