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