1*457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2ecea4ab6SPaul Gortmaker #include <linux/export.h> 3f16fb1ecSRussell King #include <linux/sched.h> 4b17b0153SIngo Molnar #include <linux/sched/debug.h> 5f16fb1ecSRussell King #include <linux/stacktrace.h> 6f16fb1ecSRussell King 7c6089061SRussell King #include <asm/sections.h> 82d7c11bfSCatalin Marinas #include <asm/stacktrace.h> 907b40341SRussell King #include <asm/traps.h> 10f16fb1ecSRussell King 112d7c11bfSCatalin Marinas #if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND) 122d7c11bfSCatalin Marinas /* 132d7c11bfSCatalin Marinas * Unwind the current stack frame and store the new register values in the 142d7c11bfSCatalin Marinas * structure passed as argument. Unwinding is equivalent to a function return, 152d7c11bfSCatalin Marinas * hence the new PC value rather than LR should be used for backtrace. 162d7c11bfSCatalin Marinas * 172d7c11bfSCatalin Marinas * With framepointer enabled, a simple function prologue looks like this: 182d7c11bfSCatalin Marinas * mov ip, sp 192d7c11bfSCatalin Marinas * stmdb sp!, {fp, ip, lr, pc} 202d7c11bfSCatalin Marinas * sub fp, ip, #4 212d7c11bfSCatalin Marinas * 222d7c11bfSCatalin Marinas * A simple function epilogue looks like this: 232d7c11bfSCatalin Marinas * ldm sp, {fp, sp, pc} 242d7c11bfSCatalin Marinas * 252d7c11bfSCatalin Marinas * Note that with framepointer enabled, even the leaf functions have the same 262d7c11bfSCatalin Marinas * prologue and epilogue, therefore we can ignore the LR value in this case. 272d7c11bfSCatalin Marinas */ 284bf1fa5aSUwe Kleine-König int notrace unwind_frame(struct stackframe *frame) 292d7c11bfSCatalin Marinas { 302d7c11bfSCatalin Marinas unsigned long high, low; 312d7c11bfSCatalin Marinas unsigned long fp = frame->fp; 322d7c11bfSCatalin Marinas 332d7c11bfSCatalin Marinas /* only go to a higher address on the stack */ 342d7c11bfSCatalin Marinas low = frame->sp; 35d33aadbfSWill Deacon high = ALIGN(low, THREAD_SIZE); 362d7c11bfSCatalin Marinas 372d7c11bfSCatalin Marinas /* check current frame pointer is within bounds */ 383abb6671SKonstantin Khlebnikov if (fp < low + 12 || fp > high - 4) 392d7c11bfSCatalin Marinas return -EINVAL; 402d7c11bfSCatalin Marinas 412d7c11bfSCatalin Marinas /* restore the registers from the stack frame */ 422d7c11bfSCatalin Marinas frame->fp = *(unsigned long *)(fp - 12); 432d7c11bfSCatalin Marinas frame->sp = *(unsigned long *)(fp - 8); 442d7c11bfSCatalin Marinas frame->pc = *(unsigned long *)(fp - 4); 452d7c11bfSCatalin Marinas 462d7c11bfSCatalin Marinas return 0; 472d7c11bfSCatalin Marinas } 482d7c11bfSCatalin Marinas #endif 492d7c11bfSCatalin Marinas 504bf1fa5aSUwe Kleine-König void notrace walk_stackframe(struct stackframe *frame, 51f16fb1ecSRussell King int (*fn)(struct stackframe *, void *), void *data) 52f16fb1ecSRussell King { 532d7c11bfSCatalin Marinas while (1) { 542d7c11bfSCatalin Marinas int ret; 55f16fb1ecSRussell King 56f16fb1ecSRussell King if (fn(frame, data)) 57f16fb1ecSRussell King break; 582d7c11bfSCatalin Marinas ret = unwind_frame(frame); 592d7c11bfSCatalin Marinas if (ret < 0) 602d7c11bfSCatalin Marinas break; 612d7c11bfSCatalin Marinas } 62f16fb1ecSRussell King } 637b104bcbSAl Viro EXPORT_SYMBOL(walk_stackframe); 64f16fb1ecSRussell King 65f16fb1ecSRussell King #ifdef CONFIG_STACKTRACE 66f16fb1ecSRussell King struct stack_trace_data { 67f16fb1ecSRussell King struct stack_trace *trace; 68f76e9154SNicolas Pitre unsigned int no_sched_functions; 69f16fb1ecSRussell King unsigned int skip; 70f16fb1ecSRussell King }; 71f16fb1ecSRussell King 72f16fb1ecSRussell King static int save_trace(struct stackframe *frame, void *d) 73f16fb1ecSRussell King { 74f16fb1ecSRussell King struct stack_trace_data *data = d; 75f16fb1ecSRussell King struct stack_trace *trace = data->trace; 7607b40341SRussell King struct pt_regs *regs; 772d7c11bfSCatalin Marinas unsigned long addr = frame->pc; 78f16fb1ecSRussell King 79f76e9154SNicolas Pitre if (data->no_sched_functions && in_sched_functions(addr)) 80f76e9154SNicolas Pitre return 0; 81f16fb1ecSRussell King if (data->skip) { 82f16fb1ecSRussell King data->skip--; 83f16fb1ecSRussell King return 0; 84f16fb1ecSRussell King } 85f16fb1ecSRussell King 86f76e9154SNicolas Pitre trace->entries[trace->nr_entries++] = addr; 87f16fb1ecSRussell King 8807b40341SRussell King if (trace->nr_entries >= trace->max_entries) 8907b40341SRussell King return 1; 9007b40341SRussell King 91c6089061SRussell King if (!in_entry_text(frame->pc)) 9207b40341SRussell King return 0; 9307b40341SRussell King 9407b40341SRussell King regs = (struct pt_regs *)frame->sp; 9507b40341SRussell King 9607b40341SRussell King trace->entries[trace->nr_entries++] = regs->ARM_pc; 9707b40341SRussell King 98f16fb1ecSRussell King return trace->nr_entries >= trace->max_entries; 99f16fb1ecSRussell King } 100f16fb1ecSRussell King 1013683f44cSRussell King /* This must be noinline to so that our skip calculation works correctly */ 1023683f44cSRussell King static noinline void __save_stack_trace(struct task_struct *tsk, 1033683f44cSRussell King struct stack_trace *trace, unsigned int nosched) 104f16fb1ecSRussell King { 105f16fb1ecSRussell King struct stack_trace_data data; 1062d7c11bfSCatalin Marinas struct stackframe frame; 107f16fb1ecSRussell King 108f16fb1ecSRussell King data.trace = trace; 109f16fb1ecSRussell King data.skip = trace->skip; 1103683f44cSRussell King data.no_sched_functions = nosched; 111f76e9154SNicolas Pitre 112f76e9154SNicolas Pitre if (tsk != current) { 113f76e9154SNicolas Pitre #ifdef CONFIG_SMP 114f76e9154SNicolas Pitre /* 115d5996b2fSRussell King * What guarantees do we have here that 'tsk' is not 116d5996b2fSRussell King * running on another CPU? For now, ignore it as we 117d5996b2fSRussell King * can't guarantee we won't explode. 118f76e9154SNicolas Pitre */ 119d5996b2fSRussell King return; 120f76e9154SNicolas Pitre #else 1212d7c11bfSCatalin Marinas frame.fp = thread_saved_fp(tsk); 1222d7c11bfSCatalin Marinas frame.sp = thread_saved_sp(tsk); 1232d7c11bfSCatalin Marinas frame.lr = 0; /* recovered from the stack */ 1242d7c11bfSCatalin Marinas frame.pc = thread_saved_pc(tsk); 125f76e9154SNicolas Pitre #endif 126f76e9154SNicolas Pitre } else { 1273683f44cSRussell King /* We don't want this function nor the caller */ 1283683f44cSRussell King data.skip += 2; 1292d7c11bfSCatalin Marinas frame.fp = (unsigned long)__builtin_frame_address(0); 13074dbeee0SBehan Webster frame.sp = current_stack_pointer; 1312d7c11bfSCatalin Marinas frame.lr = (unsigned long)__builtin_return_address(0); 1323683f44cSRussell King frame.pc = (unsigned long)__save_stack_trace; 133f76e9154SNicolas Pitre } 134f16fb1ecSRussell King 1352d7c11bfSCatalin Marinas walk_stackframe(&frame, save_trace, &data); 136f76e9154SNicolas Pitre } 137f76e9154SNicolas Pitre 1389c986661SLin Yongting void save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace) 1399c986661SLin Yongting { 1409c986661SLin Yongting struct stack_trace_data data; 1419c986661SLin Yongting struct stackframe frame; 1429c986661SLin Yongting 1439c986661SLin Yongting data.trace = trace; 1449c986661SLin Yongting data.skip = trace->skip; 1459c986661SLin Yongting data.no_sched_functions = 0; 1469c986661SLin Yongting 1479c986661SLin Yongting frame.fp = regs->ARM_fp; 1489c986661SLin Yongting frame.sp = regs->ARM_sp; 1499c986661SLin Yongting frame.lr = regs->ARM_lr; 1509c986661SLin Yongting frame.pc = regs->ARM_pc; 1519c986661SLin Yongting 1529c986661SLin Yongting walk_stackframe(&frame, save_trace, &data); 1539c986661SLin Yongting } 1549c986661SLin Yongting 1553683f44cSRussell King void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) 1563683f44cSRussell King { 1573683f44cSRussell King __save_stack_trace(tsk, trace, 1); 1583683f44cSRussell King } 1599a3dc318SDustin Brown EXPORT_SYMBOL(save_stack_trace_tsk); 1603683f44cSRussell King 161f76e9154SNicolas Pitre void save_stack_trace(struct stack_trace *trace) 162f76e9154SNicolas Pitre { 1633683f44cSRussell King __save_stack_trace(current, trace, 0); 164f16fb1ecSRussell King } 1657b4c9505SIngo Molnar EXPORT_SYMBOL_GPL(save_stack_trace); 166f16fb1ecSRussell King #endif 167