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