1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2ecea4ab6SPaul Gortmaker #include <linux/export.h> 3fed240d9SMasami Hiramatsu #include <linux/kprobes.h> 4f16fb1ecSRussell King #include <linux/sched.h> 5b17b0153SIngo Molnar #include <linux/sched/debug.h> 6f16fb1ecSRussell King #include <linux/stacktrace.h> 7f16fb1ecSRussell King 8c6089061SRussell King #include <asm/sections.h> 92d7c11bfSCatalin Marinas #include <asm/stacktrace.h> 1007b40341SRussell King #include <asm/traps.h> 11f16fb1ecSRussell King 122d7c11bfSCatalin Marinas #if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND) 132d7c11bfSCatalin Marinas /* 142d7c11bfSCatalin Marinas * Unwind the current stack frame and store the new register values in the 152d7c11bfSCatalin Marinas * structure passed as argument. Unwinding is equivalent to a function return, 162d7c11bfSCatalin Marinas * hence the new PC value rather than LR should be used for backtrace. 172d7c11bfSCatalin Marinas * 182d7c11bfSCatalin Marinas * With framepointer enabled, a simple function prologue looks like this: 192d7c11bfSCatalin Marinas * mov ip, sp 202d7c11bfSCatalin Marinas * stmdb sp!, {fp, ip, lr, pc} 212d7c11bfSCatalin Marinas * sub fp, ip, #4 222d7c11bfSCatalin Marinas * 232d7c11bfSCatalin Marinas * A simple function epilogue looks like this: 242d7c11bfSCatalin Marinas * ldm sp, {fp, sp, pc} 252d7c11bfSCatalin Marinas * 26b4d5ec9bSNathan Huckleberry * When compiled with clang, pc and sp are not pushed. A simple function 27b4d5ec9bSNathan Huckleberry * prologue looks like this when built with clang: 28b4d5ec9bSNathan Huckleberry * 29b4d5ec9bSNathan Huckleberry * stmdb {..., fp, lr} 30b4d5ec9bSNathan Huckleberry * add fp, sp, #x 31b4d5ec9bSNathan Huckleberry * sub sp, sp, #y 32b4d5ec9bSNathan Huckleberry * 33b4d5ec9bSNathan Huckleberry * A simple function epilogue looks like this when built with clang: 34b4d5ec9bSNathan Huckleberry * 35b4d5ec9bSNathan Huckleberry * sub sp, fp, #x 36b4d5ec9bSNathan Huckleberry * ldm {..., fp, pc} 37b4d5ec9bSNathan Huckleberry * 38b4d5ec9bSNathan Huckleberry * 392d7c11bfSCatalin Marinas * Note that with framepointer enabled, even the leaf functions have the same 402d7c11bfSCatalin Marinas * prologue and epilogue, therefore we can ignore the LR value in this case. 412d7c11bfSCatalin Marinas */ 424bf1fa5aSUwe Kleine-König int notrace unwind_frame(struct stackframe *frame) 432d7c11bfSCatalin Marinas { 442d7c11bfSCatalin Marinas unsigned long high, low; 452d7c11bfSCatalin Marinas unsigned long fp = frame->fp; 462d7c11bfSCatalin Marinas 472d7c11bfSCatalin Marinas /* only go to a higher address on the stack */ 482d7c11bfSCatalin Marinas low = frame->sp; 49d33aadbfSWill Deacon high = ALIGN(low, THREAD_SIZE); 502d7c11bfSCatalin Marinas 51b4d5ec9bSNathan Huckleberry #ifdef CONFIG_CC_IS_CLANG 52b4d5ec9bSNathan Huckleberry /* check current frame pointer is within bounds */ 53b4d5ec9bSNathan Huckleberry if (fp < low + 4 || fp > high - 4) 54b4d5ec9bSNathan Huckleberry return -EINVAL; 55b4d5ec9bSNathan Huckleberry 56b4d5ec9bSNathan Huckleberry frame->sp = frame->fp; 57b4d5ec9bSNathan Huckleberry frame->fp = *(unsigned long *)(fp); 58b3ea5d56SMasami Hiramatsu frame->pc = *(unsigned long *)(fp + 4); 59b4d5ec9bSNathan 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); 68b4d5ec9bSNathan Huckleberry #endif 69fed240d9SMasami Hiramatsu #ifdef CONFIG_KRETPROBES 70fed240d9SMasami Hiramatsu if (is_kretprobe_trampoline(frame->pc)) 71fed240d9SMasami Hiramatsu frame->pc = kretprobe_find_ret_addr(frame->tsk, 72fed240d9SMasami Hiramatsu (void *)frame->fp, &frame->kr_cur); 73fed240d9SMasami Hiramatsu #endif 742d7c11bfSCatalin Marinas 752d7c11bfSCatalin Marinas return 0; 762d7c11bfSCatalin Marinas } 772d7c11bfSCatalin Marinas #endif 782d7c11bfSCatalin Marinas 794bf1fa5aSUwe Kleine-König void notrace walk_stackframe(struct stackframe *frame, 80f16fb1ecSRussell King int (*fn)(struct stackframe *, void *), void *data) 81f16fb1ecSRussell King { 822d7c11bfSCatalin Marinas while (1) { 832d7c11bfSCatalin Marinas int ret; 84f16fb1ecSRussell King 85f16fb1ecSRussell King if (fn(frame, data)) 86f16fb1ecSRussell King break; 872d7c11bfSCatalin Marinas ret = unwind_frame(frame); 882d7c11bfSCatalin Marinas if (ret < 0) 892d7c11bfSCatalin Marinas break; 902d7c11bfSCatalin Marinas } 91f16fb1ecSRussell King } 927b104bcbSAl Viro EXPORT_SYMBOL(walk_stackframe); 93f16fb1ecSRussell King 94f16fb1ecSRussell King #ifdef CONFIG_STACKTRACE 95f16fb1ecSRussell King struct stack_trace_data { 96f16fb1ecSRussell King struct stack_trace *trace; 97f76e9154SNicolas Pitre unsigned int no_sched_functions; 98f16fb1ecSRussell King unsigned int skip; 99f16fb1ecSRussell King }; 100f16fb1ecSRussell King 101f16fb1ecSRussell King static int save_trace(struct stackframe *frame, void *d) 102f16fb1ecSRussell King { 103f16fb1ecSRussell King struct stack_trace_data *data = d; 104f16fb1ecSRussell King struct stack_trace *trace = data->trace; 10507b40341SRussell King struct pt_regs *regs; 1062d7c11bfSCatalin Marinas unsigned long addr = frame->pc; 107f16fb1ecSRussell King 108f76e9154SNicolas Pitre if (data->no_sched_functions && in_sched_functions(addr)) 109f76e9154SNicolas Pitre return 0; 110f16fb1ecSRussell King if (data->skip) { 111f16fb1ecSRussell King data->skip--; 112f16fb1ecSRussell King return 0; 113f16fb1ecSRussell King } 114f16fb1ecSRussell King 115f76e9154SNicolas Pitre trace->entries[trace->nr_entries++] = addr; 116f16fb1ecSRussell King 11707b40341SRussell King if (trace->nr_entries >= trace->max_entries) 11807b40341SRussell King return 1; 11907b40341SRussell King 120c6089061SRussell King if (!in_entry_text(frame->pc)) 12107b40341SRussell King return 0; 12207b40341SRussell King 12307b40341SRussell King regs = (struct pt_regs *)frame->sp; 12440ff1ddbSVincent Whitchurch if ((unsigned long)®s[1] > ALIGN(frame->sp, THREAD_SIZE)) 12540ff1ddbSVincent Whitchurch return 0; 12607b40341SRussell King 12707b40341SRussell King trace->entries[trace->nr_entries++] = regs->ARM_pc; 12807b40341SRussell King 129f16fb1ecSRussell King return trace->nr_entries >= trace->max_entries; 130f16fb1ecSRussell King } 131f16fb1ecSRussell King 1323683f44cSRussell King /* This must be noinline to so that our skip calculation works correctly */ 1333683f44cSRussell King static noinline void __save_stack_trace(struct task_struct *tsk, 1343683f44cSRussell King struct stack_trace *trace, unsigned int nosched) 135f16fb1ecSRussell King { 136f16fb1ecSRussell King struct stack_trace_data data; 1372d7c11bfSCatalin Marinas struct stackframe frame; 138f16fb1ecSRussell King 139f16fb1ecSRussell King data.trace = trace; 140f16fb1ecSRussell King data.skip = trace->skip; 1413683f44cSRussell King data.no_sched_functions = nosched; 142f76e9154SNicolas Pitre 143f76e9154SNicolas Pitre if (tsk != current) { 144f76e9154SNicolas Pitre #ifdef CONFIG_SMP 145f76e9154SNicolas Pitre /* 146d5996b2fSRussell King * What guarantees do we have here that 'tsk' is not 147d5996b2fSRussell King * running on another CPU? For now, ignore it as we 148d5996b2fSRussell King * can't guarantee we won't explode. 149f76e9154SNicolas Pitre */ 150d5996b2fSRussell King return; 151f76e9154SNicolas Pitre #else 1522d7c11bfSCatalin Marinas frame.fp = thread_saved_fp(tsk); 1532d7c11bfSCatalin Marinas frame.sp = thread_saved_sp(tsk); 1542d7c11bfSCatalin Marinas frame.lr = 0; /* recovered from the stack */ 1552d7c11bfSCatalin Marinas frame.pc = thread_saved_pc(tsk); 156f76e9154SNicolas Pitre #endif 157f76e9154SNicolas Pitre } else { 1583683f44cSRussell King /* We don't want this function nor the caller */ 1593683f44cSRussell King data.skip += 2; 1602d7c11bfSCatalin Marinas frame.fp = (unsigned long)__builtin_frame_address(0); 16174dbeee0SBehan Webster frame.sp = current_stack_pointer; 1622d7c11bfSCatalin Marinas frame.lr = (unsigned long)__builtin_return_address(0); 163*c46c2c9bSRussell King (Oracle) here: 164*c46c2c9bSRussell King (Oracle) frame.pc = (unsigned long)&&here; 165f76e9154SNicolas Pitre } 166fed240d9SMasami Hiramatsu #ifdef CONFIG_KRETPROBES 167fed240d9SMasami Hiramatsu frame.kr_cur = NULL; 168fed240d9SMasami Hiramatsu frame.tsk = tsk; 169fed240d9SMasami Hiramatsu #endif 170f16fb1ecSRussell King 1712d7c11bfSCatalin Marinas walk_stackframe(&frame, save_trace, &data); 172f76e9154SNicolas Pitre } 173f76e9154SNicolas Pitre 1749c986661SLin Yongting void save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace) 1759c986661SLin Yongting { 1769c986661SLin Yongting struct stack_trace_data data; 1779c986661SLin Yongting struct stackframe frame; 1789c986661SLin Yongting 1799c986661SLin Yongting data.trace = trace; 1809c986661SLin Yongting data.skip = trace->skip; 1819c986661SLin Yongting data.no_sched_functions = 0; 1829c986661SLin Yongting 1839c986661SLin Yongting frame.fp = regs->ARM_fp; 1849c986661SLin Yongting frame.sp = regs->ARM_sp; 1859c986661SLin Yongting frame.lr = regs->ARM_lr; 1869c986661SLin Yongting frame.pc = regs->ARM_pc; 187fed240d9SMasami Hiramatsu #ifdef CONFIG_KRETPROBES 188fed240d9SMasami Hiramatsu frame.kr_cur = NULL; 189fed240d9SMasami Hiramatsu frame.tsk = current; 190fed240d9SMasami Hiramatsu #endif 1919c986661SLin Yongting 1929c986661SLin Yongting walk_stackframe(&frame, save_trace, &data); 1939c986661SLin Yongting } 1949c986661SLin Yongting 1953683f44cSRussell King void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) 1963683f44cSRussell King { 1973683f44cSRussell King __save_stack_trace(tsk, trace, 1); 1983683f44cSRussell King } 1999a3dc318SDustin Brown EXPORT_SYMBOL(save_stack_trace_tsk); 2003683f44cSRussell King 201f76e9154SNicolas Pitre void save_stack_trace(struct stack_trace *trace) 202f76e9154SNicolas Pitre { 2033683f44cSRussell King __save_stack_trace(current, trace, 0); 204f16fb1ecSRussell King } 2057b4c9505SIngo Molnar EXPORT_SYMBOL_GPL(save_stack_trace); 206f16fb1ecSRussell King #endif 207