1 // SPDX-License-Identifier: GPL-2.0-only 1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 2 /* 3 * stacktrace.c : stacktracing APIs neede !! 3 * Stack trace management functions 4 * (wrappers over ARC dwa << 5 * 4 * 6 * Copyright (C) 2004, 2007-2010, 2011-2012 Sy !! 5 * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp> 7 * << 8 * vineetg: aug 2009 << 9 * -Implemented CONFIG_STACKTRACE APIs, prima << 10 * for displaying task's kernel mode call st << 11 * -Iterator based approach to have single co << 12 * needing unwinding, implement the logic in << 13 * = which frame onwards to start capture << 14 * = which frame to stop capturing (wchan << 15 * = specifics of data structs where trac << 16 * << 17 * vineetg: March 2009 << 18 * -Implemented correct versions of thread_sa << 19 * << 20 * rajeshwarr: 2008 << 21 * -Initial implementation << 22 */ 6 */ 23 !! 7 #include <linux/sched.h> 24 #include <linux/ptrace.h> << 25 #include <linux/export.h> << 26 #include <linux/stacktrace.h> << 27 #include <linux/kallsyms.h> << 28 #include <linux/sched/debug.h> 8 #include <linux/sched/debug.h> 29 !! 9 #include <linux/sched/task_stack.h> 30 #include <asm/arcregs.h> !! 10 #include <linux/stacktrace.h> 31 #include <asm/unwind.h> !! 11 #include <linux/export.h> 32 #include <asm/stacktrace.h> 12 #include <asm/stacktrace.h> 33 #include <asm/switch_to.h> << 34 13 35 /*-------------------------------------------- !! 14 /* 36 * Unwinder Iterator !! 15 * Save stack-backtrace addresses into a stack_trace buffer: 37 *-------------------------------------------- << 38 */ 16 */ 39 !! 17 static void save_raw_context_stack(struct stack_trace *trace, 40 #ifdef CONFIG_ARC_DW2_UNWIND !! 18 unsigned long reg29, int savesched) 41 << 42 static int << 43 seed_unwind_frame_info(struct task_struct *tsk << 44 struct unwind_frame_inf << 45 { 19 { 46 if (regs) { !! 20 unsigned long *sp = (unsigned long *)reg29; 47 /* !! 21 unsigned long addr; 48 * Asynchronous unwinding of i << 49 * - Just uses the pt_regs pa << 50 */ << 51 frame_info->task = tsk; << 52 << 53 frame_info->regs.r27 = regs->f << 54 frame_info->regs.r28 = regs->s << 55 frame_info->regs.r31 = regs->b << 56 frame_info->regs.r63 = regs->r << 57 frame_info->call_frame = 0; << 58 } else if (tsk == NULL || tsk == curre << 59 /* << 60 * synchronous unwinding (e.g. << 61 * - uses current values of S << 62 */ << 63 unsigned long fp, sp, blink, r << 64 frame_info->task = current; << 65 << 66 __asm__ __volatile__( << 67 "mov %0,r27\n\t" << 68 "mov %1,r28\n\t" << 69 "mov %2,r31\n\t" << 70 "mov %3,r63\n\t" << 71 : "=r"(fp), "=r"(sp), << 72 ); << 73 << 74 frame_info->regs.r27 = fp; << 75 frame_info->regs.r28 = sp; << 76 frame_info->regs.r31 = blink; << 77 frame_info->regs.r63 = ret; << 78 frame_info->call_frame = 0; << 79 } else { << 80 /* << 81 * Asynchronous unwinding of a << 82 * - first ensure it is actua << 83 * - if so, it will be in __s << 84 * is safe-kept and BLINK a << 85 */ << 86 << 87 if (task_is_running(tsk)) << 88 return -1; << 89 << 90 frame_info->task = tsk; << 91 << 92 frame_info->regs.r27 = TSK_K_F << 93 frame_info->regs.r28 = TSK_K_E << 94 frame_info->regs.r31 = TSK_K_B << 95 frame_info->regs.r63 = (unsign << 96 << 97 /* In the prologue of __switch << 98 * and then SP is copied to FP << 99 * but we didn't save FP. The << 100 * state in previous frame. << 101 * As a work around for this, << 102 * and adjust SP accordingly. << 103 * __switch_to macro is dwarf << 104 * assembly code << 105 */ << 106 frame_info->regs.r27 = 0; << 107 frame_info->regs.r28 += 60; << 108 frame_info->call_frame = 0; << 109 22 >> 23 while (!kstack_end(sp)) { >> 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 } 110 } 34 } 111 return 0; << 112 } 35 } 113 36 114 #endif !! 37 static void save_context_stack(struct stack_trace *trace, 115 !! 38 struct task_struct *tsk, struct pt_regs *regs, int savesched) 116 notrace noinline unsigned int << 117 arc_unwind_core(struct task_struct *tsk, struc << 118 int (*consumer_fn) (unsigned i << 119 { 39 { 120 #ifdef CONFIG_ARC_DW2_UNWIND !! 40 unsigned long sp = regs->regs[29]; 121 int ret = 0, cnt = 0; !! 41 #ifdef CONFIG_KALLSYMS 122 unsigned int address; !! 42 unsigned long ra = regs->regs[31]; 123 struct unwind_frame_info frame_info; !! 43 unsigned long pc = regs->cp0_epc; 124 !! 44 125 if (seed_unwind_frame_info(tsk, regs, !! 45 if (raw_show_trace || !__kernel_text_address(pc)) { 126 return 0; !! 46 unsigned long stack_page = 127 !! 47 (unsigned long)task_stack_page(tsk); 128 while (1) { !! 48 if (stack_page && sp >= stack_page && 129 address = UNW_PC(&frame_info); !! 49 sp <= stack_page + THREAD_SIZE - 32) 130 !! 50 save_raw_context_stack(trace, sp, savesched); 131 if (!address || !__kernel_text !! 51 return; 132 break; << 133 << 134 if (consumer_fn(address, arg) << 135 break; << 136 << 137 ret = arc_unwind(&frame_info); << 138 if (ret) << 139 break; << 140 << 141 frame_info.regs.r63 = frame_in << 142 << 143 if (cnt++ > 128) { << 144 printk("unwinder loopi << 145 return 0; << 146 } << 147 } 52 } 148 !! 53 do { 149 return address; /* return the !! 54 if (savesched || !in_sched_functions(pc)) { >> 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); 150 #else 64 #else 151 /* On ARC, only Dward based unwinder w !! 65 save_raw_context_stack(trace, sp, savesched); 152 * not possible (-fno-omit-frame-point << 153 * prologue is setup (callee regs save << 154 * way around << 155 */ << 156 pr_warn_once("CONFIG_ARC_DW2_UNWIND ne << 157 return 0; << 158 << 159 #endif << 160 } << 161 << 162 /*-------------------------------------------- << 163 * callbacks called by unwinder iterator to im << 164 * << 165 * The callback can return -1 to force the ite << 166 * keeps going till the bottom-most frame. << 167 *-------------------------------------------- << 168 */ << 169 << 170 /* Call-back which plugs into unwinding core t << 171 * case of panic/OOPs/BUG etc << 172 */ << 173 static int __print_sym(unsigned int address, v << 174 { << 175 const char *loglvl = arg; << 176 << 177 printk("%s %pS\n", loglvl, (void *)ad << 178 return 0; << 179 } << 180 << 181 #ifdef CONFIG_STACKTRACE << 182 << 183 /* Call-back which plugs into unwinding core t << 184 * traces needed by kernel on /proc/<pid>/stac << 185 */ << 186 static int __collect_all(unsigned int address, << 187 { << 188 struct stack_trace *trace = arg; << 189 << 190 if (trace->skip > 0) << 191 trace->skip--; << 192 else << 193 trace->entries[trace->nr_entri << 194 << 195 if (trace->nr_entries >= trace->max_en << 196 return -1; << 197 << 198 return 0; << 199 } << 200 << 201 static int __collect_all_but_sched(unsigned in << 202 { << 203 struct stack_trace *trace = arg; << 204 << 205 if (in_sched_functions(address)) << 206 return 0; << 207 << 208 if (trace->skip > 0) << 209 trace->skip--; << 210 else << 211 trace->entries[trace->nr_entri << 212 << 213 if (trace->nr_entries >= trace->max_en << 214 return -1; << 215 << 216 return 0; << 217 } << 218 << 219 #endif 66 #endif 220 << 221 static int __get_first_nonsched(unsigned int a << 222 { << 223 if (in_sched_functions(address)) << 224 return 0; << 225 << 226 return -1; << 227 } 67 } 228 68 229 /*-------------------------------------------- !! 69 /* 230 * APIs expected by various kerne !! 70 * Save stack-backtrace addresses into a stack_trace buffer. 231 *-------------------------------------------- << 232 */ << 233 << 234 noinline void show_stacktrace(struct task_stru << 235 const char *logl << 236 { << 237 printk("%s\nStack Trace:\n", loglvl); << 238 arc_unwind_core(tsk, regs, __print_sym << 239 } << 240 EXPORT_SYMBOL(show_stacktrace); << 241 << 242 /* Expected by sched Code */ << 243 void show_stack(struct task_struct *tsk, unsig << 244 { << 245 show_stacktrace(tsk, NULL, loglvl); << 246 } << 247 << 248 /* Another API expected by schedular, shows up << 249 * Of course just returning schedule( ) would << 250 * the function is not in schedular code << 251 */ 71 */ 252 unsigned int __get_wchan(struct task_struct *t !! 72 void save_stack_trace(struct stack_trace *trace) 253 { 73 { 254 return arc_unwind_core(tsk, NULL, __ge !! 74 save_stack_trace_tsk(current, trace); 255 } 75 } >> 76 EXPORT_SYMBOL_GPL(save_stack_trace); 256 77 257 #ifdef CONFIG_STACKTRACE << 258 << 259 /* << 260 * API required by CONFIG_STACKTRACE, CONFIG_L << 261 * A typical use is when /proc/<pid>/stack is << 262 */ << 263 void save_stack_trace_tsk(struct task_struct * 78 void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) 264 { 79 { 265 /* Assumes @tsk is sleeping so unwinds !! 80 struct pt_regs dummyregs; 266 arc_unwind_core(tsk, NULL, __collect_a !! 81 struct pt_regs *regs = &dummyregs; 267 } << 268 82 269 void save_stack_trace(struct stack_trace *trac !! 83 WARN_ON(trace->nr_entries || !trace->max_entries); 270 { !! 84 271 /* Pass NULL for task so it unwinds th !! 85 if (tsk != current) { 272 arc_unwind_core(NULL, NULL, __collect_ !! 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); 273 } 92 } 274 EXPORT_SYMBOL_GPL(save_stack_trace); !! 93 EXPORT_SYMBOL_GPL(save_stack_trace_tsk); 275 #endif << 276 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.