1457c8996SThomas 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 * 25*b4d5ec9bSNathan Huckleberry * When compiled with clang, pc and sp are not pushed. A simple function 26*b4d5ec9bSNathan Huckleberry * prologue looks like this when built with clang: 27*b4d5ec9bSNathan Huckleberry * 28*b4d5ec9bSNathan Huckleberry * stmdb {..., fp, lr} 29*b4d5ec9bSNathan Huckleberry * add fp, sp, #x 30*b4d5ec9bSNathan Huckleberry * sub sp, sp, #y 31*b4d5ec9bSNathan Huckleberry * 32*b4d5ec9bSNathan Huckleberry * A simple function epilogue looks like this when built with clang: 33*b4d5ec9bSNathan Huckleberry * 34*b4d5ec9bSNathan Huckleberry * sub sp, fp, #x 35*b4d5ec9bSNathan Huckleberry * ldm {..., fp, pc} 36*b4d5ec9bSNathan Huckleberry * 37*b4d5ec9bSNathan Huckleberry * 382d7c11bfSCatalin Marinas * Note that with framepointer enabled, even the leaf functions have the same 392d7c11bfSCatalin Marinas * prologue and epilogue, therefore we can ignore the LR value in this case. 402d7c11bfSCatalin Marinas */ 414bf1fa5aSUwe Kleine-König int notrace unwind_frame(struct stackframe *frame) 422d7c11bfSCatalin Marinas { 432d7c11bfSCatalin Marinas unsigned long high, low; 442d7c11bfSCatalin Marinas unsigned long fp = frame->fp; 452d7c11bfSCatalin Marinas 462d7c11bfSCatalin Marinas /* only go to a higher address on the stack */ 472d7c11bfSCatalin Marinas low = frame->sp; 48d33aadbfSWill Deacon high = ALIGN(low, THREAD_SIZE); 492d7c11bfSCatalin Marinas 50*b4d5ec9bSNathan Huckleberry #ifdef CONFIG_CC_IS_CLANG 51*b4d5ec9bSNathan Huckleberry /* check current frame pointer is within bounds */ 52*b4d5ec9bSNathan Huckleberry if (fp < low + 4 || fp > high - 4) 53*b4d5ec9bSNathan Huckleberry return -EINVAL; 54*b4d5ec9bSNathan Huckleberry 55*b4d5ec9bSNathan Huckleberry frame->sp = frame->fp; 56*b4d5ec9bSNathan Huckleberry frame->fp = *(unsigned long *)(fp); 57*b4d5ec9bSNathan Huckleberry frame->pc = frame->lr; 58*b4d5ec9bSNathan Huckleberry frame->lr = *(unsigned long *)(fp + 4); 59*b4d5ec9bSNathan Huckleberry #else 602d7c11bfSCatalin Marinas /* check current frame pointer is within bounds */ 613abb6671SKonstantin Khlebnikov if (fp < low + 12 || fp > high - 4) 622d7c11bfSCatalin Marinas return -EINVAL; 632d7c11bfSCatalin Marinas 642d7c11bfSCatalin Marinas /* restore the registers from the stack frame */ 652d7c11bfSCatalin Marinas frame->fp = *(unsigned long *)(fp - 12); 662d7c11bfSCatalin Marinas frame->sp = *(unsigned long *)(fp - 8); 672d7c11bfSCatalin Marinas frame->pc = *(unsigned long *)(fp - 4); 68*b4d5ec9bSNathan Huckleberry #endif 692d7c11bfSCatalin Marinas 702d7c11bfSCatalin Marinas return 0; 712d7c11bfSCatalin Marinas } 722d7c11bfSCatalin Marinas #endif 732d7c11bfSCatalin Marinas 744bf1fa5aSUwe Kleine-König void notrace walk_stackframe(struct stackframe *frame, 75f16fb1ecSRussell King int (*fn)(struct stackframe *, void *), void *data) 76f16fb1ecSRussell King { 772d7c11bfSCatalin Marinas while (1) { 782d7c11bfSCatalin Marinas int ret; 79f16fb1ecSRussell King 80f16fb1ecSRussell King if (fn(frame, data)) 81f16fb1ecSRussell King break; 822d7c11bfSCatalin Marinas ret = unwind_frame(frame); 832d7c11bfSCatalin Marinas if (ret < 0) 842d7c11bfSCatalin Marinas break; 852d7c11bfSCatalin Marinas } 86f16fb1ecSRussell King } 877b104bcbSAl Viro EXPORT_SYMBOL(walk_stackframe); 88f16fb1ecSRussell King 89f16fb1ecSRussell King #ifdef CONFIG_STACKTRACE 90f16fb1ecSRussell King struct stack_trace_data { 91f16fb1ecSRussell King struct stack_trace *trace; 92f76e9154SNicolas Pitre unsigned int no_sched_functions; 93f16fb1ecSRussell King unsigned int skip; 94f16fb1ecSRussell King }; 95f16fb1ecSRussell King 96f16fb1ecSRussell King static int save_trace(struct stackframe *frame, void *d) 97f16fb1ecSRussell King { 98f16fb1ecSRussell King struct stack_trace_data *data = d; 99f16fb1ecSRussell King struct stack_trace *trace = data->trace; 10007b40341SRussell King struct pt_regs *regs; 1012d7c11bfSCatalin Marinas unsigned long addr = frame->pc; 102f16fb1ecSRussell King 103f76e9154SNicolas Pitre if (data->no_sched_functions && in_sched_functions(addr)) 104f76e9154SNicolas Pitre return 0; 105f16fb1ecSRussell King if (data->skip) { 106f16fb1ecSRussell King data->skip--; 107f16fb1ecSRussell King return 0; 108f16fb1ecSRussell King } 109f16fb1ecSRussell King 110f76e9154SNicolas Pitre trace->entries[trace->nr_entries++] = addr; 111f16fb1ecSRussell King 11207b40341SRussell King if (trace->nr_entries >= trace->max_entries) 11307b40341SRussell King return 1; 11407b40341SRussell King 115c6089061SRussell King if (!in_entry_text(frame->pc)) 11607b40341SRussell King return 0; 11707b40341SRussell King 11807b40341SRussell King regs = (struct pt_regs *)frame->sp; 11940ff1ddbSVincent Whitchurch if ((unsigned long)®s[1] > ALIGN(frame->sp, THREAD_SIZE)) 12040ff1ddbSVincent Whitchurch return 0; 12107b40341SRussell King 12207b40341SRussell King trace->entries[trace->nr_entries++] = regs->ARM_pc; 12307b40341SRussell King 124f16fb1ecSRussell King return trace->nr_entries >= trace->max_entries; 125f16fb1ecSRussell King } 126f16fb1ecSRussell King 1273683f44cSRussell King /* This must be noinline to so that our skip calculation works correctly */ 1283683f44cSRussell King static noinline void __save_stack_trace(struct task_struct *tsk, 1293683f44cSRussell King struct stack_trace *trace, unsigned int nosched) 130f16fb1ecSRussell King { 131f16fb1ecSRussell King struct stack_trace_data data; 1322d7c11bfSCatalin Marinas struct stackframe frame; 133f16fb1ecSRussell King 134f16fb1ecSRussell King data.trace = trace; 135f16fb1ecSRussell King data.skip = trace->skip; 1363683f44cSRussell King data.no_sched_functions = nosched; 137f76e9154SNicolas Pitre 138f76e9154SNicolas Pitre if (tsk != current) { 139f76e9154SNicolas Pitre #ifdef CONFIG_SMP 140f76e9154SNicolas Pitre /* 141d5996b2fSRussell King * What guarantees do we have here that 'tsk' is not 142d5996b2fSRussell King * running on another CPU? For now, ignore it as we 143d5996b2fSRussell King * can't guarantee we won't explode. 144f76e9154SNicolas Pitre */ 145d5996b2fSRussell King return; 146f76e9154SNicolas Pitre #else 1472d7c11bfSCatalin Marinas frame.fp = thread_saved_fp(tsk); 1482d7c11bfSCatalin Marinas frame.sp = thread_saved_sp(tsk); 1492d7c11bfSCatalin Marinas frame.lr = 0; /* recovered from the stack */ 1502d7c11bfSCatalin Marinas frame.pc = thread_saved_pc(tsk); 151f76e9154SNicolas Pitre #endif 152f76e9154SNicolas Pitre } else { 1533683f44cSRussell King /* We don't want this function nor the caller */ 1543683f44cSRussell King data.skip += 2; 1552d7c11bfSCatalin Marinas frame.fp = (unsigned long)__builtin_frame_address(0); 15674dbeee0SBehan Webster frame.sp = current_stack_pointer; 1572d7c11bfSCatalin Marinas frame.lr = (unsigned long)__builtin_return_address(0); 1583683f44cSRussell King frame.pc = (unsigned long)__save_stack_trace; 159f76e9154SNicolas Pitre } 160f16fb1ecSRussell King 1612d7c11bfSCatalin Marinas walk_stackframe(&frame, save_trace, &data); 162f76e9154SNicolas Pitre } 163f76e9154SNicolas Pitre 1649c986661SLin Yongting void save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace) 1659c986661SLin Yongting { 1669c986661SLin Yongting struct stack_trace_data data; 1679c986661SLin Yongting struct stackframe frame; 1689c986661SLin Yongting 1699c986661SLin Yongting data.trace = trace; 1709c986661SLin Yongting data.skip = trace->skip; 1719c986661SLin Yongting data.no_sched_functions = 0; 1729c986661SLin Yongting 1739c986661SLin Yongting frame.fp = regs->ARM_fp; 1749c986661SLin Yongting frame.sp = regs->ARM_sp; 1759c986661SLin Yongting frame.lr = regs->ARM_lr; 1769c986661SLin Yongting frame.pc = regs->ARM_pc; 1779c986661SLin Yongting 1789c986661SLin Yongting walk_stackframe(&frame, save_trace, &data); 1799c986661SLin Yongting } 1809c986661SLin Yongting 1813683f44cSRussell King void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) 1823683f44cSRussell King { 1833683f44cSRussell King __save_stack_trace(tsk, trace, 1); 1843683f44cSRussell King } 1859a3dc318SDustin Brown EXPORT_SYMBOL(save_stack_trace_tsk); 1863683f44cSRussell King 187f76e9154SNicolas Pitre void save_stack_trace(struct stack_trace *trace) 188f76e9154SNicolas Pitre { 1893683f44cSRussell King __save_stack_trace(current, trace, 0); 190f16fb1ecSRussell King } 1917b4c9505SIngo Molnar EXPORT_SYMBOL_GPL(save_stack_trace); 192f16fb1ecSRussell King #endif 193