0001
0002
0003
0004
0005
0006
0007 #include <linux/sched.h>
0008 #include <linux/sched/debug.h>
0009 #include <linux/sched/task_stack.h>
0010 #include <linux/stacktrace.h>
0011 #include <linux/export.h>
0012 #include <asm/stacktrace.h>
0013
0014
0015
0016
0017 static void save_raw_context_stack(struct stack_trace *trace,
0018 unsigned long reg29, int savesched)
0019 {
0020 unsigned long *sp = (unsigned long *)reg29;
0021 unsigned long addr;
0022
0023 while (!kstack_end(sp)) {
0024 addr = *sp++;
0025 if (__kernel_text_address(addr) &&
0026 (savesched || !in_sched_functions(addr))) {
0027 if (trace->skip > 0)
0028 trace->skip--;
0029 else
0030 trace->entries[trace->nr_entries++] = addr;
0031 if (trace->nr_entries >= trace->max_entries)
0032 break;
0033 }
0034 }
0035 }
0036
0037 static void save_context_stack(struct stack_trace *trace,
0038 struct task_struct *tsk, struct pt_regs *regs, int savesched)
0039 {
0040 unsigned long sp = regs->regs[29];
0041 #ifdef CONFIG_KALLSYMS
0042 unsigned long ra = regs->regs[31];
0043 unsigned long pc = regs->cp0_epc;
0044
0045 if (raw_show_trace || !__kernel_text_address(pc)) {
0046 unsigned long stack_page =
0047 (unsigned long)task_stack_page(tsk);
0048 if (stack_page && sp >= stack_page &&
0049 sp <= stack_page + THREAD_SIZE - 32)
0050 save_raw_context_stack(trace, sp, savesched);
0051 return;
0052 }
0053 do {
0054 if (savesched || !in_sched_functions(pc)) {
0055 if (trace->skip > 0)
0056 trace->skip--;
0057 else
0058 trace->entries[trace->nr_entries++] = pc;
0059 if (trace->nr_entries >= trace->max_entries)
0060 break;
0061 }
0062 pc = unwind_stack(tsk, &sp, pc, &ra);
0063 } while (pc);
0064 #else
0065 save_raw_context_stack(trace, sp, savesched);
0066 #endif
0067 }
0068
0069
0070
0071
0072 void save_stack_trace(struct stack_trace *trace)
0073 {
0074 save_stack_trace_tsk(current, trace);
0075 }
0076 EXPORT_SYMBOL_GPL(save_stack_trace);
0077
0078 void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
0079 {
0080 struct pt_regs dummyregs;
0081 struct pt_regs *regs = &dummyregs;
0082
0083 WARN_ON(trace->nr_entries || !trace->max_entries);
0084
0085 if (tsk != current) {
0086 regs->regs[29] = tsk->thread.reg29;
0087 regs->regs[31] = 0;
0088 regs->cp0_epc = tsk->thread.reg31;
0089 } else
0090 prepare_frametrace(regs);
0091 save_context_stack(trace, tsk, regs, tsk == current);
0092 }
0093 EXPORT_SYMBOL_GPL(save_stack_trace_tsk);