stacktrace.c (8632987380765dee716d460640aa58d58d52998e) stacktrace.c (1614b2b11fab29dd4ff31ebba9d266961f5af69e)
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Stack tracing support
4 *
5 * Copyright (C) 2012 ARM Ltd.
6 */
7#include <linux/kernel.h>
8#include <linux/export.h>

--- 24 unchanged lines hidden (view full) ---

33 */
34
35
36void start_backtrace(struct stackframe *frame, unsigned long fp,
37 unsigned long pc)
38{
39 frame->fp = fp;
40 frame->pc = pc;
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Stack tracing support
4 *
5 * Copyright (C) 2012 ARM Ltd.
6 */
7#include <linux/kernel.h>
8#include <linux/export.h>

--- 24 unchanged lines hidden (view full) ---

33 */
34
35
36void start_backtrace(struct stackframe *frame, unsigned long fp,
37 unsigned long pc)
38{
39 frame->fp = fp;
40 frame->pc = pc;
41#ifdef CONFIG_FUNCTION_GRAPH_TRACER
42 frame->graph = 0;
43#endif
44#ifdef CONFIG_KRETPROBES
45 frame->kr_cur = NULL;
46#endif
47
48 /*
49 * Prime the first unwind.
50 *
51 * In unwind_frame() we'll check that the FP points to a valid stack,

--- 59 unchanged lines hidden (view full) ---

111 * Record this frame record's values and location. The prev_fp and
112 * prev_type are only meaningful to the next unwind_frame() invocation.
113 */
114 frame->fp = READ_ONCE_NOCHECK(*(unsigned long *)(fp));
115 frame->pc = READ_ONCE_NOCHECK(*(unsigned long *)(fp + 8));
116 frame->prev_fp = fp;
117 frame->prev_type = info.type;
118
41#ifdef CONFIG_KRETPROBES
42 frame->kr_cur = NULL;
43#endif
44
45 /*
46 * Prime the first unwind.
47 *
48 * In unwind_frame() we'll check that the FP points to a valid stack,

--- 59 unchanged lines hidden (view full) ---

108 * Record this frame record's values and location. The prev_fp and
109 * prev_type are only meaningful to the next unwind_frame() invocation.
110 */
111 frame->fp = READ_ONCE_NOCHECK(*(unsigned long *)(fp));
112 frame->pc = READ_ONCE_NOCHECK(*(unsigned long *)(fp + 8));
113 frame->prev_fp = fp;
114 frame->prev_type = info.type;
115
116 frame->pc = ptrauth_strip_insn_pac(frame->pc);
117
119#ifdef CONFIG_FUNCTION_GRAPH_TRACER
120 if (tsk->ret_stack &&
118#ifdef CONFIG_FUNCTION_GRAPH_TRACER
119 if (tsk->ret_stack &&
121 (ptrauth_strip_insn_pac(frame->pc) == (unsigned long)return_to_handler)) {
122 struct ftrace_ret_stack *ret_stack;
120 (frame->pc == (unsigned long)return_to_handler)) {
121 unsigned long orig_pc;
123 /*
124 * This is a case where function graph tracer has
125 * modified a return address (LR) in a stack frame
126 * to hook a function return.
127 * So replace it to an original value.
128 */
122 /*
123 * This is a case where function graph tracer has
124 * modified a return address (LR) in a stack frame
125 * to hook a function return.
126 * So replace it to an original value.
127 */
129 ret_stack = ftrace_graph_get_ret_stack(tsk, frame->graph++);
130 if (WARN_ON_ONCE(!ret_stack))
128 orig_pc = ftrace_graph_ret_addr(tsk, NULL, frame->pc,
129 (void *)frame->fp);
130 if (WARN_ON_ONCE(frame->pc == orig_pc))
131 return -EINVAL;
131 return -EINVAL;
132 frame->pc = ret_stack->ret;
132 frame->pc = orig_pc;
133 }
134#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
135#ifdef CONFIG_KRETPROBES
136 if (is_kretprobe_trampoline(frame->pc))
137 frame->pc = kretprobe_find_ret_addr(tsk, (void *)frame->fp, &frame->kr_cur);
138#endif
139
133 }
134#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
135#ifdef CONFIG_KRETPROBES
136 if (is_kretprobe_trampoline(frame->pc))
137 frame->pc = kretprobe_find_ret_addr(tsk, (void *)frame->fp, &frame->kr_cur);
138#endif
139
140 frame->pc = ptrauth_strip_insn_pac(frame->pc);
141
142 return 0;
143}
144NOKPROBE_SYMBOL(unwind_frame);
145
146void notrace walk_stackframe(struct task_struct *tsk, struct stackframe *frame,
147 bool (*fn)(void *, unsigned long), void *data)
148{
149 while (1) {

--- 68 unchanged lines hidden (view full) ---

218}
219
220void show_stack(struct task_struct *tsk, unsigned long *sp, const char *loglvl)
221{
222 dump_backtrace(NULL, tsk, loglvl);
223 barrier();
224}
225
140 return 0;
141}
142NOKPROBE_SYMBOL(unwind_frame);
143
144void notrace walk_stackframe(struct task_struct *tsk, struct stackframe *frame,
145 bool (*fn)(void *, unsigned long), void *data)
146{
147 while (1) {

--- 68 unchanged lines hidden (view full) ---

216}
217
218void show_stack(struct task_struct *tsk, unsigned long *sp, const char *loglvl)
219{
220 dump_backtrace(NULL, tsk, loglvl);
221 barrier();
222}
223
226#ifdef CONFIG_STACKTRACE
227
228noinline notrace void arch_stack_walk(stack_trace_consume_fn consume_entry,
229 void *cookie, struct task_struct *task,
230 struct pt_regs *regs)
231{
232 struct stackframe frame;
233
234 if (regs)
235 start_backtrace(&frame, regs->regs[29], regs->pc);
236 else if (task == current)
237 start_backtrace(&frame,
238 (unsigned long)__builtin_frame_address(1),
239 (unsigned long)__builtin_return_address(0));
240 else
241 start_backtrace(&frame, thread_saved_fp(task),
242 thread_saved_pc(task));
243
244 walk_stackframe(task, &frame, consume_entry, cookie);
245}
224noinline notrace void arch_stack_walk(stack_trace_consume_fn consume_entry,
225 void *cookie, struct task_struct *task,
226 struct pt_regs *regs)
227{
228 struct stackframe frame;
229
230 if (regs)
231 start_backtrace(&frame, regs->regs[29], regs->pc);
232 else if (task == current)
233 start_backtrace(&frame,
234 (unsigned long)__builtin_frame_address(1),
235 (unsigned long)__builtin_return_address(0));
236 else
237 start_backtrace(&frame, thread_saved_fp(task),
238 thread_saved_pc(task));
239
240 walk_stackframe(task, &frame, consume_entry, cookie);
241}
246
247#endif