Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Stack trace management functions
0004  *
0005  *  Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
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  * Save stack-backtrace addresses into a stack_trace buffer:
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  * Save stack-backtrace addresses into a stack_trace buffer.
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);