1 // SPDX-License-Identifier: GPL-2.0-only 2 #include <linux/export.h> 3 #include <linux/kprobes.h> 4 #include <linux/sched.h> 5 #include <linux/sched/debug.h> 6 #include <linux/stacktrace.h> 7 8 #include <asm/sections.h> 9 #include <asm/stacktrace.h> 10 #include <asm/traps.h> 11 12 #include "reboot.h" 13 14 #if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND) 15 /* 16 * Unwind the current stack frame and store the new register values in the 17 * structure passed as argument. Unwinding is equivalent to a function return, 18 * hence the new PC value rather than LR should be used for backtrace. 19 * 20 * With framepointer enabled, a simple function prologue looks like this: 21 * mov ip, sp 22 * stmdb sp!, {fp, ip, lr, pc} 23 * sub fp, ip, #4 24 * 25 * A simple function epilogue looks like this: 26 * ldm sp, {fp, sp, pc} 27 * 28 * When compiled with clang, pc and sp are not pushed. A simple function 29 * prologue looks like this when built with clang: 30 * 31 * stmdb {..., fp, lr} 32 * add fp, sp, #x 33 * sub sp, sp, #y 34 * 35 * A simple function epilogue looks like this when built with clang: 36 * 37 * sub sp, fp, #x 38 * ldm {..., fp, pc} 39 * 40 * 41 * Note that with framepointer enabled, even the leaf functions have the same 42 * prologue and epilogue, therefore we can ignore the LR value in this case. 43 */ 44 45 extern unsigned long call_with_stack_end; 46 47 static int frame_pointer_check(struct stackframe *frame) 48 { 49 unsigned long high, low; 50 unsigned long fp = frame->fp; 51 unsigned long pc = frame->pc; 52 53 /* 54 * call_with_stack() is the only place we allow SP to jump from one 55 * stack to another, with FP and SP pointing to different stacks, 56 * skipping the FP boundary check at this point. 57 */ 58 if (pc >= (unsigned long)&call_with_stack && 59 pc < (unsigned long)&call_with_stack_end) 60 return 0; 61 62 /* only go to a higher address on the stack */ 63 low = frame->sp; 64 high = ALIGN(low, THREAD_SIZE); 65 66 /* check current frame pointer is within bounds */ 67 #ifdef CONFIG_CC_IS_CLANG 68 if (fp < low + 4 || fp > high - 4) 69 return -EINVAL; 70 #else 71 if (fp < low + 12 || fp > high - 4) 72 return -EINVAL; 73 #endif 74 75 return 0; 76 } 77 78 int notrace unwind_frame(struct stackframe *frame) 79 { 80 unsigned long fp = frame->fp; 81 82 if (frame_pointer_check(frame)) 83 return -EINVAL; 84 85 /* restore the registers from the stack frame */ 86 #ifdef CONFIG_CC_IS_CLANG 87 frame->sp = frame->fp; 88 frame->fp = READ_ONCE_NOCHECK(*(unsigned long *)(fp)); 89 frame->pc = READ_ONCE_NOCHECK(*(unsigned long *)(fp + 4)); 90 #else 91 frame->fp = READ_ONCE_NOCHECK(*(unsigned long *)(fp - 12)); 92 frame->sp = READ_ONCE_NOCHECK(*(unsigned long *)(fp - 8)); 93 frame->pc = READ_ONCE_NOCHECK(*(unsigned long *)(fp - 4)); 94 #endif 95 #ifdef CONFIG_KRETPROBES 96 if (is_kretprobe_trampoline(frame->pc)) 97 frame->pc = kretprobe_find_ret_addr(frame->tsk, 98 (void *)frame->fp, &frame->kr_cur); 99 #endif 100 101 return 0; 102 } 103 #endif 104 105 void notrace walk_stackframe(struct stackframe *frame, 106 int (*fn)(struct stackframe *, void *), void *data) 107 { 108 while (1) { 109 int ret; 110 111 if (fn(frame, data)) 112 break; 113 ret = unwind_frame(frame); 114 if (ret < 0) 115 break; 116 } 117 } 118 EXPORT_SYMBOL(walk_stackframe); 119 120 #ifdef CONFIG_STACKTRACE 121 struct stack_trace_data { 122 struct stack_trace *trace; 123 unsigned int no_sched_functions; 124 unsigned int skip; 125 }; 126 127 static int save_trace(struct stackframe *frame, void *d) 128 { 129 struct stack_trace_data *data = d; 130 struct stack_trace *trace = data->trace; 131 struct pt_regs *regs; 132 unsigned long addr = frame->pc; 133 134 if (data->no_sched_functions && in_sched_functions(addr)) 135 return 0; 136 if (data->skip) { 137 data->skip--; 138 return 0; 139 } 140 141 trace->entries[trace->nr_entries++] = addr; 142 143 if (trace->nr_entries >= trace->max_entries) 144 return 1; 145 146 if (!in_entry_text(frame->pc)) 147 return 0; 148 149 regs = (struct pt_regs *)frame->sp; 150 if ((unsigned long)®s[1] > ALIGN(frame->sp, THREAD_SIZE)) 151 return 0; 152 153 trace->entries[trace->nr_entries++] = regs->ARM_pc; 154 155 return trace->nr_entries >= trace->max_entries; 156 } 157 158 /* This must be noinline to so that our skip calculation works correctly */ 159 static noinline void __save_stack_trace(struct task_struct *tsk, 160 struct stack_trace *trace, unsigned int nosched) 161 { 162 struct stack_trace_data data; 163 struct stackframe frame; 164 165 data.trace = trace; 166 data.skip = trace->skip; 167 data.no_sched_functions = nosched; 168 169 if (tsk != current) { 170 #ifdef CONFIG_SMP 171 /* 172 * What guarantees do we have here that 'tsk' is not 173 * running on another CPU? For now, ignore it as we 174 * can't guarantee we won't explode. 175 */ 176 return; 177 #else 178 frame.fp = thread_saved_fp(tsk); 179 frame.sp = thread_saved_sp(tsk); 180 frame.lr = 0; /* recovered from the stack */ 181 frame.pc = thread_saved_pc(tsk); 182 #endif 183 } else { 184 /* We don't want this function nor the caller */ 185 data.skip += 2; 186 frame.fp = (unsigned long)__builtin_frame_address(0); 187 frame.sp = current_stack_pointer; 188 frame.lr = (unsigned long)__builtin_return_address(0); 189 here: 190 frame.pc = (unsigned long)&&here; 191 } 192 #ifdef CONFIG_KRETPROBES 193 frame.kr_cur = NULL; 194 frame.tsk = tsk; 195 #endif 196 197 walk_stackframe(&frame, save_trace, &data); 198 } 199 200 void save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace) 201 { 202 struct stack_trace_data data; 203 struct stackframe frame; 204 205 data.trace = trace; 206 data.skip = trace->skip; 207 data.no_sched_functions = 0; 208 209 frame.fp = regs->ARM_fp; 210 frame.sp = regs->ARM_sp; 211 frame.lr = regs->ARM_lr; 212 frame.pc = regs->ARM_pc; 213 #ifdef CONFIG_KRETPROBES 214 frame.kr_cur = NULL; 215 frame.tsk = current; 216 #endif 217 218 walk_stackframe(&frame, save_trace, &data); 219 } 220 221 void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) 222 { 223 __save_stack_trace(tsk, trace, 1); 224 } 225 EXPORT_SYMBOL(save_stack_trace_tsk); 226 227 void save_stack_trace(struct stack_trace *trace) 228 { 229 __save_stack_trace(current, trace, 0); 230 } 231 EXPORT_SYMBOL_GPL(save_stack_trace); 232 #endif 233