1 /* !! 1 // SPDX-License-Identifier: GPL-2.0-only 2 * Stack trace utility for OpenRISC << 3 * << 4 * Copyright (C) 2017 Stafford Horne <shorne@g << 5 * << 6 * This file is licensed under the terms of th << 7 * version 2. This program is licensed "as is << 8 * kind, whether express or implied. << 9 * << 10 * Losely based on work from sh and powerpc. << 11 */ << 12 << 13 #include <linux/export.h> << 14 #include <linux/sched.h> 2 #include <linux/sched.h> 15 #include <linux/sched/debug.h> 3 #include <linux/sched/debug.h> 16 #include <linux/sched/task_stack.h> << 17 #include <linux/stacktrace.h> 4 #include <linux/stacktrace.h> >> 5 #include <linux/thread_info.h> >> 6 #include <linux/ftrace.h> >> 7 #include <linux/export.h> >> 8 #include <asm/ptrace.h> >> 9 #include <asm/stacktrace.h> 18 10 19 #include <asm/processor.h> !! 11 #include "kstack.h" 20 #include <asm/unwinder.h> << 21 12 22 /* !! 13 static void __save_stack_trace(struct thread_info *tp, 23 * Save stack-backtrace addresses into a stack !! 14 struct stack_trace *trace, 24 */ !! 15 bool skip_sched) 25 static void << 26 save_stack_address(void *data, unsigned long a << 27 { 16 { 28 struct stack_trace *trace = data; !! 17 unsigned long ksp, fp; 29 !! 18 #ifdef CONFIG_FUNCTION_GRAPH_TRACER 30 if (!reliable) !! 19 struct task_struct *t; 31 return; !! 20 int graph = 0; 32 !! 21 #endif 33 if (trace->skip > 0) { !! 22 34 trace->skip--; !! 23 if (tp == current_thread_info()) { 35 return; !! 24 stack_trace_flush(); >> 25 __asm__ __volatile__("mov %%fp, %0" : "=r" (ksp)); >> 26 } else { >> 27 ksp = tp->ksp; 36 } 28 } 37 29 38 if (trace->nr_entries < trace->max_ent !! 30 fp = ksp + STACK_BIAS; 39 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); 40 } 75 } 41 76 42 void save_stack_trace(struct stack_trace *trac 77 void save_stack_trace(struct stack_trace *trace) 43 { 78 { 44 unwind_stack(trace, (unsigned long *) !! 79 __save_stack_trace(current_thread_info(), trace, false); 45 } 80 } 46 EXPORT_SYMBOL_GPL(save_stack_trace); 81 EXPORT_SYMBOL_GPL(save_stack_trace); 47 82 48 static void << 49 save_stack_address_nosched(void *data, unsigne << 50 { << 51 struct stack_trace *trace = (struct st << 52 << 53 if (!reliable) << 54 return; << 55 << 56 if (in_sched_functions(addr)) << 57 return; << 58 << 59 if (trace->skip > 0) { << 60 trace->skip--; << 61 return; << 62 } << 63 << 64 if (trace->nr_entries < trace->max_ent << 65 trace->entries[trace->nr_entri << 66 } << 67 << 68 void save_stack_trace_tsk(struct task_struct * 83 void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) 69 { 84 { 70 unsigned long *sp = NULL; !! 85 struct thread_info *tp = task_thread_info(tsk); 71 << 72 if (!try_get_task_stack(tsk)) << 73 return; << 74 << 75 if (tsk == current) << 76 sp = (unsigned long *) &sp; << 77 else { << 78 unsigned long ksp; << 79 << 80 /* Locate stack from kernel co << 81 ksp = task_thread_info(tsk)->k << 82 ksp += STACK_FRAME_OVERHEAD; << 83 ksp += sizeof(struct pt_regs); << 84 << 85 sp = (unsigned long *) ksp; << 86 } << 87 << 88 unwind_stack(trace, sp, save_stack_add << 89 86 90 put_task_stack(tsk); !! 87 __save_stack_trace(tp, trace, true); 91 } 88 } 92 EXPORT_SYMBOL_GPL(save_stack_trace_tsk); 89 EXPORT_SYMBOL_GPL(save_stack_trace_tsk); 93 << 94 void << 95 save_stack_trace_regs(struct pt_regs *regs, st << 96 { << 97 unwind_stack(trace, (unsigned long *) << 98 save_stack_address_nosche << 99 } << 100 EXPORT_SYMBOL_GPL(save_stack_trace_regs); << 101 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.