xref: /aosp_15_r20/external/arm-trusted-firmware/common/backtrace/backtrace.c (revision 54fd6939e177f8ff529b10183254802c76df6d08)
1*54fd6939SJiyong Park /*
2*54fd6939SJiyong Park  * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
3*54fd6939SJiyong Park  *
4*54fd6939SJiyong Park  * SPDX-License-Identifier: BSD-3-Clause
5*54fd6939SJiyong Park  */
6*54fd6939SJiyong Park 
7*54fd6939SJiyong Park #include <assert.h>
8*54fd6939SJiyong Park #include <stdbool.h>
9*54fd6939SJiyong Park #include <stdint.h>
10*54fd6939SJiyong Park 
11*54fd6939SJiyong Park #include <arch_helpers.h>
12*54fd6939SJiyong Park #include <common/debug.h>
13*54fd6939SJiyong Park #include <drivers/console.h>
14*54fd6939SJiyong Park 
15*54fd6939SJiyong Park /* Maximum number of entries in the backtrace to display */
16*54fd6939SJiyong Park #define UNWIND_LIMIT	20U
17*54fd6939SJiyong Park 
18*54fd6939SJiyong Park /*
19*54fd6939SJiyong Park  * If -fno-omit-frame-pointer is used:
20*54fd6939SJiyong Park  *
21*54fd6939SJiyong Park  * - AArch64: The AAPCS defines the format of the frame records and mandates the
22*54fd6939SJiyong Park  *   usage of r29 as frame pointer.
23*54fd6939SJiyong Park  *
24*54fd6939SJiyong Park  * - AArch32: The format of the frame records is not defined in the AAPCS.
25*54fd6939SJiyong Park  *   However, at least GCC and Clang use the same format. When they are forced
26*54fd6939SJiyong Park  *   to only generate A32 code (with -marm), they use r11 as frame pointer and a
27*54fd6939SJiyong Park  *   similar format as in AArch64. If interworking with T32 is enabled, the
28*54fd6939SJiyong Park  *   frame pointer is r7 and the format is  different. This is not supported by
29*54fd6939SJiyong Park  *   this implementation of backtrace, so it is needed to use -marm.
30*54fd6939SJiyong Park  */
31*54fd6939SJiyong Park 
32*54fd6939SJiyong Park /* Frame records form a linked list in the stack */
33*54fd6939SJiyong Park struct frame_record {
34*54fd6939SJiyong Park 	/* Previous frame record in the list */
35*54fd6939SJiyong Park 	struct frame_record *parent;
36*54fd6939SJiyong Park 	/* Return address of the function at this level */
37*54fd6939SJiyong Park 	uintptr_t return_addr;
38*54fd6939SJiyong Park };
39*54fd6939SJiyong Park 
get_el_str(unsigned int el)40*54fd6939SJiyong Park const char *get_el_str(unsigned int el)
41*54fd6939SJiyong Park {
42*54fd6939SJiyong Park 	if (el == 3U) {
43*54fd6939SJiyong Park 		return "EL3";
44*54fd6939SJiyong Park 	} else if (el == 2U) {
45*54fd6939SJiyong Park 		return "EL2";
46*54fd6939SJiyong Park 	} else {
47*54fd6939SJiyong Park 		return "S-EL1";
48*54fd6939SJiyong Park 	}
49*54fd6939SJiyong Park }
50*54fd6939SJiyong Park 
51*54fd6939SJiyong Park /*
52*54fd6939SJiyong Park  * Returns true if the address points to a virtual address that can be read at
53*54fd6939SJiyong Park  * the current EL, false otherwise.
54*54fd6939SJiyong Park  */
55*54fd6939SJiyong Park #ifdef __aarch64__
is_address_readable(uintptr_t addr)56*54fd6939SJiyong Park static bool is_address_readable(uintptr_t addr)
57*54fd6939SJiyong Park {
58*54fd6939SJiyong Park 	unsigned int el = get_current_el();
59*54fd6939SJiyong Park 
60*54fd6939SJiyong Park #if ENABLE_PAUTH
61*54fd6939SJiyong Park 	/*
62*54fd6939SJiyong Park 	 * When pointer authentication is enabled, the LR value saved on the
63*54fd6939SJiyong Park 	 * stack contains a PAC. It must be stripped to retrieve the return
64*54fd6939SJiyong Park 	 * address.
65*54fd6939SJiyong Park 	 */
66*54fd6939SJiyong Park 	xpaci(addr);
67*54fd6939SJiyong Park #endif
68*54fd6939SJiyong Park 	if (el == 3U) {
69*54fd6939SJiyong Park 		ats1e3r(addr);
70*54fd6939SJiyong Park 	} else if (el == 2U) {
71*54fd6939SJiyong Park 		ats1e2r(addr);
72*54fd6939SJiyong Park 	} else {
73*54fd6939SJiyong Park 		AT(ats1e1r, addr);
74*54fd6939SJiyong Park 	}
75*54fd6939SJiyong Park 
76*54fd6939SJiyong Park 	isb();
77*54fd6939SJiyong Park 
78*54fd6939SJiyong Park 	/* If PAR.F == 1 the address translation was aborted.  */
79*54fd6939SJiyong Park 	if ((read_par_el1() & PAR_F_MASK) != 0U)
80*54fd6939SJiyong Park 		return false;
81*54fd6939SJiyong Park 
82*54fd6939SJiyong Park 	return true;
83*54fd6939SJiyong Park }
84*54fd6939SJiyong Park #else /* !__aarch64__ */
is_address_readable(uintptr_t addr)85*54fd6939SJiyong Park static bool is_address_readable(uintptr_t addr)
86*54fd6939SJiyong Park {
87*54fd6939SJiyong Park 	unsigned int el = get_current_el();
88*54fd6939SJiyong Park 
89*54fd6939SJiyong Park 	if (el == 3U) {
90*54fd6939SJiyong Park 		write_ats1cpr(addr);
91*54fd6939SJiyong Park 	} else if (el == 2U) {
92*54fd6939SJiyong Park 		write_ats1hr(addr);
93*54fd6939SJiyong Park 	} else {
94*54fd6939SJiyong Park 		write_ats1cpr(addr);
95*54fd6939SJiyong Park 	}
96*54fd6939SJiyong Park 
97*54fd6939SJiyong Park 	isb();
98*54fd6939SJiyong Park 
99*54fd6939SJiyong Park 	/* If PAR.F == 1 the address translation was aborted.  */
100*54fd6939SJiyong Park 	if ((read64_par() & PAR_F_MASK) != 0U)
101*54fd6939SJiyong Park 		return false;
102*54fd6939SJiyong Park 
103*54fd6939SJiyong Park 	return true;
104*54fd6939SJiyong Park }
105*54fd6939SJiyong Park #endif /* __aarch64__ */
106*54fd6939SJiyong Park 
107*54fd6939SJiyong Park /*
108*54fd6939SJiyong Park  * Returns true if all the bytes in a given object are in mapped memory and an
109*54fd6939SJiyong Park  * LDR using this pointer would succeed, false otherwise.
110*54fd6939SJiyong Park  */
is_valid_object(uintptr_t addr,size_t size)111*54fd6939SJiyong Park static bool is_valid_object(uintptr_t addr, size_t size)
112*54fd6939SJiyong Park {
113*54fd6939SJiyong Park 	assert(size > 0U);
114*54fd6939SJiyong Park 
115*54fd6939SJiyong Park 	if (addr == 0U)
116*54fd6939SJiyong Park 		return false;
117*54fd6939SJiyong Park 
118*54fd6939SJiyong Park 	/* Detect overflows */
119*54fd6939SJiyong Park 	if ((addr + size) < addr)
120*54fd6939SJiyong Park 		return false;
121*54fd6939SJiyong Park 
122*54fd6939SJiyong Park 	/* A pointer not aligned properly could trigger an alignment fault. */
123*54fd6939SJiyong Park 	if ((addr & (sizeof(uintptr_t) - 1U)) != 0U)
124*54fd6939SJiyong Park 		return false;
125*54fd6939SJiyong Park 
126*54fd6939SJiyong Park 	/* Check that all the object is readable */
127*54fd6939SJiyong Park 	for (size_t i = 0; i < size; i++) {
128*54fd6939SJiyong Park 		if (!is_address_readable(addr + i))
129*54fd6939SJiyong Park 			return false;
130*54fd6939SJiyong Park 	}
131*54fd6939SJiyong Park 
132*54fd6939SJiyong Park 	return true;
133*54fd6939SJiyong Park }
134*54fd6939SJiyong Park 
135*54fd6939SJiyong Park /*
136*54fd6939SJiyong Park  * Returns true if the specified address is correctly aligned and points to a
137*54fd6939SJiyong Park  * valid memory region.
138*54fd6939SJiyong Park  */
is_valid_jump_address(uintptr_t addr)139*54fd6939SJiyong Park static bool is_valid_jump_address(uintptr_t addr)
140*54fd6939SJiyong Park {
141*54fd6939SJiyong Park 	if (addr == 0U)
142*54fd6939SJiyong Park 		return false;
143*54fd6939SJiyong Park 
144*54fd6939SJiyong Park 	/* Check alignment. Both A64 and A32 use 32-bit opcodes */
145*54fd6939SJiyong Park 	if ((addr & (sizeof(uint32_t) - 1U)) != 0U)
146*54fd6939SJiyong Park 		return false;
147*54fd6939SJiyong Park 
148*54fd6939SJiyong Park 	if (!is_address_readable(addr))
149*54fd6939SJiyong Park 		return false;
150*54fd6939SJiyong Park 
151*54fd6939SJiyong Park 	return true;
152*54fd6939SJiyong Park }
153*54fd6939SJiyong Park 
154*54fd6939SJiyong Park /*
155*54fd6939SJiyong Park  * Returns true if the pointer points at a valid frame record, false otherwise.
156*54fd6939SJiyong Park  */
is_valid_frame_record(struct frame_record * fr)157*54fd6939SJiyong Park static bool is_valid_frame_record(struct frame_record *fr)
158*54fd6939SJiyong Park {
159*54fd6939SJiyong Park 	return is_valid_object((uintptr_t)fr, sizeof(struct frame_record));
160*54fd6939SJiyong Park }
161*54fd6939SJiyong Park 
162*54fd6939SJiyong Park /*
163*54fd6939SJiyong Park  * Adjust the frame-pointer-register value by 4 bytes on AArch32 to have the
164*54fd6939SJiyong Park  * same layout as AArch64.
165*54fd6939SJiyong Park  */
adjust_frame_record(struct frame_record * fr)166*54fd6939SJiyong Park static struct frame_record *adjust_frame_record(struct frame_record *fr)
167*54fd6939SJiyong Park {
168*54fd6939SJiyong Park #ifdef __aarch64__
169*54fd6939SJiyong Park 	return fr;
170*54fd6939SJiyong Park #else
171*54fd6939SJiyong Park 	return (struct frame_record *)((uintptr_t)fr - 4U);
172*54fd6939SJiyong Park #endif
173*54fd6939SJiyong Park }
174*54fd6939SJiyong Park 
unwind_stack(struct frame_record * fr,uintptr_t current_pc,uintptr_t link_register)175*54fd6939SJiyong Park static void unwind_stack(struct frame_record *fr, uintptr_t current_pc,
176*54fd6939SJiyong Park 			 uintptr_t link_register)
177*54fd6939SJiyong Park {
178*54fd6939SJiyong Park 	uintptr_t call_site;
179*54fd6939SJiyong Park 	static const char *backtrace_str = "%u: %s: 0x%lx\n";
180*54fd6939SJiyong Park 	const char *el_str = get_el_str(get_current_el());
181*54fd6939SJiyong Park 
182*54fd6939SJiyong Park 	if (!is_valid_frame_record(fr)) {
183*54fd6939SJiyong Park 		printf("ERROR: Corrupted frame pointer (frame record address = %p)\n",
184*54fd6939SJiyong Park 		       fr);
185*54fd6939SJiyong Park 		return;
186*54fd6939SJiyong Park 	}
187*54fd6939SJiyong Park 
188*54fd6939SJiyong Park 	if (fr->return_addr != link_register) {
189*54fd6939SJiyong Park 		printf("ERROR: Corrupted stack (frame record address = %p)\n",
190*54fd6939SJiyong Park 		       fr);
191*54fd6939SJiyong Park 		return;
192*54fd6939SJiyong Park 	}
193*54fd6939SJiyong Park 
194*54fd6939SJiyong Park 	/* The level 0 of the backtrace is the current backtrace function */
195*54fd6939SJiyong Park 	printf(backtrace_str, 0U, el_str, current_pc);
196*54fd6939SJiyong Park 
197*54fd6939SJiyong Park 	/*
198*54fd6939SJiyong Park 	 * The last frame record pointer in the linked list at the beginning of
199*54fd6939SJiyong Park 	 * the stack should be NULL unless stack is corrupted.
200*54fd6939SJiyong Park 	 */
201*54fd6939SJiyong Park 	for (unsigned int i = 1U; i < UNWIND_LIMIT; i++) {
202*54fd6939SJiyong Park 		/* If an invalid frame record is found, exit. */
203*54fd6939SJiyong Park 		if (!is_valid_frame_record(fr))
204*54fd6939SJiyong Park 			return;
205*54fd6939SJiyong Park 		/*
206*54fd6939SJiyong Park 		 * A32 and A64 are fixed length so the address from where the
207*54fd6939SJiyong Park 		 * call was made is the instruction before the return address,
208*54fd6939SJiyong Park 		 * which is always 4 bytes before it.
209*54fd6939SJiyong Park 		 */
210*54fd6939SJiyong Park 		call_site = fr->return_addr - 4U;
211*54fd6939SJiyong Park 
212*54fd6939SJiyong Park #if ENABLE_PAUTH
213*54fd6939SJiyong Park 		/*
214*54fd6939SJiyong Park 		 * When pointer authentication is enabled, the LR value saved on
215*54fd6939SJiyong Park 		 * the stack contains a PAC. It must be stripped to retrieve the
216*54fd6939SJiyong Park 		 * return address.
217*54fd6939SJiyong Park 		 */
218*54fd6939SJiyong Park 		xpaci(call_site);
219*54fd6939SJiyong Park #endif
220*54fd6939SJiyong Park 		/*
221*54fd6939SJiyong Park 		 * If the address is invalid it means that the frame record is
222*54fd6939SJiyong Park 		 * probably corrupted.
223*54fd6939SJiyong Park 		 */
224*54fd6939SJiyong Park 		if (!is_valid_jump_address(call_site))
225*54fd6939SJiyong Park 			return;
226*54fd6939SJiyong Park 
227*54fd6939SJiyong Park 		printf(backtrace_str, i, el_str, call_site);
228*54fd6939SJiyong Park 
229*54fd6939SJiyong Park 		fr = adjust_frame_record(fr->parent);
230*54fd6939SJiyong Park 	}
231*54fd6939SJiyong Park 
232*54fd6939SJiyong Park 	printf("ERROR: Max backtrace depth reached\n");
233*54fd6939SJiyong Park }
234*54fd6939SJiyong Park 
235*54fd6939SJiyong Park /*
236*54fd6939SJiyong Park  * Display a backtrace. The cookie string parameter is displayed along the
237*54fd6939SJiyong Park  * trace to help filter the log messages.
238*54fd6939SJiyong Park  *
239*54fd6939SJiyong Park  * Many things can prevent displaying the expected backtrace. For example,
240*54fd6939SJiyong Park  * compiler optimizations can use a branch instead of branch with link when it
241*54fd6939SJiyong Park  * detects a tail call. The backtrace level for this caller will not be
242*54fd6939SJiyong Park  * displayed, as it does not appear in the call stack anymore. Also, assembly
243*54fd6939SJiyong Park  * functions will not be displayed unless they setup AAPCS compliant frame
244*54fd6939SJiyong Park  * records on AArch64 and compliant with GCC-specific frame record format on
245*54fd6939SJiyong Park  * AArch32.
246*54fd6939SJiyong Park  *
247*54fd6939SJiyong Park  * Usage of the trace: addr2line can be used to map the addresses to function
248*54fd6939SJiyong Park  * and source code location when given the ELF file compiled with debug
249*54fd6939SJiyong Park  * information. The "-i" flag is highly recommended to improve display of
250*54fd6939SJiyong Park  * inlined function. The *.dump files generated when building each image can
251*54fd6939SJiyong Park  * also be used.
252*54fd6939SJiyong Park  *
253*54fd6939SJiyong Park  * WARNING: In case of corrupted stack, this function could display security
254*54fd6939SJiyong Park  * sensitive information past the beginning of the stack so it must not be used
255*54fd6939SJiyong Park  * in production build. This function is only compiled in when ENABLE_BACKTRACE
256*54fd6939SJiyong Park  * is set to 1.
257*54fd6939SJiyong Park  */
backtrace(const char * cookie)258*54fd6939SJiyong Park void backtrace(const char *cookie)
259*54fd6939SJiyong Park {
260*54fd6939SJiyong Park 	uintptr_t return_address = (uintptr_t)__builtin_return_address(0U);
261*54fd6939SJiyong Park 	struct frame_record *fr = __builtin_frame_address(0U);
262*54fd6939SJiyong Park 
263*54fd6939SJiyong Park 	/* Printing the backtrace may crash the system, flush before starting */
264*54fd6939SJiyong Park 	console_flush();
265*54fd6939SJiyong Park 
266*54fd6939SJiyong Park 	fr = adjust_frame_record(fr);
267*54fd6939SJiyong Park 
268*54fd6939SJiyong Park 	printf("BACKTRACE: START: %s\n", cookie);
269*54fd6939SJiyong Park 
270*54fd6939SJiyong Park 	unwind_stack(fr, (uintptr_t)&backtrace, return_address);
271*54fd6939SJiyong Park 
272*54fd6939SJiyong Park 	printf("BACKTRACE: END: %s\n", cookie);
273*54fd6939SJiyong Park }
274