1ecea4ab6SPaul Gortmaker #include <linux/export.h> 2f16fb1ecSRussell King #include <linux/sched.h> 3b17b0153SIngo Molnar #include <linux/sched/debug.h> 4f16fb1ecSRussell King #include <linux/stacktrace.h> 5f16fb1ecSRussell King 6*c6089061SRussell King #include <asm/sections.h> 72d7c11bfSCatalin Marinas #include <asm/stacktrace.h> 807b40341SRussell King #include <asm/traps.h> 9f16fb1ecSRussell King 102d7c11bfSCatalin Marinas #if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND) 112d7c11bfSCatalin Marinas /* 122d7c11bfSCatalin Marinas * Unwind the current stack frame and store the new register values in the 132d7c11bfSCatalin Marinas * structure passed as argument. Unwinding is equivalent to a function return, 142d7c11bfSCatalin Marinas * hence the new PC value rather than LR should be used for backtrace. 152d7c11bfSCatalin Marinas * 162d7c11bfSCatalin Marinas * With framepointer enabled, a simple function prologue looks like this: 172d7c11bfSCatalin Marinas * mov ip, sp 182d7c11bfSCatalin Marinas * stmdb sp!, {fp, ip, lr, pc} 192d7c11bfSCatalin Marinas * sub fp, ip, #4 202d7c11bfSCatalin Marinas * 212d7c11bfSCatalin Marinas * A simple function epilogue looks like this: 222d7c11bfSCatalin Marinas * ldm sp, {fp, sp, pc} 232d7c11bfSCatalin Marinas * 242d7c11bfSCatalin Marinas * Note that with framepointer enabled, even the leaf functions have the same 252d7c11bfSCatalin Marinas * prologue and epilogue, therefore we can ignore the LR value in this case. 262d7c11bfSCatalin Marinas */ 274bf1fa5aSUwe Kleine-König int notrace unwind_frame(struct stackframe *frame) 282d7c11bfSCatalin Marinas { 292d7c11bfSCatalin Marinas unsigned long high, low; 302d7c11bfSCatalin Marinas unsigned long fp = frame->fp; 312d7c11bfSCatalin Marinas 322d7c11bfSCatalin Marinas /* only go to a higher address on the stack */ 332d7c11bfSCatalin Marinas low = frame->sp; 34d33aadbfSWill Deacon high = ALIGN(low, THREAD_SIZE); 352d7c11bfSCatalin Marinas 362d7c11bfSCatalin Marinas /* check current frame pointer is within bounds */ 373abb6671SKonstantin Khlebnikov if (fp < low + 12 || fp > high - 4) 382d7c11bfSCatalin Marinas return -EINVAL; 392d7c11bfSCatalin Marinas 402d7c11bfSCatalin Marinas /* restore the registers from the stack frame */ 412d7c11bfSCatalin Marinas frame->fp = *(unsigned long *)(fp - 12); 422d7c11bfSCatalin Marinas frame->sp = *(unsigned long *)(fp - 8); 432d7c11bfSCatalin Marinas frame->pc = *(unsigned long *)(fp - 4); 442d7c11bfSCatalin Marinas 452d7c11bfSCatalin Marinas return 0; 462d7c11bfSCatalin Marinas } 472d7c11bfSCatalin Marinas #endif 482d7c11bfSCatalin Marinas 494bf1fa5aSUwe Kleine-König void notrace walk_stackframe(struct stackframe *frame, 50f16fb1ecSRussell King int (*fn)(struct stackframe *, void *), void *data) 51f16fb1ecSRussell King { 522d7c11bfSCatalin Marinas while (1) { 532d7c11bfSCatalin Marinas int ret; 54f16fb1ecSRussell King 55f16fb1ecSRussell King if (fn(frame, data)) 56f16fb1ecSRussell King break; 572d7c11bfSCatalin Marinas ret = unwind_frame(frame); 582d7c11bfSCatalin Marinas if (ret < 0) 592d7c11bfSCatalin Marinas break; 602d7c11bfSCatalin Marinas } 61f16fb1ecSRussell King } 627b104bcbSAl Viro EXPORT_SYMBOL(walk_stackframe); 63f16fb1ecSRussell King 64f16fb1ecSRussell King #ifdef CONFIG_STACKTRACE 65f16fb1ecSRussell King struct stack_trace_data { 66f16fb1ecSRussell King struct stack_trace *trace; 67f76e9154SNicolas Pitre unsigned int no_sched_functions; 68f16fb1ecSRussell King unsigned int skip; 69f16fb1ecSRussell King }; 70f16fb1ecSRussell King 71f16fb1ecSRussell King static int save_trace(struct stackframe *frame, void *d) 72f16fb1ecSRussell King { 73f16fb1ecSRussell King struct stack_trace_data *data = d; 74f16fb1ecSRussell King struct stack_trace *trace = data->trace; 7507b40341SRussell King struct pt_regs *regs; 762d7c11bfSCatalin Marinas unsigned long addr = frame->pc; 77f16fb1ecSRussell King 78f76e9154SNicolas Pitre if (data->no_sched_functions && in_sched_functions(addr)) 79f76e9154SNicolas Pitre return 0; 80f16fb1ecSRussell King if (data->skip) { 81f16fb1ecSRussell King data->skip--; 82f16fb1ecSRussell King return 0; 83f16fb1ecSRussell King } 84f16fb1ecSRussell King 85f76e9154SNicolas Pitre trace->entries[trace->nr_entries++] = addr; 86f16fb1ecSRussell King 8707b40341SRussell King if (trace->nr_entries >= trace->max_entries) 8807b40341SRussell King return 1; 8907b40341SRussell King 90*c6089061SRussell King if (!in_entry_text(frame->pc)) 9107b40341SRussell King return 0; 9207b40341SRussell King 9307b40341SRussell King regs = (struct pt_regs *)frame->sp; 9407b40341SRussell King 9507b40341SRussell King trace->entries[trace->nr_entries++] = regs->ARM_pc; 9607b40341SRussell King 97f16fb1ecSRussell King return trace->nr_entries >= trace->max_entries; 98f16fb1ecSRussell King } 99f16fb1ecSRussell King 1003683f44cSRussell King /* This must be noinline to so that our skip calculation works correctly */ 1013683f44cSRussell King static noinline void __save_stack_trace(struct task_struct *tsk, 1023683f44cSRussell King struct stack_trace *trace, unsigned int nosched) 103f16fb1ecSRussell King { 104f16fb1ecSRussell King struct stack_trace_data data; 1052d7c11bfSCatalin Marinas struct stackframe frame; 106f16fb1ecSRussell King 107f16fb1ecSRussell King data.trace = trace; 108f16fb1ecSRussell King data.skip = trace->skip; 1093683f44cSRussell King data.no_sched_functions = nosched; 110f76e9154SNicolas Pitre 111f76e9154SNicolas Pitre if (tsk != current) { 112f76e9154SNicolas Pitre #ifdef CONFIG_SMP 113f76e9154SNicolas Pitre /* 114d5996b2fSRussell King * What guarantees do we have here that 'tsk' is not 115d5996b2fSRussell King * running on another CPU? For now, ignore it as we 116d5996b2fSRussell King * can't guarantee we won't explode. 117f76e9154SNicolas Pitre */ 118d5996b2fSRussell King if (trace->nr_entries < trace->max_entries) 119d5996b2fSRussell King trace->entries[trace->nr_entries++] = ULONG_MAX; 120d5996b2fSRussell King return; 121f76e9154SNicolas Pitre #else 1222d7c11bfSCatalin Marinas frame.fp = thread_saved_fp(tsk); 1232d7c11bfSCatalin Marinas frame.sp = thread_saved_sp(tsk); 1242d7c11bfSCatalin Marinas frame.lr = 0; /* recovered from the stack */ 1252d7c11bfSCatalin Marinas frame.pc = thread_saved_pc(tsk); 126f76e9154SNicolas Pitre #endif 127f76e9154SNicolas Pitre } else { 1283683f44cSRussell King /* We don't want this function nor the caller */ 1293683f44cSRussell King data.skip += 2; 1302d7c11bfSCatalin Marinas frame.fp = (unsigned long)__builtin_frame_address(0); 13174dbeee0SBehan Webster frame.sp = current_stack_pointer; 1322d7c11bfSCatalin Marinas frame.lr = (unsigned long)__builtin_return_address(0); 1333683f44cSRussell King frame.pc = (unsigned long)__save_stack_trace; 134f76e9154SNicolas Pitre } 135f16fb1ecSRussell King 1362d7c11bfSCatalin Marinas walk_stackframe(&frame, save_trace, &data); 137f76e9154SNicolas Pitre if (trace->nr_entries < trace->max_entries) 138f76e9154SNicolas Pitre trace->entries[trace->nr_entries++] = ULONG_MAX; 139f76e9154SNicolas Pitre } 140f76e9154SNicolas Pitre 1419c986661SLin Yongting void save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace) 1429c986661SLin Yongting { 1439c986661SLin Yongting struct stack_trace_data data; 1449c986661SLin Yongting struct stackframe frame; 1459c986661SLin Yongting 1469c986661SLin Yongting data.trace = trace; 1479c986661SLin Yongting data.skip = trace->skip; 1489c986661SLin Yongting data.no_sched_functions = 0; 1499c986661SLin Yongting 1509c986661SLin Yongting frame.fp = regs->ARM_fp; 1519c986661SLin Yongting frame.sp = regs->ARM_sp; 1529c986661SLin Yongting frame.lr = regs->ARM_lr; 1539c986661SLin Yongting frame.pc = regs->ARM_pc; 1549c986661SLin Yongting 1559c986661SLin Yongting walk_stackframe(&frame, save_trace, &data); 1569c986661SLin Yongting if (trace->nr_entries < trace->max_entries) 1579c986661SLin Yongting trace->entries[trace->nr_entries++] = ULONG_MAX; 1589c986661SLin Yongting } 1599c986661SLin Yongting 1603683f44cSRussell King void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) 1613683f44cSRussell King { 1623683f44cSRussell King __save_stack_trace(tsk, trace, 1); 1633683f44cSRussell King } 1649a3dc318SDustin Brown EXPORT_SYMBOL(save_stack_trace_tsk); 1653683f44cSRussell King 166f76e9154SNicolas Pitre void save_stack_trace(struct stack_trace *trace) 167f76e9154SNicolas Pitre { 1683683f44cSRussell King __save_stack_trace(current, trace, 0); 169f16fb1ecSRussell King } 1707b4c9505SIngo Molnar EXPORT_SYMBOL_GPL(save_stack_trace); 171f16fb1ecSRussell King #endif 172