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