xref: /linux/arch/csky/kernel/stacktrace.c (revision 0ea2dc7cd668be5475babecaf6fdeaa464e2847b)
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