xref: /kvm-unit-tests/lib/ppc64/stack.c (revision ac6e1abfedf922c87abac7c2aba03ed9c25b6cc8)
1*ac6e1abfSNicholas Piggin #include <libcflat.h>
2*ac6e1abfSNicholas Piggin #include <asm/ptrace.h>
3*ac6e1abfSNicholas Piggin #include <stack.h>
4*ac6e1abfSNicholas Piggin 
5*ac6e1abfSNicholas Piggin extern char do_handle_exception_return[];
6*ac6e1abfSNicholas Piggin 
arch_backtrace_frame(const void * frame,const void ** return_addrs,int max_depth,bool current_frame)7*ac6e1abfSNicholas Piggin int arch_backtrace_frame(const void *frame, const void **return_addrs,
8*ac6e1abfSNicholas Piggin 			 int max_depth, bool current_frame)
9*ac6e1abfSNicholas Piggin {
10*ac6e1abfSNicholas Piggin 	static int walking;
11*ac6e1abfSNicholas Piggin 	int depth = 0;
12*ac6e1abfSNicholas Piggin 	const unsigned long *bp = (unsigned long *)frame;
13*ac6e1abfSNicholas Piggin 	void *return_addr;
14*ac6e1abfSNicholas Piggin 
15*ac6e1abfSNicholas Piggin 	asm volatile("" ::: "lr"); /* Force it to save LR */
16*ac6e1abfSNicholas Piggin 
17*ac6e1abfSNicholas Piggin 	if (walking) {
18*ac6e1abfSNicholas Piggin 		printf("RECURSIVE STACK WALK!!!\n");
19*ac6e1abfSNicholas Piggin 		return 0;
20*ac6e1abfSNicholas Piggin 	}
21*ac6e1abfSNicholas Piggin 	walking = 1;
22*ac6e1abfSNicholas Piggin 
23*ac6e1abfSNicholas Piggin 	if (current_frame)
24*ac6e1abfSNicholas Piggin 		bp = __builtin_frame_address(0);
25*ac6e1abfSNicholas Piggin 
26*ac6e1abfSNicholas Piggin 	bp = (unsigned long *)bp[0];
27*ac6e1abfSNicholas Piggin 	return_addr = (void *)bp[2];
28*ac6e1abfSNicholas Piggin 
29*ac6e1abfSNicholas Piggin 	for (depth = 0; bp && depth < max_depth; depth++) {
30*ac6e1abfSNicholas Piggin 		return_addrs[depth] = return_addr;
31*ac6e1abfSNicholas Piggin 		if (return_addrs[depth] == 0)
32*ac6e1abfSNicholas Piggin 			break;
33*ac6e1abfSNicholas Piggin 		if (return_addrs[depth] == do_handle_exception_return) {
34*ac6e1abfSNicholas Piggin 			struct pt_regs *regs;
35*ac6e1abfSNicholas Piggin 
36*ac6e1abfSNicholas Piggin 			regs = (void *)bp + STACK_FRAME_OVERHEAD;
37*ac6e1abfSNicholas Piggin 			bp = (unsigned long *)bp[0];
38*ac6e1abfSNicholas Piggin 			/* Represent interrupt frame with vector number */
39*ac6e1abfSNicholas Piggin 			return_addr = (void *)regs->trap;
40*ac6e1abfSNicholas Piggin 			if (depth + 1 < max_depth) {
41*ac6e1abfSNicholas Piggin 				depth++;
42*ac6e1abfSNicholas Piggin 				return_addrs[depth] = return_addr;
43*ac6e1abfSNicholas Piggin 				return_addr = (void *)regs->nip;
44*ac6e1abfSNicholas Piggin 			}
45*ac6e1abfSNicholas Piggin 		} else {
46*ac6e1abfSNicholas Piggin 			bp = (unsigned long *)bp[0];
47*ac6e1abfSNicholas Piggin 			return_addr = (void *)bp[2];
48*ac6e1abfSNicholas Piggin 		}
49*ac6e1abfSNicholas Piggin 	}
50*ac6e1abfSNicholas Piggin 
51*ac6e1abfSNicholas Piggin 	walking = 0;
52*ac6e1abfSNicholas Piggin 	return depth;
53*ac6e1abfSNicholas Piggin }
54