1 /*
2  * SPDX-License-Identifier: BSD-3-Clause
3  * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
4  */
5 
6 #include <arch_helpers.h>
7 #include <debug.h>
8 
9 /* Maximum number of entries in the backtrace to display */
10 #define UNWIND_LIMIT	20U
11 
12 /*
13  * If "-fno-omit-frame-pointer" is used:
14  *
15  * The AArch64 AAPCS defines the format of the frame records and mandates the
16  * usage of x29 as frame pointer.
17  */
18 
19 /* Frame records form a linked list in the stack */
20 struct frame_record {
21 	/* Previous frame record in the list */
22 	struct frame_record *parent;
23 	/* Return address of the function at this level */
24 	uintptr_t return_addr;
25 };
26 
extract_address(uintptr_t address)27 static inline uintptr_t extract_address(uintptr_t address)
28 {
29 	/*
30 	 * When pointer authentication is enabled, the LR value saved on the
31 	 * stack contains a PAC. It must be stripped to retrieve the return
32 	 * address.
33 	 */
34 	xpaci(address);
35 	return address;
36 }
37 
38 /*
39  * Returns true if the address points to a virtual address that can be read at
40  * the current EL, false otherwise.
41  */
is_address_readable(uintptr_t address)42 static bool is_address_readable(uintptr_t address)
43 {
44 	ats1e2r(address);
45 	isb();
46 
47 	/* If PAR_EL1.F == 1 the address translation was aborted */
48 	return ((read_par_el1() & PAR_EL1_F_BIT) == 0UL);
49 }
50 
51 /*
52  * Returns true if all the bytes in a given object are in mapped memory and an
53  * LDR using this pointer would succeed, false otherwise.
54  */
is_valid_object(uintptr_t addr,size_t size)55 static bool is_valid_object(uintptr_t addr, size_t size)
56 {
57 	/* Check address and detect overflows */
58 	if ((addr == 0UL) || ((addr + size) < addr)) {
59 		return false;
60 	}
61 
62 	/* A pointer not aligned properly could trigger an alignment fault */
63 	if ((addr & (sizeof(uintptr_t) - 1UL)) != 0UL) {
64 		return false;
65 	}
66 
67 	/* Check that all the object is readable */
68 	for (size_t i = 0UL; i < size; i++) {
69 		if (!is_address_readable(addr + i)) {
70 			return false;
71 		}
72 	}
73 
74 	return true;
75 }
76 
77 /*
78  * Returns true if the specified address is correctly aligned and points to a
79  * valid memory region.
80  */
is_valid_jump_address(uintptr_t addr)81 static bool is_valid_jump_address(uintptr_t addr)
82 {
83 	/* Check 32-bit alignment */
84 	if ((addr == 0UL) || ((addr & (sizeof(uint32_t) - 1UL)) != 0U)) {
85 		return false;
86 	}
87 
88 	return is_address_readable(addr);
89 }
90 
91 /*
92  * Returns true if the pointer points at a valid frame record, false otherwise.
93  */
is_valid_frame_record(struct frame_record * fr)94 static bool is_valid_frame_record(struct frame_record *fr)
95 {
96 	return is_valid_object((uintptr_t)fr, sizeof(struct frame_record));
97 }
98 
unwind_stack(struct frame_record * fr)99 static void __unused unwind_stack(struct frame_record *fr)
100 {
101 	if (!is_valid_frame_record(fr)) {
102 		INFO("Corrupted frame pointer (frame record address = 0x%lx)\n",
103 			(uintptr_t)fr);
104 		return;
105 	}
106 
107 	/*
108 	 * The last frame record pointer in the linked list at the beginning of
109 	 * the stack should be NULL unless stack is corrupted.
110 	 */
111 	for (unsigned int i = 0U; i < UNWIND_LIMIT; i++) {
112 		uintptr_t call_site;
113 
114 		/* If an invalid frame record is found, exit. */
115 		if (!is_valid_frame_record(fr)) {
116 			return;
117 		}
118 
119 		/*
120 		 * AArch64 instructions are fixed length so the address from
121 		 * where the call was made is the instruction before the return
122 		 * address, which is always 4 bytes before it.
123 		 */
124 		call_site = extract_address(fr->return_addr) - 4UL;
125 
126 		/*
127 		 * If the address is invalid it means that the frame record is
128 		 * probably corrupted.
129 		 */
130 		if (!is_valid_jump_address(call_site)) {
131 			return;
132 		}
133 
134 		INFO("%s", (i == 0U) ? "BACKTRACE:" : "\t");
135 		INFO("\t0x%016lx\n", call_site);
136 
137 		fr = fr->parent;
138 	}
139 
140 	INFO("Max backtrace depth reached\n");
141 }
142 
143 /*
144  * Display a backtrace.
145  *
146  * Many things can prevent displaying the expected backtrace. For example,
147  * compiler optimizations can use a branch instead of branch with link when it
148  * detects a tail call. The backtrace level for this caller will not be
149  * displayed, as it does not appear in the call stack anymore. Also, assembly
150  * functions will not be displayed unless they setup AAPCS compliant frame
151  * records on AArch64.
152  *
153  * Usage of the trace: addr2line can be used to map the addresses to function
154  * and source code location when given the ELF file compiled with debug
155  * information. The "-i" flag is highly recommended to improve display of
156  * inlined function. The *.dump files generated when building each image can
157  * also be used.
158  *
159  * WARNING: In case of corrupted stack, this function could display security
160  * sensitive information past the beginning of the stack so it must not be used
161  * in production build. This function is only called for Debug builds with
162  * "-fno-omit-frame-pointer" option.
163  */
backtrace(uintptr_t frame_pointer)164 void backtrace(uintptr_t frame_pointer)
165 {
166 	/* To avoid misra-c2012-2.7 warnings */
167 	(void)frame_pointer;
168 
169 #if !defined(NDEBUG) && (LOG_LEVEL >= LOG_LEVEL_INFO)
170 	unwind_stack((struct frame_record *)frame_pointer);
171 #endif
172 }
173