xref: /openbmc/linux/arch/arm/kernel/stacktrace.c (revision f16fb1ecc5a1cb2f7cc595179d1fe55e711e599f)
1*f16fb1ecSRussell King #include <linux/sched.h>
2*f16fb1ecSRussell King #include <linux/stacktrace.h>
3*f16fb1ecSRussell King 
4*f16fb1ecSRussell King #include "stacktrace.h"
5*f16fb1ecSRussell King 
6*f16fb1ecSRussell King int walk_stackframe(unsigned long fp, unsigned long low, unsigned long high,
7*f16fb1ecSRussell King 		    int (*fn)(struct stackframe *, void *), void *data)
8*f16fb1ecSRussell King {
9*f16fb1ecSRussell King 	struct stackframe *frame;
10*f16fb1ecSRussell King 
11*f16fb1ecSRussell King 	do {
12*f16fb1ecSRussell King 		/*
13*f16fb1ecSRussell King 		 * Check current frame pointer is within bounds
14*f16fb1ecSRussell King 		 */
15*f16fb1ecSRussell King 		if ((fp - 12) < low || fp + 4 >= high)
16*f16fb1ecSRussell King 			break;
17*f16fb1ecSRussell King 
18*f16fb1ecSRussell King 		frame = (struct stackframe *)(fp - 12);
19*f16fb1ecSRussell King 
20*f16fb1ecSRussell King 		if (fn(frame, data))
21*f16fb1ecSRussell King 			break;
22*f16fb1ecSRussell King 
23*f16fb1ecSRussell King 		/*
24*f16fb1ecSRussell King 		 * Update the low bound - the next frame must always
25*f16fb1ecSRussell King 		 * be at a higher address than the current frame.
26*f16fb1ecSRussell King 		 */
27*f16fb1ecSRussell King 		low = fp + 4;
28*f16fb1ecSRussell King 		fp = frame->fp;
29*f16fb1ecSRussell King 	} while (fp);
30*f16fb1ecSRussell King 
31*f16fb1ecSRussell King 	return 0;
32*f16fb1ecSRussell King }
33*f16fb1ecSRussell King 
34*f16fb1ecSRussell King #ifdef CONFIG_STACKTRACE
35*f16fb1ecSRussell King struct stack_trace_data {
36*f16fb1ecSRussell King 	struct stack_trace *trace;
37*f16fb1ecSRussell King 	unsigned int skip;
38*f16fb1ecSRussell King };
39*f16fb1ecSRussell King 
40*f16fb1ecSRussell King static int save_trace(struct stackframe *frame, void *d)
41*f16fb1ecSRussell King {
42*f16fb1ecSRussell King 	struct stack_trace_data *data = d;
43*f16fb1ecSRussell King 	struct stack_trace *trace = data->trace;
44*f16fb1ecSRussell King 
45*f16fb1ecSRussell King 	if (data->skip) {
46*f16fb1ecSRussell King 		data->skip--;
47*f16fb1ecSRussell King 		return 0;
48*f16fb1ecSRussell King 	}
49*f16fb1ecSRussell King 
50*f16fb1ecSRussell King 	trace->entries[trace->nr_entries++] = frame->lr;
51*f16fb1ecSRussell King 
52*f16fb1ecSRussell King 	return trace->nr_entries >= trace->max_entries;
53*f16fb1ecSRussell King }
54*f16fb1ecSRussell King 
55*f16fb1ecSRussell King void save_stack_trace(struct stack_trace *trace, struct task_struct *task)
56*f16fb1ecSRussell King {
57*f16fb1ecSRussell King 	struct stack_trace_data data;
58*f16fb1ecSRussell King 	unsigned long fp, base;
59*f16fb1ecSRussell King 
60*f16fb1ecSRussell King 	data.trace = trace;
61*f16fb1ecSRussell King 	data.skip = trace->skip;
62*f16fb1ecSRussell King 
63*f16fb1ecSRussell King 	if (task) {
64*f16fb1ecSRussell King 		base = (unsigned long)task_stack_page(task);
65*f16fb1ecSRussell King 		fp = 0; /* FIXME */
66*f16fb1ecSRussell King 	} else {
67*f16fb1ecSRussell King 		base = (unsigned long)task_stack_page(current);
68*f16fb1ecSRussell King 		asm("mov %0, fp" : "=r" (fp));
69*f16fb1ecSRussell King 	}
70*f16fb1ecSRussell King 
71*f16fb1ecSRussell King 	walk_stackframe(fp, base, base + THREAD_SIZE, save_trace, &data);
72*f16fb1ecSRussell King }
73*f16fb1ecSRussell King #endif
74