1 // SPDX-License-Identifier: GPL-2.0 !! 1 // SPDX-License-Identifier: GPL-2.0-only 2 /* << 3 * arch/sh/kernel/stacktrace.c << 4 * << 5 * Stack trace management functions << 6 * << 7 * Copyright (C) 2006 - 2008 Paul Mundt << 8 */ << 9 #include <linux/sched.h> 2 #include <linux/sched.h> 10 #include <linux/sched/debug.h> 3 #include <linux/sched/debug.h> 11 #include <linux/stacktrace.h> 4 #include <linux/stacktrace.h> 12 #include <linux/thread_info.h> 5 #include <linux/thread_info.h> 13 #include <linux/module.h> !! 6 #include <linux/ftrace.h> 14 #include <asm/unwinder.h> !! 7 #include <linux/export.h> 15 #include <asm/ptrace.h> 8 #include <asm/ptrace.h> 16 #include <asm/stacktrace.h> 9 #include <asm/stacktrace.h> 17 10 18 /* !! 11 #include "kstack.h" 19 * Save stack-backtrace addresses into a stack << 20 */ << 21 static void save_stack_address(void *data, uns << 22 { << 23 struct stack_trace *trace = data; << 24 << 25 if (!reliable) << 26 return; << 27 12 28 if (trace->skip > 0) { !! 13 static void __save_stack_trace(struct thread_info *tp, 29 trace->skip--; !! 14 struct stack_trace *trace, 30 return; !! 15 bool skip_sched) >> 16 { >> 17 unsigned long ksp, fp; >> 18 #ifdef CONFIG_FUNCTION_GRAPH_TRACER >> 19 struct task_struct *t; >> 20 int graph = 0; >> 21 #endif >> 22 >> 23 if (tp == current_thread_info()) { >> 24 stack_trace_flush(); >> 25 __asm__ __volatile__("mov %%fp, %0" : "=r" (ksp)); >> 26 } else { >> 27 ksp = tp->ksp; 31 } 28 } 32 29 33 if (trace->nr_entries < trace->max_ent !! 30 fp = ksp + STACK_BIAS; 34 trace->entries[trace->nr_entri !! 31 #ifdef CONFIG_FUNCTION_GRAPH_TRACER >> 32 t = tp->task; >> 33 #endif >> 34 do { >> 35 struct sparc_stackf *sf; >> 36 struct pt_regs *regs; >> 37 unsigned long pc; >> 38 >> 39 if (!kstack_valid(tp, fp)) >> 40 break; >> 41 >> 42 sf = (struct sparc_stackf *) fp; >> 43 regs = (struct pt_regs *) (sf + 1); >> 44 >> 45 if (kstack_is_trap_frame(tp, regs)) { >> 46 if (!(regs->tstate & TSTATE_PRIV)) >> 47 break; >> 48 pc = regs->tpc; >> 49 fp = regs->u_regs[UREG_I6] + STACK_BIAS; >> 50 } else { >> 51 pc = sf->callers_pc; >> 52 fp = (unsigned long)sf->fp + STACK_BIAS; >> 53 } >> 54 >> 55 if (trace->skip > 0) >> 56 trace->skip--; >> 57 else if (!skip_sched || !in_sched_functions(pc)) { >> 58 trace->entries[trace->nr_entries++] = pc; >> 59 #ifdef CONFIG_FUNCTION_GRAPH_TRACER >> 60 if ((pc + 8UL) == (unsigned long) &return_to_handler) { >> 61 struct ftrace_ret_stack *ret_stack; >> 62 ret_stack = ftrace_graph_get_ret_stack(t, >> 63 graph); >> 64 if (ret_stack) { >> 65 pc = ret_stack->ret; >> 66 if (trace->nr_entries < >> 67 trace->max_entries) >> 68 trace->entries[trace->nr_entries++] = pc; >> 69 graph++; >> 70 } >> 71 } >> 72 #endif >> 73 } >> 74 } while (trace->nr_entries < trace->max_entries); 35 } 75 } 36 76 37 static const struct stacktrace_ops save_stack_ << 38 .address = save_stack_address, << 39 }; << 40 << 41 void save_stack_trace(struct stack_trace *trac 77 void save_stack_trace(struct stack_trace *trace) 42 { 78 { 43 unsigned long *sp = (unsigned long *)c !! 79 __save_stack_trace(current_thread_info(), trace, false); 44 << 45 unwind_stack(current, NULL, sp, &save << 46 } 80 } 47 EXPORT_SYMBOL_GPL(save_stack_trace); 81 EXPORT_SYMBOL_GPL(save_stack_trace); 48 82 49 static void << 50 save_stack_address_nosched(void *data, unsigne << 51 { << 52 struct stack_trace *trace = (struct st << 53 << 54 if (!reliable) << 55 return; << 56 << 57 if (in_sched_functions(addr)) << 58 return; << 59 << 60 if (trace->skip > 0) { << 61 trace->skip--; << 62 return; << 63 } << 64 << 65 if (trace->nr_entries < trace->max_ent << 66 trace->entries[trace->nr_entri << 67 } << 68 << 69 static const struct stacktrace_ops save_stack_ << 70 .address = save_stack_address_nosched, << 71 }; << 72 << 73 void save_stack_trace_tsk(struct task_struct * 83 void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) 74 { 84 { 75 unsigned long *sp = (unsigned long *)t !! 85 struct thread_info *tp = task_thread_info(tsk); 76 86 77 unwind_stack(current, NULL, sp, &save !! 87 __save_stack_trace(tp, trace, true); 78 } 88 } 79 EXPORT_SYMBOL_GPL(save_stack_trace_tsk); 89 EXPORT_SYMBOL_GPL(save_stack_trace_tsk); 80 90
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.