stacktrace.c (5854e4d8530e6ed4c2532a71a6b0474e199d44dd) | stacktrace.c (752ec621ef5c30777958cc5eb5f1cf394f7733f4) |
---|---|
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> --- 68 unchanged lines hidden (view full) --- 77 78int notrace unwind_frame(struct stackframe *frame) 79{ 80 unsigned long fp = frame->fp; 81 82 if (frame_pointer_check(frame)) 83 return -EINVAL; 84 | 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> --- 68 unchanged lines hidden (view full) --- 77 78int 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 |
|
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 | 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 |
|
101 return 0; 102} 103#endif 104 105void notrace walk_stackframe(struct stackframe *frame, 106 int (*fn)(struct stackframe *, void *), void *data) 107{ 108 while (1) { --- 14 unchanged lines hidden (view full) --- 123 unsigned int no_sched_functions; 124 unsigned int skip; 125}; 126 127static int save_trace(struct stackframe *frame, void *d) 128{ 129 struct stack_trace_data *data = d; 130 struct stack_trace *trace = data->trace; | 125 return 0; 126} 127#endif 128 129void notrace walk_stackframe(struct stackframe *frame, 130 int (*fn)(struct stackframe *, void *), void *data) 131{ 132 while (1) { --- 14 unchanged lines hidden (view full) --- 147 unsigned int no_sched_functions; 148 unsigned int skip; 149}; 150 151static int save_trace(struct stackframe *frame, void *d) 152{ 153 struct stack_trace_data *data = d; 154 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; | 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; |
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 */ 159static noinline void __save_stack_trace(struct task_struct *tsk, 160 struct stack_trace *trace, unsigned int nosched) 161{ 162 struct stack_trace_data data; --- 25 unchanged lines hidden (view full) --- 188 frame.lr = (unsigned long)__builtin_return_address(0); 189here: 190 frame.pc = (unsigned long)&&here; 191 } 192#ifdef CONFIG_KRETPROBES 193 frame.kr_cur = NULL; 194 frame.tsk = tsk; 195#endif | 165 return trace->nr_entries >= trace->max_entries; 166} 167 168/* This must be noinline to so that our skip calculation works correctly */ 169static noinline void __save_stack_trace(struct task_struct *tsk, 170 struct stack_trace *trace, unsigned int nosched) 171{ 172 struct stack_trace_data data; --- 25 unchanged lines hidden (view full) --- 198 frame.lr = (unsigned long)__builtin_return_address(0); 199here: 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 |
|
196 197 walk_stackframe(&frame, save_trace, &data); 198} 199 200void save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace) 201{ 202 struct stack_trace_data data; 203 struct stackframe frame; --- 5 unchanged lines hidden (view full) --- 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 | 209 210 walk_stackframe(&frame, save_trace, &data); 211} 212 213void save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace) 214{ 215 struct stack_trace_data data; 216 struct stackframe frame; --- 5 unchanged lines hidden (view full) --- 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 |
|
217 218 walk_stackframe(&frame, save_trace, &data); 219} 220 221void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) 222{ 223 __save_stack_trace(tsk, trace, 1); 224} 225EXPORT_SYMBOL(save_stack_trace_tsk); 226 227void save_stack_trace(struct stack_trace *trace) 228{ 229 __save_stack_trace(current, trace, 0); 230} 231EXPORT_SYMBOL_GPL(save_stack_trace); 232#endif | 233 234 walk_stackframe(&frame, save_trace, &data); 235} 236 237void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) 238{ 239 __save_stack_trace(tsk, trace, 1); 240} 241EXPORT_SYMBOL(save_stack_trace_tsk); 242 243void save_stack_trace(struct stack_trace *trace) 244{ 245 __save_stack_trace(current, trace, 0); 246} 247EXPORT_SYMBOL_GPL(save_stack_trace); 248#endif |