1 // SPDX-License-Identifier: GPL-2.0 !! 1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 2 /* 3 * arch/sh/kernel/stacktrace.c << 4 * << 5 * Stack trace management functions 3 * Stack trace management functions 6 * 4 * 7 * Copyright (C) 2006 - 2008 Paul Mundt !! 5 * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp> 8 */ 6 */ 9 #include <linux/sched.h> 7 #include <linux/sched.h> 10 #include <linux/sched/debug.h> 8 #include <linux/sched/debug.h> >> 9 #include <linux/sched/task_stack.h> 11 #include <linux/stacktrace.h> 10 #include <linux/stacktrace.h> 12 #include <linux/thread_info.h> !! 11 #include <linux/export.h> 13 #include <linux/module.h> << 14 #include <asm/unwinder.h> << 15 #include <asm/ptrace.h> << 16 #include <asm/stacktrace.h> 12 #include <asm/stacktrace.h> 17 13 18 /* 14 /* 19 * Save stack-backtrace addresses into a stack !! 15 * Save stack-backtrace addresses into a stack_trace buffer: 20 */ 16 */ 21 static void save_stack_address(void *data, uns !! 17 static void save_raw_context_stack(struct stack_trace *trace, >> 18 unsigned long reg29, int savesched) 22 { 19 { 23 struct stack_trace *trace = data; !! 20 unsigned long *sp = (unsigned long *)reg29; >> 21 unsigned long addr; 24 22 25 if (!reliable) !! 23 while (!kstack_end(sp)) { 26 return; !! 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 } 27 36 28 if (trace->skip > 0) { !! 37 static void save_context_stack(struct stack_trace *trace, 29 trace->skip--; !! 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); 30 return; 51 return; 31 } 52 } 32 !! 53 do { 33 if (trace->nr_entries < trace->max_ent !! 54 if (savesched || !in_sched_functions(pc)) { 34 trace->entries[trace->nr_entri !! 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 35 } 67 } 36 68 37 static const struct stacktrace_ops save_stack_ !! 69 /* 38 .address = save_stack_address, !! 70 * Save stack-backtrace addresses into a stack_trace buffer. 39 }; !! 71 */ 40 << 41 void save_stack_trace(struct stack_trace *trac 72 void save_stack_trace(struct stack_trace *trace) 42 { 73 { 43 unsigned long *sp = (unsigned long *)c !! 74 save_stack_trace_tsk(current, trace); 44 << 45 unwind_stack(current, NULL, sp, &save << 46 } 75 } 47 EXPORT_SYMBOL_GPL(save_stack_trace); 76 EXPORT_SYMBOL_GPL(save_stack_trace); 48 77 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 * 78 void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) 74 { 79 { 75 unsigned long *sp = (unsigned long *)t !! 80 struct pt_regs dummyregs; >> 81 struct pt_regs *regs = &dummyregs; >> 82 >> 83 WARN_ON(trace->nr_entries || !trace->max_entries); 76 84 77 unwind_stack(current, NULL, sp, &save !! 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); 78 } 92 } 79 EXPORT_SYMBOL_GPL(save_stack_trace_tsk); 93 EXPORT_SYMBOL_GPL(save_stack_trace_tsk); 80 94
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.