xref: /kvm-unit-tests/lib/arm64/stack.c (revision 6444ae208ce0085d0f5c5ffb15909ca3bbd49c84)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Backtrace support.
4  */
5 #include <libcflat.h>
6 #include <stdbool.h>
7 #include <stack.h>
8 
9 extern char vector_stub_start, vector_stub_end;
10 
arch_backtrace_frame(const void * frame,const void ** return_addrs,int max_depth,bool current_frame)11 int arch_backtrace_frame(const void *frame, const void **return_addrs,
12 			 int max_depth, bool current_frame)
13 {
14 	const void *fp = frame;
15 	static bool walking;
16 	void *lr;
17 	int depth;
18 	bool is_exception = false;
19 	unsigned long addr;
20 
21 	if (current_frame)
22 		fp = __builtin_frame_address(0);
23 
24 	if (walking) {
25 		printf("RECURSIVE STACK WALK!!!\n");
26 		return 0;
27 	}
28 	walking = true;
29 
30 	/*
31 	 * ARM64 stack grows down. fp points to the previous fp on the stack,
32 	 * and lr is just above it
33 	 */
34 	for (depth = 0; fp && depth < max_depth; ++depth) {
35 
36 		asm volatile ("ldp %0, %1, [%2]"
37 				  : "=r" (fp), "=r" (lr)
38 				  : "r" (fp)
39 				  : );
40 
41 		return_addrs[depth] = lr;
42 
43 		/*
44 		 * If this is an exception, add 1 to the pointer so when the
45 		 * pretty_print_stacks script is run it would get the right
46 		 * address (it deducts 1 to find the call address, but we want
47 		 * the actual address).
48 		 */
49 		if (is_exception)
50 			return_addrs[depth] += 1;
51 
52 		/* Check if we are in the exception handlers for the next entry */
53 		addr = (unsigned long)lr;
54 		is_exception = (addr >= (unsigned long)&vector_stub_start &&
55 				addr < (unsigned long)&vector_stub_end);
56 	}
57 
58 	walking = false;
59 	return depth;
60 }
61