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