1*0ea2dc7cSGuo Ren // SPDX-License-Identifier: GPL-2.0 2*0ea2dc7cSGuo Ren /* Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. */ 3*0ea2dc7cSGuo Ren 4*0ea2dc7cSGuo Ren #include <linux/sched/debug.h> 5*0ea2dc7cSGuo Ren #include <linux/sched/task_stack.h> 6*0ea2dc7cSGuo Ren #include <linux/stacktrace.h> 7*0ea2dc7cSGuo Ren #include <linux/ftrace.h> 8*0ea2dc7cSGuo Ren 9*0ea2dc7cSGuo Ren void save_stack_trace(struct stack_trace *trace) 10*0ea2dc7cSGuo Ren { 11*0ea2dc7cSGuo Ren save_stack_trace_tsk(current, trace); 12*0ea2dc7cSGuo Ren } 13*0ea2dc7cSGuo Ren EXPORT_SYMBOL_GPL(save_stack_trace); 14*0ea2dc7cSGuo Ren 15*0ea2dc7cSGuo Ren void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) 16*0ea2dc7cSGuo Ren { 17*0ea2dc7cSGuo Ren unsigned long *fp, *stack_start, *stack_end; 18*0ea2dc7cSGuo Ren unsigned long addr; 19*0ea2dc7cSGuo Ren int skip = trace->skip; 20*0ea2dc7cSGuo Ren int savesched; 21*0ea2dc7cSGuo Ren int graph_idx = 0; 22*0ea2dc7cSGuo Ren 23*0ea2dc7cSGuo Ren if (tsk == current) { 24*0ea2dc7cSGuo Ren asm volatile("mov %0, r8\n":"=r"(fp)); 25*0ea2dc7cSGuo Ren savesched = 1; 26*0ea2dc7cSGuo Ren } else { 27*0ea2dc7cSGuo Ren fp = (unsigned long *)thread_saved_fp(tsk); 28*0ea2dc7cSGuo Ren savesched = 0; 29*0ea2dc7cSGuo Ren } 30*0ea2dc7cSGuo Ren 31*0ea2dc7cSGuo Ren addr = (unsigned long) fp & THREAD_MASK; 32*0ea2dc7cSGuo Ren stack_start = (unsigned long *) addr; 33*0ea2dc7cSGuo Ren stack_end = (unsigned long *) (addr + THREAD_SIZE); 34*0ea2dc7cSGuo Ren 35*0ea2dc7cSGuo Ren while (fp > stack_start && fp < stack_end) { 36*0ea2dc7cSGuo Ren unsigned long lpp, fpp; 37*0ea2dc7cSGuo Ren 38*0ea2dc7cSGuo Ren fpp = fp[0]; 39*0ea2dc7cSGuo Ren lpp = fp[1]; 40*0ea2dc7cSGuo Ren if (!__kernel_text_address(lpp)) 41*0ea2dc7cSGuo Ren break; 42*0ea2dc7cSGuo Ren else 43*0ea2dc7cSGuo Ren lpp = ftrace_graph_ret_addr(tsk, &graph_idx, lpp, NULL); 44*0ea2dc7cSGuo Ren 45*0ea2dc7cSGuo Ren if (savesched || !in_sched_functions(lpp)) { 46*0ea2dc7cSGuo Ren if (skip) { 47*0ea2dc7cSGuo Ren skip--; 48*0ea2dc7cSGuo Ren } else { 49*0ea2dc7cSGuo Ren trace->entries[trace->nr_entries++] = lpp; 50*0ea2dc7cSGuo Ren if (trace->nr_entries >= trace->max_entries) 51*0ea2dc7cSGuo Ren break; 52*0ea2dc7cSGuo Ren } 53*0ea2dc7cSGuo Ren } 54*0ea2dc7cSGuo Ren fp = (unsigned long *)fpp; 55*0ea2dc7cSGuo Ren } 56*0ea2dc7cSGuo Ren } 57*0ea2dc7cSGuo Ren EXPORT_SYMBOL_GPL(save_stack_trace_tsk); 58