linux/arch/mips/kernel/stacktrace.c
<<
>>
Prefs
   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 */
  17static 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
  37static 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 */
  72void save_stack_trace(struct stack_trace *trace)
  73{
  74        save_stack_trace_tsk(current, trace);
  75}
  76EXPORT_SYMBOL_GPL(save_stack_trace);
  77
  78void 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}
  93EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
  94