| .. SPDX-License-Identifier: GPL-2.0+ |
| .. Copyright (c) 2020 Heinrich Schuchardt |
| |
| Analyzing crash dumps |
| ===================== |
| |
| When the CPU detects an instruction that it cannot execute it raises an |
| interrupt. U-Boot then writes a crash dump. This chapter describes how such |
| dump can be analyzed. |
| |
| Creating a crash dump voluntarily |
| --------------------------------- |
| |
| For describing the analysis of a crash dump we need an example. U-Boot comes |
| with a command 'exception' that comes in handy here. The command is enabled |
| by:: |
| |
| CONFIG_CMD_EXCEPTION=y |
| |
| The example output below was recorded when running qemu\_arm64\_defconfig on |
| QEMU:: |
| |
| => exception undefined |
| "Synchronous Abort" handler, esr 0x02000000 |
| elr: 00000000000101fc lr : 00000000000214ec (reloc) |
| elr: 000000007ff291fc lr : 000000007ff3a4ec |
| x0 : 000000007ffbd7f8 x1 : 0000000000000000 |
| x2 : 0000000000000001 x3 : 000000007eedce18 |
| x4 : 000000007ff291fc x5 : 000000007eedce50 |
| x6 : 0000000000000064 x7 : 000000007eedce10 |
| x8 : 0000000000000000 x9 : 0000000000000004 |
| x10: 6db6db6db6db6db7 x11: 000000000000000d |
| x12: 0000000000000006 x13: 000000000001869f |
| x14: 000000007edd7dc0 x15: 0000000000000002 |
| x16: 000000007ff291fc x17: 0000000000000000 |
| x18: 000000007eed8dc0 x19: 0000000000000000 |
| x20: 000000007ffbd7f8 x21: 0000000000000000 |
| x22: 000000007eedce10 x23: 0000000000000002 |
| x24: 000000007ffd4c80 x25: 0000000000000000 |
| x26: 0000000000000000 x27: 0000000000000000 |
| x28: 000000007eedce70 x29: 000000007edd7b40 |
| |
| Code: b00003c0 912ad000 940029d6 17ffff52 (e7f7defb) |
| Resetting CPU ... |
| |
| resetting ... |
| |
| The first line provides us with the type of interrupt that occurred. |
| On ARMv8 a synchronous abort is an exception thrown when hitting an unallocated |
| instruction. The exception syndrome register ESR register contains information |
| describing the reason for the exception. Bit 25 set here indicates that a 32 bit |
| instruction led to the exception. |
| |
| The second line provides the contents of the elr and the lr register after |
| subtracting the relocation offset. - U-Boot relocates itself after being |
| loaded. - The relocation offset can also be displayed using the bdinfo command. |
| |
| After the contents of the registers we get a line indicating the machine |
| code of the instructions preceding the crash and in parentheses the instruction |
| leading to the dump. |
| |
| Analyzing the code location |
| --------------------------- |
| |
| We can convert the instructions in the line starting with 'Code:' into mnemonics |
| using the objdump command. To make things easier scripts/decodecode is |
| supplied:: |
| |
| $echo 'Code: b00003c0 912ad000 940029d6 17ffff52 (e7f7defb)' | \ |
| CROSS_COMPILE=aarch64-linux-gnu- ARCH=arm64 scripts/decodecode |
| Code: b00003c0 912ad000 940029d6 17ffff52 (e7f7defb) |
| All code |
| ======== |
| 0: b00003c0 adrp x0, 0x79000 |
| 4: 912ad000 add x0, x0, #0xab4 |
| 8: 940029d6 bl 0xa760 |
| c: 17ffff52 b 0xfffffffffffffd54 |
| 10:* e7f7defb .inst 0xe7f7defb ; undefined <-- trapping instruction |
| |
| Code starting with the faulting instruction |
| =========================================== |
| 0: e7f7defb .inst 0xe7f7defb ; undefined |
| |
| Now lets use the locations provided by the elr and lr registers after |
| subtracting the relocation offset to find out where in the code the crash |
| occurred and from where it was invoked. |
| |
| File u-boot.map contains the memory layout of the U-Boot binary. Here we find |
| these lines:: |
| |
| .text.do_undefined |
| 0x00000000000101fc 0xc cmd/built-in.o |
| .text.exception_complete |
| 0x0000000000010208 0x90 cmd/built-in.o |
| ... |
| .text.cmd_process |
| 0x00000000000213b8 0x164 common/built-in.o |
| 0x00000000000213b8 cmd_process |
| .text.cmd_process_error |
| 0x000000000002151c 0x40 common/built-in.o |
| 0x000000000002151c cmd_process_error |
| |
| So the error occurred at the start of function do\_undefined() and this |
| function was invoked from somewhere inside function cmd\_process(). |
| |
| If we want to dive deeper, we can disassemble the U-Boot binary:: |
| |
| $ aarch64-linux-gnu-objdump -S -D u-boot | less |
| |
| 00000000000101fc <do_undefined>: |
| { |
| /* |
| * 0xe7f...f. is undefined in ARM mode |
| * 0xde.. is undefined in Thumb mode |
| */ |
| asm volatile (".word 0xe7f7defb\n"); |
| 101fc: e7f7defb .inst 0xe7f7defb ; undefined |
| return CMD_RET_FAILURE; |
| } |
| 10200: 52800020 mov w0, #0x1 // #1 |
| 10204: d65f03c0 ret |
| |
| This example is based on the ARMv8 architecture but the same procedures can be |
| used on other architectures as well. |