1 /* 2 * Copyright (C) 2008 ARM Limited 3 * Copyright (C) 2014 Regents of the University of California 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 */ 14 15 #include <linux/export.h> 16 #include <linux/kallsyms.h> 17 #include <linux/sched.h> 18 #include <linux/sched/debug.h> 19 #include <linux/sched/task_stack.h> 20 #include <linux/stacktrace.h> 21 #include <linux/ftrace.h> 22 23 #ifdef CONFIG_FRAME_POINTER 24 25 struct stackframe { 26 unsigned long fp; 27 unsigned long ra; 28 }; 29 30 static void notrace walk_stackframe(struct task_struct *task, 31 struct pt_regs *regs, bool (*fn)(unsigned long, void *), void *arg) 32 { 33 unsigned long fp, sp, pc; 34 35 if (regs) { 36 fp = frame_pointer(regs); 37 sp = user_stack_pointer(regs); 38 pc = instruction_pointer(regs); 39 } else if (task == NULL || task == current) { 40 const register unsigned long current_sp __asm__ ("sp"); 41 fp = (unsigned long)__builtin_frame_address(0); 42 sp = current_sp; 43 pc = (unsigned long)walk_stackframe; 44 } else { 45 /* task blocked in __switch_to */ 46 fp = task->thread.s[0]; 47 sp = task->thread.sp; 48 pc = task->thread.ra; 49 } 50 51 for (;;) { 52 unsigned long low, high; 53 struct stackframe *frame; 54 55 if (unlikely(!__kernel_text_address(pc) || fn(pc, arg))) 56 break; 57 58 /* Validate frame pointer */ 59 low = sp + sizeof(struct stackframe); 60 high = ALIGN(sp, THREAD_SIZE); 61 if (unlikely(fp < low || fp > high || fp & 0x7)) 62 break; 63 /* Unwind stack frame */ 64 frame = (struct stackframe *)fp - 1; 65 sp = fp; 66 fp = frame->fp; 67 pc = ftrace_graph_ret_addr(current, NULL, frame->ra, 68 (unsigned long *)(fp - 8)); 69 } 70 } 71 72 #else /* !CONFIG_FRAME_POINTER */ 73 74 static void notrace walk_stackframe(struct task_struct *task, 75 struct pt_regs *regs, bool (*fn)(unsigned long, void *), void *arg) 76 { 77 unsigned long sp, pc; 78 unsigned long *ksp; 79 80 if (regs) { 81 sp = user_stack_pointer(regs); 82 pc = instruction_pointer(regs); 83 } else if (task == NULL || task == current) { 84 const register unsigned long current_sp __asm__ ("sp"); 85 sp = current_sp; 86 pc = (unsigned long)walk_stackframe; 87 } else { 88 /* task blocked in __switch_to */ 89 sp = task->thread.sp; 90 pc = task->thread.ra; 91 } 92 93 if (unlikely(sp & 0x7)) 94 return; 95 96 ksp = (unsigned long *)sp; 97 while (!kstack_end(ksp)) { 98 if (__kernel_text_address(pc) && unlikely(fn(pc, arg))) 99 break; 100 pc = (*ksp++) - 0x4; 101 } 102 } 103 104 #endif /* CONFIG_FRAME_POINTER */ 105 106 107 static bool print_trace_address(unsigned long pc, void *arg) 108 { 109 print_ip_sym(pc); 110 return false; 111 } 112 113 void show_stack(struct task_struct *task, unsigned long *sp) 114 { 115 pr_cont("Call Trace:\n"); 116 walk_stackframe(task, NULL, print_trace_address, NULL); 117 } 118 119 120 static bool save_wchan(unsigned long pc, void *arg) 121 { 122 if (!in_sched_functions(pc)) { 123 unsigned long *p = arg; 124 *p = pc; 125 return true; 126 } 127 return false; 128 } 129 130 unsigned long get_wchan(struct task_struct *task) 131 { 132 unsigned long pc = 0; 133 134 if (likely(task && task != current && task->state != TASK_RUNNING)) 135 walk_stackframe(task, NULL, save_wchan, &pc); 136 return pc; 137 } 138 139 140 #ifdef CONFIG_STACKTRACE 141 142 static bool __save_trace(unsigned long pc, void *arg, bool nosched) 143 { 144 struct stack_trace *trace = arg; 145 146 if (unlikely(nosched && in_sched_functions(pc))) 147 return false; 148 if (unlikely(trace->skip > 0)) { 149 trace->skip--; 150 return false; 151 } 152 153 trace->entries[trace->nr_entries++] = pc; 154 return (trace->nr_entries >= trace->max_entries); 155 } 156 157 static bool save_trace(unsigned long pc, void *arg) 158 { 159 return __save_trace(pc, arg, false); 160 } 161 162 /* 163 * Save stack-backtrace addresses into a stack_trace buffer. 164 */ 165 void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) 166 { 167 walk_stackframe(tsk, NULL, save_trace, trace); 168 } 169 EXPORT_SYMBOL_GPL(save_stack_trace_tsk); 170 171 void save_stack_trace(struct stack_trace *trace) 172 { 173 save_stack_trace_tsk(NULL, trace); 174 } 175 EXPORT_SYMBOL_GPL(save_stack_trace); 176 177 #endif /* CONFIG_STACKTRACE */ 178