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 /* 86 * When we unwind through an exception stack, include the saved PC 87 * value into the stack trace. 88 */ 89 if (frame->ex_frame) { 90 struct pt_regs *regs = (struct pt_regs *)frame->sp; 91 92 /* 93 * We check that 'regs + sizeof(struct pt_regs)' (that is, 94 * ®s[1]) does not exceed the bottom of the stack to avoid 95 * accessing data outside the task's stack. This may happen 96 * when frame->ex_frame is a false positive. 97 */ 98 if ((unsigned long)®s[1] > ALIGN(frame->sp, THREAD_SIZE)) 99 return -EINVAL; 100 101 frame->pc = regs->ARM_pc; 102 frame->ex_frame = false; 103 return 0; 104 } 105 106 /* restore the registers from the stack frame */ 107 #ifdef CONFIG_CC_IS_CLANG 108 frame->sp = frame->fp; 109 frame->fp = READ_ONCE_NOCHECK(*(unsigned long *)(fp)); 110 frame->pc = READ_ONCE_NOCHECK(*(unsigned long *)(fp + 4)); 111 #else 112 frame->fp = READ_ONCE_NOCHECK(*(unsigned long *)(fp - 12)); 113 frame->sp = READ_ONCE_NOCHECK(*(unsigned long *)(fp - 8)); 114 frame->pc = READ_ONCE_NOCHECK(*(unsigned long *)(fp - 4)); 115 #endif 116 #ifdef CONFIG_KRETPROBES 117 if (is_kretprobe_trampoline(frame->pc)) 118 frame->pc = kretprobe_find_ret_addr(frame->tsk, 119 (void *)frame->fp, &frame->kr_cur); 120 #endif 121 122 if (in_entry_text(frame->pc)) 123 frame->ex_frame = true; 124 125 return 0; 126 } 127 #endif 128 129 void notrace walk_stackframe(struct stackframe *frame, 130 int (*fn)(struct stackframe *, void *), void *data) 131 { 132 while (1) { 133 int ret; 134 135 if (fn(frame, data)) 136 break; 137 ret = unwind_frame(frame); 138 if (ret < 0) 139 break; 140 } 141 } 142 EXPORT_SYMBOL(walk_stackframe); 143 144 #ifdef CONFIG_STACKTRACE 145 struct stack_trace_data { 146 struct stack_trace *trace; 147 unsigned int no_sched_functions; 148 unsigned int skip; 149 }; 150 151 static int save_trace(struct stackframe *frame, void *d) 152 { 153 struct stack_trace_data *data = d; 154 struct stack_trace *trace = data->trace; 155 unsigned long addr = frame->pc; 156 157 if (data->no_sched_functions && in_sched_functions(addr)) 158 return 0; 159 if (data->skip) { 160 data->skip--; 161 return 0; 162 } 163 164 trace->entries[trace->nr_entries++] = addr; 165 return trace->nr_entries >= trace->max_entries; 166 } 167 168 /* This must be noinline to so that our skip calculation works correctly */ 169 static noinline void __save_stack_trace(struct task_struct *tsk, 170 struct stack_trace *trace, unsigned int nosched) 171 { 172 struct stack_trace_data data; 173 struct stackframe frame; 174 175 data.trace = trace; 176 data.skip = trace->skip; 177 data.no_sched_functions = nosched; 178 179 if (tsk != current) { 180 #ifdef CONFIG_SMP 181 /* 182 * What guarantees do we have here that 'tsk' is not 183 * running on another CPU? For now, ignore it as we 184 * can't guarantee we won't explode. 185 */ 186 return; 187 #else 188 frame.fp = thread_saved_fp(tsk); 189 frame.sp = thread_saved_sp(tsk); 190 frame.lr = 0; /* recovered from the stack */ 191 frame.pc = thread_saved_pc(tsk); 192 #endif 193 } else { 194 /* We don't want this function nor the caller */ 195 data.skip += 2; 196 frame.fp = (unsigned long)__builtin_frame_address(0); 197 frame.sp = current_stack_pointer; 198 frame.lr = (unsigned long)__builtin_return_address(0); 199 here: 200 frame.pc = (unsigned long)&&here; 201 } 202 #ifdef CONFIG_KRETPROBES 203 frame.kr_cur = NULL; 204 frame.tsk = tsk; 205 #endif 206 #ifdef CONFIG_UNWINDER_FRAME_POINTER 207 frame.ex_frame = false; 208 #endif 209 210 walk_stackframe(&frame, save_trace, &data); 211 } 212 213 void save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace) 214 { 215 struct stack_trace_data data; 216 struct stackframe frame; 217 218 data.trace = trace; 219 data.skip = trace->skip; 220 data.no_sched_functions = 0; 221 222 frame.fp = regs->ARM_fp; 223 frame.sp = regs->ARM_sp; 224 frame.lr = regs->ARM_lr; 225 frame.pc = regs->ARM_pc; 226 #ifdef CONFIG_KRETPROBES 227 frame.kr_cur = NULL; 228 frame.tsk = current; 229 #endif 230 #ifdef CONFIG_UNWINDER_FRAME_POINTER 231 frame.ex_frame = in_entry_text(frame.pc); 232 #endif 233 234 walk_stackframe(&frame, save_trace, &data); 235 } 236 237 void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) 238 { 239 __save_stack_trace(tsk, trace, 1); 240 } 241 EXPORT_SYMBOL(save_stack_trace_tsk); 242 243 void save_stack_trace(struct stack_trace *trace) 244 { 245 __save_stack_trace(current, trace, 0); 246 } 247 EXPORT_SYMBOL_GPL(save_stack_trace); 248 #endif 249