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