125 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
			
		
		
	
	
			125 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
| .. 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.
 |