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 |
| 15 | with a command 'exception' that comes in handy here. The command is enabled |
| 16 | by:: |
| 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. |