root/arch/mips/kernel/stacktrace.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. save_raw_context_stack
  2. save_context_stack
  3. save_stack_trace
  4. save_stack_trace_tsk

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Stack trace management functions
   4  *
   5  *  Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
   6  */
   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>
  13 
  14 /*
  15  * Save stack-backtrace addresses into a stack_trace buffer:
  16  */
  17 static void save_raw_context_stack(struct stack_trace *trace,
  18         unsigned long reg29, int savesched)
  19 {
  20         unsigned long *sp = (unsigned long *)reg29;
  21         unsigned long addr;
  22 
  23         while (!kstack_end(sp)) {
  24                 addr = *sp++;
  25                 if (__kernel_text_address(addr) &&
  26                     (savesched || !in_sched_functions(addr))) {
  27                         if (trace->skip > 0)
  28                                 trace->skip--;
  29                         else
  30                                 trace->entries[trace->nr_entries++] = addr;
  31                         if (trace->nr_entries >= trace->max_entries)
  32                                 break;
  33                 }
  34         }
  35 }
  36 
  37 static void save_context_stack(struct stack_trace *trace,
  38         struct task_struct *tsk, struct pt_regs *regs, int savesched)
  39 {
  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;
  44 
  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);
  51                 return;
  52         }
  53         do {
  54                 if (savesched || !in_sched_functions(pc)) {
  55                         if (trace->skip > 0)
  56                                 trace->skip--;
  57                         else
  58                                 trace->entries[trace->nr_entries++] = pc;
  59                         if (trace->nr_entries >= trace->max_entries)
  60                                 break;
  61                 }
  62                 pc = unwind_stack(tsk, &sp, pc, &ra);
  63         } while (pc);
  64 #else
  65         save_raw_context_stack(trace, sp, savesched);
  66 #endif
  67 }
  68 
  69 /*
  70  * Save stack-backtrace addresses into a stack_trace buffer.
  71  */
  72 void save_stack_trace(struct stack_trace *trace)
  73 {
  74         save_stack_trace_tsk(current, trace);
  75 }
  76 EXPORT_SYMBOL_GPL(save_stack_trace);
  77 
  78 void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
  79 {
  80         struct pt_regs dummyregs;
  81         struct pt_regs *regs = &dummyregs;
  82 
  83         WARN_ON(trace->nr_entries || !trace->max_entries);
  84 
  85         if (tsk != current) {
  86                 regs->regs[29] = tsk->thread.reg29;
  87                 regs->regs[31] = 0;
  88                 regs->cp0_epc = tsk->thread.reg31;
  89         } else
  90                 prepare_frametrace(regs);
  91         save_context_stack(trace, tsk, regs, tsk == current);
  92 }
  93 EXPORT_SYMBOL_GPL(save_stack_trace_tsk);

/* [<][>][^][v][top][bottom][index][help] */