17b104bcbSAl Viro #include <linux/module.h> 2f16fb1ecSRussell King #include <linux/sched.h> 3f16fb1ecSRussell King #include <linux/stacktrace.h> 4f16fb1ecSRussell King 5*2d7c11bfSCatalin Marinas #include <asm/stacktrace.h> 6f16fb1ecSRussell King 7*2d7c11bfSCatalin Marinas #if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND) 8*2d7c11bfSCatalin Marinas /* 9*2d7c11bfSCatalin Marinas * Unwind the current stack frame and store the new register values in the 10*2d7c11bfSCatalin Marinas * structure passed as argument. Unwinding is equivalent to a function return, 11*2d7c11bfSCatalin Marinas * hence the new PC value rather than LR should be used for backtrace. 12*2d7c11bfSCatalin Marinas * 13*2d7c11bfSCatalin Marinas * With framepointer enabled, a simple function prologue looks like this: 14*2d7c11bfSCatalin Marinas * mov ip, sp 15*2d7c11bfSCatalin Marinas * stmdb sp!, {fp, ip, lr, pc} 16*2d7c11bfSCatalin Marinas * sub fp, ip, #4 17*2d7c11bfSCatalin Marinas * 18*2d7c11bfSCatalin Marinas * A simple function epilogue looks like this: 19*2d7c11bfSCatalin Marinas * ldm sp, {fp, sp, pc} 20*2d7c11bfSCatalin Marinas * 21*2d7c11bfSCatalin Marinas * Note that with framepointer enabled, even the leaf functions have the same 22*2d7c11bfSCatalin Marinas * prologue and epilogue, therefore we can ignore the LR value in this case. 23*2d7c11bfSCatalin Marinas */ 24*2d7c11bfSCatalin Marinas int unwind_frame(struct stackframe *frame) 25*2d7c11bfSCatalin Marinas { 26*2d7c11bfSCatalin Marinas unsigned long high, low; 27*2d7c11bfSCatalin Marinas unsigned long fp = frame->fp; 28*2d7c11bfSCatalin Marinas 29*2d7c11bfSCatalin Marinas /* only go to a higher address on the stack */ 30*2d7c11bfSCatalin Marinas low = frame->sp; 31*2d7c11bfSCatalin Marinas high = ALIGN(low, THREAD_SIZE) + THREAD_SIZE; 32*2d7c11bfSCatalin Marinas 33*2d7c11bfSCatalin Marinas /* check current frame pointer is within bounds */ 34*2d7c11bfSCatalin Marinas if (fp < (low + 12) || fp + 4 >= high) 35*2d7c11bfSCatalin Marinas return -EINVAL; 36*2d7c11bfSCatalin Marinas 37*2d7c11bfSCatalin Marinas /* restore the registers from the stack frame */ 38*2d7c11bfSCatalin Marinas frame->fp = *(unsigned long *)(fp - 12); 39*2d7c11bfSCatalin Marinas frame->sp = *(unsigned long *)(fp - 8); 40*2d7c11bfSCatalin Marinas frame->pc = *(unsigned long *)(fp - 4); 41*2d7c11bfSCatalin Marinas 42*2d7c11bfSCatalin Marinas return 0; 43*2d7c11bfSCatalin Marinas } 44*2d7c11bfSCatalin Marinas #endif 45*2d7c11bfSCatalin Marinas 46*2d7c11bfSCatalin Marinas void walk_stackframe(struct stackframe *frame, 47f16fb1ecSRussell King int (*fn)(struct stackframe *, void *), void *data) 48f16fb1ecSRussell King { 49*2d7c11bfSCatalin Marinas while (1) { 50*2d7c11bfSCatalin Marinas int ret; 51f16fb1ecSRussell King 52f16fb1ecSRussell King if (fn(frame, data)) 53f16fb1ecSRussell King break; 54*2d7c11bfSCatalin Marinas ret = unwind_frame(frame); 55*2d7c11bfSCatalin Marinas if (ret < 0) 56*2d7c11bfSCatalin Marinas break; 57*2d7c11bfSCatalin Marinas } 58f16fb1ecSRussell King } 597b104bcbSAl Viro EXPORT_SYMBOL(walk_stackframe); 60f16fb1ecSRussell King 61f16fb1ecSRussell King #ifdef CONFIG_STACKTRACE 62f16fb1ecSRussell King struct stack_trace_data { 63f16fb1ecSRussell King struct stack_trace *trace; 64f76e9154SNicolas Pitre unsigned int no_sched_functions; 65f16fb1ecSRussell King unsigned int skip; 66f16fb1ecSRussell King }; 67f16fb1ecSRussell King 68f16fb1ecSRussell King static int save_trace(struct stackframe *frame, void *d) 69f16fb1ecSRussell King { 70f16fb1ecSRussell King struct stack_trace_data *data = d; 71f16fb1ecSRussell King struct stack_trace *trace = data->trace; 72*2d7c11bfSCatalin Marinas unsigned long addr = frame->pc; 73f16fb1ecSRussell King 74f76e9154SNicolas Pitre if (data->no_sched_functions && in_sched_functions(addr)) 75f76e9154SNicolas Pitre return 0; 76f16fb1ecSRussell King if (data->skip) { 77f16fb1ecSRussell King data->skip--; 78f16fb1ecSRussell King return 0; 79f16fb1ecSRussell King } 80f16fb1ecSRussell King 81f76e9154SNicolas Pitre trace->entries[trace->nr_entries++] = addr; 82f16fb1ecSRussell King 83f16fb1ecSRussell King return trace->nr_entries >= trace->max_entries; 84f16fb1ecSRussell King } 85f16fb1ecSRussell King 86f76e9154SNicolas Pitre void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) 87f16fb1ecSRussell King { 88f16fb1ecSRussell King struct stack_trace_data data; 89*2d7c11bfSCatalin Marinas struct stackframe frame; 90f16fb1ecSRussell King 91f16fb1ecSRussell King data.trace = trace; 92f16fb1ecSRussell King data.skip = trace->skip; 93f76e9154SNicolas Pitre 94f76e9154SNicolas Pitre if (tsk != current) { 95f76e9154SNicolas Pitre #ifdef CONFIG_SMP 96f76e9154SNicolas Pitre /* 97f76e9154SNicolas Pitre * What guarantees do we have here that 'tsk' 98f76e9154SNicolas Pitre * is not running on another CPU? 99f76e9154SNicolas Pitre */ 100f76e9154SNicolas Pitre BUG(); 101f76e9154SNicolas Pitre #else 102f76e9154SNicolas Pitre data.no_sched_functions = 1; 103*2d7c11bfSCatalin Marinas frame.fp = thread_saved_fp(tsk); 104*2d7c11bfSCatalin Marinas frame.sp = thread_saved_sp(tsk); 105*2d7c11bfSCatalin Marinas frame.lr = 0; /* recovered from the stack */ 106*2d7c11bfSCatalin Marinas frame.pc = thread_saved_pc(tsk); 107f76e9154SNicolas Pitre #endif 108f76e9154SNicolas Pitre } else { 109*2d7c11bfSCatalin Marinas register unsigned long current_sp asm ("sp"); 110*2d7c11bfSCatalin Marinas 111f76e9154SNicolas Pitre data.no_sched_functions = 0; 112*2d7c11bfSCatalin Marinas frame.fp = (unsigned long)__builtin_frame_address(0); 113*2d7c11bfSCatalin Marinas frame.sp = current_sp; 114*2d7c11bfSCatalin Marinas frame.lr = (unsigned long)__builtin_return_address(0); 115*2d7c11bfSCatalin Marinas frame.pc = (unsigned long)save_stack_trace_tsk; 116f76e9154SNicolas Pitre } 117f16fb1ecSRussell King 118*2d7c11bfSCatalin Marinas walk_stackframe(&frame, save_trace, &data); 119f76e9154SNicolas Pitre if (trace->nr_entries < trace->max_entries) 120f76e9154SNicolas Pitre trace->entries[trace->nr_entries++] = ULONG_MAX; 121f76e9154SNicolas Pitre } 122f76e9154SNicolas Pitre 123f76e9154SNicolas Pitre void save_stack_trace(struct stack_trace *trace) 124f76e9154SNicolas Pitre { 125f76e9154SNicolas Pitre save_stack_trace_tsk(current, trace); 126f16fb1ecSRussell King } 1277b4c9505SIngo Molnar EXPORT_SYMBOL_GPL(save_stack_trace); 128f16fb1ecSRussell King #endif 129