Heinrich Schuchardt | 7182061 | 2020-04-24 23:31:20 +0200 | [diff] [blame] | 1 | .. SPDX-License-Identifier: GPL-2.0+ |
| 2 | .. Copyright (c) 2020 Heinrich Schuchardt |
| 3 | |
| 4 | Analyzing crash dumps |
| 5 | ===================== |
| 6 | |
| 7 | When the CPU detects an instruction that it cannot execute it raises an |
Heinrich Schuchardt | 1c5fe19 | 2020-07-09 08:12:06 +0200 | [diff] [blame] | 8 | interrupt. U-Boot then writes a crash dump. This chapter describes how such |
Heinrich Schuchardt | 7182061 | 2020-04-24 23:31:20 +0200 | [diff] [blame] | 9 | dump can be analyzed. |
| 10 | |
| 11 | Creating a crash dump voluntarily |
| 12 | --------------------------------- |
| 13 | |
| 14 | For describing the analysis of a crash dump we need an example. U-Boot comes |
Heinrich Schuchardt | c9f2e29 | 2022-08-02 15:36:42 +0200 | [diff] [blame] | 15 | with a command :doc:`exception <../usage/cmd/exception>` that comes in handy |
| 16 | here. The command is enabled by:: |
Heinrich Schuchardt | 7182061 | 2020-04-24 23:31:20 +0200 | [diff] [blame] | 17 | |
| 18 | CONFIG_CMD_EXCEPTION=y |
| 19 | |
| 20 | The example output below was recorded when running qemu\_arm64\_defconfig on |
| 21 | QEMU:: |
| 22 | |
| 23 | => exception undefined |
| 24 | "Synchronous Abort" handler, esr 0x02000000 |
| 25 | elr: 00000000000101fc lr : 00000000000214ec (reloc) |
| 26 | elr: 000000007ff291fc lr : 000000007ff3a4ec |
| 27 | x0 : 000000007ffbd7f8 x1 : 0000000000000000 |
| 28 | x2 : 0000000000000001 x3 : 000000007eedce18 |
| 29 | x4 : 000000007ff291fc x5 : 000000007eedce50 |
| 30 | x6 : 0000000000000064 x7 : 000000007eedce10 |
| 31 | x8 : 0000000000000000 x9 : 0000000000000004 |
| 32 | x10: 6db6db6db6db6db7 x11: 000000000000000d |
| 33 | x12: 0000000000000006 x13: 000000000001869f |
| 34 | x14: 000000007edd7dc0 x15: 0000000000000002 |
| 35 | x16: 000000007ff291fc x17: 0000000000000000 |
| 36 | x18: 000000007eed8dc0 x19: 0000000000000000 |
| 37 | x20: 000000007ffbd7f8 x21: 0000000000000000 |
| 38 | x22: 000000007eedce10 x23: 0000000000000002 |
| 39 | x24: 000000007ffd4c80 x25: 0000000000000000 |
| 40 | x26: 0000000000000000 x27: 0000000000000000 |
| 41 | x28: 000000007eedce70 x29: 000000007edd7b40 |
| 42 | |
| 43 | Code: b00003c0 912ad000 940029d6 17ffff52 (e7f7defb) |
| 44 | Resetting CPU ... |
| 45 | |
| 46 | resetting ... |
| 47 | |
| 48 | The first line provides us with the type of interrupt that occurred. |
Heinrich Schuchardt | 1c5fe19 | 2020-07-09 08:12:06 +0200 | [diff] [blame] | 49 | On ARMv8 a synchronous abort is an exception thrown when hitting an unallocated |
| 50 | instruction. The exception syndrome register ESR register contains information |
| 51 | describing the reason for the exception. Bit 25 set here indicates that a 32 bit |
| 52 | instruction led to the exception. |
Heinrich Schuchardt | 7182061 | 2020-04-24 23:31:20 +0200 | [diff] [blame] | 53 | |
| 54 | The second line provides the contents of the elr and the lr register after |
| 55 | subtracting the relocation offset. - U-Boot relocates itself after being |
| 56 | loaded. - The relocation offset can also be displayed using the bdinfo command. |
| 57 | |
| 58 | After the contents of the registers we get a line indicating the machine |
| 59 | code of the instructions preceding the crash and in parentheses the instruction |
| 60 | leading to the dump. |
| 61 | |
| 62 | Analyzing the code location |
| 63 | --------------------------- |
| 64 | |
| 65 | We can convert the instructions in the line starting with 'Code:' into mnemonics |
| 66 | using the objdump command. To make things easier scripts/decodecode is |
| 67 | supplied:: |
| 68 | |
| 69 | $echo 'Code: b00003c0 912ad000 940029d6 17ffff52 (e7f7defb)' | \ |
| 70 | CROSS_COMPILE=aarch64-linux-gnu- ARCH=arm64 scripts/decodecode |
| 71 | Code: b00003c0 912ad000 940029d6 17ffff52 (e7f7defb) |
| 72 | All code |
| 73 | ======== |
| 74 | 0: b00003c0 adrp x0, 0x79000 |
| 75 | 4: 912ad000 add x0, x0, #0xab4 |
| 76 | 8: 940029d6 bl 0xa760 |
| 77 | c: 17ffff52 b 0xfffffffffffffd54 |
| 78 | 10:* e7f7defb .inst 0xe7f7defb ; undefined <-- trapping instruction |
| 79 | |
| 80 | Code starting with the faulting instruction |
| 81 | =========================================== |
| 82 | 0: e7f7defb .inst 0xe7f7defb ; undefined |
| 83 | |
| 84 | Now lets use the locations provided by the elr and lr registers after |
| 85 | subtracting the relocation offset to find out where in the code the crash |
| 86 | occurred and from where it was invoked. |
| 87 | |
| 88 | File u-boot.map contains the memory layout of the U-Boot binary. Here we find |
| 89 | these lines:: |
| 90 | |
| 91 | .text.do_undefined |
| 92 | 0x00000000000101fc 0xc cmd/built-in.o |
| 93 | .text.exception_complete |
| 94 | 0x0000000000010208 0x90 cmd/built-in.o |
| 95 | ... |
| 96 | .text.cmd_process |
| 97 | 0x00000000000213b8 0x164 common/built-in.o |
| 98 | 0x00000000000213b8 cmd_process |
| 99 | .text.cmd_process_error |
| 100 | 0x000000000002151c 0x40 common/built-in.o |
| 101 | 0x000000000002151c cmd_process_error |
| 102 | |
| 103 | So the error occurred at the start of function do\_undefined() and this |
| 104 | function was invoked from somewhere inside function cmd\_process(). |
| 105 | |
| 106 | If we want to dive deeper, we can disassemble the U-Boot binary:: |
| 107 | |
| 108 | $ aarch64-linux-gnu-objdump -S -D u-boot | less |
| 109 | |
| 110 | 00000000000101fc <do_undefined>: |
| 111 | { |
| 112 | /* |
| 113 | * 0xe7f...f. is undefined in ARM mode |
| 114 | * 0xde.. is undefined in Thumb mode |
| 115 | */ |
| 116 | asm volatile (".word 0xe7f7defb\n"); |
| 117 | 101fc: e7f7defb .inst 0xe7f7defb ; undefined |
| 118 | return CMD_RET_FAILURE; |
| 119 | } |
| 120 | 10200: 52800020 mov w0, #0x1 // #1 |
| 121 | 10204: d65f03c0 ret |
| 122 | |
| 123 | This example is based on the ARMv8 architecture but the same procedures can be |
| 124 | used on other architectures as well. |
Heinrich Schuchardt | e629692 | 2022-08-02 15:23:32 +0200 | [diff] [blame] | 125 | |
| 126 | Crashs in UEFI binaries |
| 127 | ----------------------- |
| 128 | |
| 129 | If UEFI images are loaded when a crash occurs, their load addresses are |
| 130 | displayed. If the process counter points to an address in a loaded UEFI |
| 131 | binary, the relative process counter position is indicated. Here is an |
| 132 | example executed on the U-Boot sandbox:: |
| 133 | |
| 134 | => load host 0:1 $kernel_addr_r buggy.efi |
| 135 | 5632 bytes read in 0 ms |
| 136 | => bootefi $kernel_addr_r |
| 137 | Booting /buggy.efi |
| 138 | Buggy world! |
| 139 | |
| 140 | Segmentation violation |
| 141 | pc = 0x19fc264c, pc_reloc = 0xffffaa4688b1664c |
| 142 | |
| 143 | UEFI image [0x0000000019fc0000:0x0000000019fc6137] pc=0x264c '/buggy.efi' |
| 144 | |
| 145 | The crash occured in UEFI binary buggy.efi at relative position 0x264c. |
| 146 | Disassembly may be used to find the actual source code location:: |
| 147 | |
| 148 | $ x86_64-linux-gnu-objdump -S -D buggy_efi.so |
| 149 | |
| 150 | 0000000000002640 <memset>: |
| 151 | 2640: f3 0f 1e fa endbr64 |
| 152 | 2644: 48 89 f8 mov %rdi,%rax |
| 153 | 2647: 48 89 f9 mov %rdi,%rcx |
| 154 | 264a: eb 0b jmp 2657 <memset+0x17> |
| 155 | 264c: 40 88 31 mov %sil,(%rcx) |
| 156 | |
| 157 | Architecture specific details |
| 158 | ----------------------------- |
| 159 | |
| 160 | ARMv8 |
| 161 | ~~~~~ |
| 162 | |
| 163 | On the ARM 64-bit architecture CONFIG_ARMV8_SPL_EXCEPTION_VECTORS controls |
| 164 | if the exception vector tables are set up in the Secondary Program Loader (SPL). |
| 165 | Without initialization of the tables crash dumps cannot be shown. The feature is |
| 166 | disabled by default on most boards to reduce the size of the SPL. |
| 167 | |
| 168 | RISC-V |
| 169 | ~~~~~~ |
| 170 | |
| 171 | On the RISC-V architecture CONFIG_SHOW_REGS=y has to be specified to show |
| 172 | all registers in crash dumps. |
| 173 | |
| 174 | Sandbox |
| 175 | ~~~~~~~ |
| 176 | |
| 177 | The sandbox U-Boot binary must be invoked with parameter *-S* to display crash |
| 178 | dumps: |
| 179 | |
| 180 | .. code-block:: bash |
| 181 | |
| 182 | ./u-boot -S -T |
| 183 | |
| 184 | Only with CONFIG_SANDBOX_CRASH_RESET=y the sandbox reboots after a crash. |