1 // SPDX-License-Identifier: GPL-2.0-only
3 * Stack trace management functions
5 * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
7 #include <linux/sched.h>
8 #include <linux/sched/debug.h>
9 #include <linux/sched/task_stack.h>
10 #include <linux/stacktrace.h>
11 #include <linux/export.h>
12 #include <asm/stacktrace.h>
15 * Save stack-backtrace addresses into a stack_trace buffer:
17 static void save_raw_context_stack(struct stack_trace
*trace
,
18 unsigned long reg29
, int savesched
)
20 unsigned long *sp
= (unsigned long *)reg29
;
23 while (!kstack_end(sp
)) {
25 if (__kernel_text_address(addr
) &&
26 (savesched
|| !in_sched_functions(addr
))) {
30 trace
->entries
[trace
->nr_entries
++] = addr
;
31 if (trace
->nr_entries
>= trace
->max_entries
)
37 static void save_context_stack(struct stack_trace
*trace
,
38 struct task_struct
*tsk
, struct pt_regs
*regs
, int savesched
)
40 unsigned long sp
= regs
->regs
[29];
41 #ifdef CONFIG_KALLSYMS
42 unsigned long ra
= regs
->regs
[31];
43 unsigned long pc
= regs
->cp0_epc
;
45 if (raw_show_trace
|| !__kernel_text_address(pc
)) {
46 unsigned long stack_page
=
47 (unsigned long)task_stack_page(tsk
);
48 if (stack_page
&& sp
>= stack_page
&&
49 sp
<= stack_page
+ THREAD_SIZE
- 32)
50 save_raw_context_stack(trace
, sp
, savesched
);
54 if (savesched
|| !in_sched_functions(pc
)) {
58 trace
->entries
[trace
->nr_entries
++] = pc
;
59 if (trace
->nr_entries
>= trace
->max_entries
)
62 pc
= unwind_stack(tsk
, &sp
, pc
, &ra
);
65 save_raw_context_stack(trace
, sp
, savesched
);
70 * Save stack-backtrace addresses into a stack_trace buffer.
72 void save_stack_trace(struct stack_trace
*trace
)
74 save_stack_trace_tsk(current
, trace
);
76 EXPORT_SYMBOL_GPL(save_stack_trace
);
78 void save_stack_trace_tsk(struct task_struct
*tsk
, struct stack_trace
*trace
)
80 struct pt_regs dummyregs
;
81 struct pt_regs
*regs
= &dummyregs
;
83 WARN_ON(trace
->nr_entries
|| !trace
->max_entries
);
86 regs
->regs
[29] = tsk
->thread
.reg29
;
88 regs
->cp0_epc
= tsk
->thread
.reg31
;
90 prepare_frametrace(regs
);
91 save_context_stack(trace
, tsk
, regs
, tsk
== current
);
93 EXPORT_SYMBOL_GPL(save_stack_trace_tsk
);