^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) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #include <linux/sched/debug.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include <linux/stacktrace.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/thread_info.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/ftrace.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/export.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <asm/ptrace.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <asm/stacktrace.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include "kstack.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) static void __save_stack_trace(struct thread_info *tp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) struct stack_trace *trace,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) bool skip_sched)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) unsigned long ksp, fp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #ifdef CONFIG_FUNCTION_GRAPH_TRACER
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) struct task_struct *t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) int graph = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) if (tp == current_thread_info()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) stack_trace_flush();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) __asm__ __volatile__("mov %%fp, %0" : "=r" (ksp));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) ksp = tp->ksp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) fp = ksp + STACK_BIAS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #ifdef CONFIG_FUNCTION_GRAPH_TRACER
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) t = tp->task;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) struct sparc_stackf *sf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) struct pt_regs *regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) unsigned long pc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) if (!kstack_valid(tp, fp))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) sf = (struct sparc_stackf *) fp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) regs = (struct pt_regs *) (sf + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) if (kstack_is_trap_frame(tp, regs)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) if (!(regs->tstate & TSTATE_PRIV))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) pc = regs->tpc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) fp = regs->u_regs[UREG_I6] + STACK_BIAS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) pc = sf->callers_pc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) fp = (unsigned long)sf->fp + STACK_BIAS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^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 if (!skip_sched || !in_sched_functions(pc)) {
^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) #ifdef CONFIG_FUNCTION_GRAPH_TRACER
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) if ((pc + 8UL) == (unsigned long) &return_to_handler) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) struct ftrace_ret_stack *ret_stack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) ret_stack = ftrace_graph_get_ret_stack(t,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) graph);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) if (ret_stack) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) pc = ret_stack->ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) if (trace->nr_entries <
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) trace->max_entries)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) trace->entries[trace->nr_entries++] = pc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) graph++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) } while (trace->nr_entries < trace->max_entries);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) void save_stack_trace(struct stack_trace *trace)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) __save_stack_trace(current_thread_info(), trace, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) EXPORT_SYMBOL_GPL(save_stack_trace);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) struct thread_info *tp = task_thread_info(tsk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) __save_stack_trace(tp, trace, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) EXPORT_SYMBOL_GPL(save_stack_trace_tsk);