0001
0002
0003 #include <linux/sched/debug.h>
0004 #include <linux/sched/task_stack.h>
0005 #include <linux/stacktrace.h>
0006 #include <linux/ftrace.h>
0007 #include <linux/ptrace.h>
0008
0009 #ifdef CONFIG_FRAME_POINTER
0010
0011 struct stackframe {
0012 unsigned long fp;
0013 unsigned long ra;
0014 };
0015
0016 void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs,
0017 bool (*fn)(unsigned long, void *), void *arg)
0018 {
0019 unsigned long fp, sp, pc;
0020
0021 if (regs) {
0022 fp = frame_pointer(regs);
0023 sp = user_stack_pointer(regs);
0024 pc = instruction_pointer(regs);
0025 } else if (task == NULL || task == current) {
0026 const register unsigned long current_sp __asm__ ("sp");
0027 const register unsigned long current_fp __asm__ ("r8");
0028 fp = current_fp;
0029 sp = current_sp;
0030 pc = (unsigned long)walk_stackframe;
0031 } else {
0032
0033 fp = thread_saved_fp(task);
0034 sp = thread_saved_sp(task);
0035 pc = thread_saved_lr(task);
0036 }
0037
0038 for (;;) {
0039 unsigned long low, high;
0040 struct stackframe *frame;
0041
0042 if (unlikely(!__kernel_text_address(pc) || fn(pc, arg)))
0043 break;
0044
0045
0046 low = sp;
0047 high = ALIGN(sp, THREAD_SIZE);
0048 if (unlikely(fp < low || fp > high || fp & 0x3))
0049 break;
0050
0051 frame = (struct stackframe *)fp;
0052 sp = fp;
0053 fp = frame->fp;
0054 pc = ftrace_graph_ret_addr(current, NULL, frame->ra,
0055 (unsigned long *)(fp - 8));
0056 }
0057 }
0058
0059 #else
0060
0061 static void notrace walk_stackframe(struct task_struct *task,
0062 struct pt_regs *regs, bool (*fn)(unsigned long, void *), void *arg)
0063 {
0064 unsigned long sp, pc;
0065 unsigned long *ksp;
0066
0067 if (regs) {
0068 sp = user_stack_pointer(regs);
0069 pc = instruction_pointer(regs);
0070 } else if (task == NULL || task == current) {
0071 const register unsigned long current_sp __asm__ ("sp");
0072 sp = current_sp;
0073 pc = (unsigned long)walk_stackframe;
0074 } else {
0075
0076 sp = thread_saved_sp(task);
0077 pc = thread_saved_lr(task);
0078 }
0079
0080 if (unlikely(sp & 0x3))
0081 return;
0082
0083 ksp = (unsigned long *)sp;
0084 while (!kstack_end(ksp)) {
0085 if (__kernel_text_address(pc) && unlikely(fn(pc, arg)))
0086 break;
0087 pc = (*ksp++) - 0x4;
0088 }
0089 }
0090 #endif
0091
0092 static bool print_trace_address(unsigned long pc, void *arg)
0093 {
0094 print_ip_sym((const char *)arg, pc);
0095 return false;
0096 }
0097
0098 void show_stack(struct task_struct *task, unsigned long *sp, const char *loglvl)
0099 {
0100 pr_cont("Call Trace:\n");
0101 walk_stackframe(task, NULL, print_trace_address, (void *)loglvl);
0102 }
0103
0104 static bool save_wchan(unsigned long pc, void *arg)
0105 {
0106 if (!in_sched_functions(pc)) {
0107 unsigned long *p = arg;
0108 *p = pc;
0109 return true;
0110 }
0111 return false;
0112 }
0113
0114 unsigned long __get_wchan(struct task_struct *task)
0115 {
0116 unsigned long pc = 0;
0117
0118 walk_stackframe(task, NULL, save_wchan, &pc);
0119 return pc;
0120 }
0121
0122 #ifdef CONFIG_STACKTRACE
0123 static bool __save_trace(unsigned long pc, void *arg, bool nosched)
0124 {
0125 struct stack_trace *trace = arg;
0126
0127 if (unlikely(nosched && in_sched_functions(pc)))
0128 return false;
0129 if (unlikely(trace->skip > 0)) {
0130 trace->skip--;
0131 return false;
0132 }
0133
0134 trace->entries[trace->nr_entries++] = pc;
0135 return (trace->nr_entries >= trace->max_entries);
0136 }
0137
0138 static bool save_trace(unsigned long pc, void *arg)
0139 {
0140 return __save_trace(pc, arg, false);
0141 }
0142
0143
0144
0145
0146 void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
0147 {
0148 walk_stackframe(tsk, NULL, save_trace, trace);
0149 }
0150 EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
0151
0152 void save_stack_trace(struct stack_trace *trace)
0153 {
0154 save_stack_trace_tsk(NULL, trace);
0155 }
0156 EXPORT_SYMBOL_GPL(save_stack_trace);
0157
0158 #endif