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