mirror of
				https://github.com/smaeul/u-boot.git
				synced 2025-11-04 05:50:17 +00:00 
			
		
		
		
	Add link to usage/cmd/exception.rst. Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
		
			
				
	
	
		
			185 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
			
		
		
	
	
			185 lines
		
	
	
		
			6.6 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 :doc:`exception <../usage/cmd/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.
 | 
						|
 | 
						|
Crashs in UEFI binaries
 | 
						|
-----------------------
 | 
						|
 | 
						|
If UEFI images are loaded when a crash occurs, their load addresses are
 | 
						|
displayed. If the process counter points to an address in a loaded UEFI
 | 
						|
binary, the relative process counter position is indicated. Here is an
 | 
						|
example executed on the U-Boot sandbox::
 | 
						|
 | 
						|
    => load host 0:1 $kernel_addr_r buggy.efi
 | 
						|
    5632 bytes read in 0 ms
 | 
						|
    => bootefi $kernel_addr_r
 | 
						|
    Booting /buggy.efi
 | 
						|
    Buggy world!
 | 
						|
 | 
						|
    Segmentation violation
 | 
						|
    pc = 0x19fc264c, pc_reloc = 0xffffaa4688b1664c
 | 
						|
 | 
						|
    UEFI image [0x0000000019fc0000:0x0000000019fc6137] pc=0x264c '/buggy.efi'
 | 
						|
 | 
						|
The crash occured in UEFI binary buggy.efi at relative position 0x264c.
 | 
						|
Disassembly may be used to find the actual source code location::
 | 
						|
 | 
						|
    $ x86_64-linux-gnu-objdump -S -D buggy_efi.so
 | 
						|
 | 
						|
    0000000000002640 <memset>:
 | 
						|
        2640:       f3 0f 1e fa             endbr64
 | 
						|
        2644:       48 89 f8                mov    %rdi,%rax
 | 
						|
        2647:       48 89 f9                mov    %rdi,%rcx
 | 
						|
        264a:       eb 0b                   jmp    2657 <memset+0x17>
 | 
						|
        264c:       40 88 31                mov    %sil,(%rcx)
 | 
						|
 | 
						|
Architecture specific details
 | 
						|
-----------------------------
 | 
						|
 | 
						|
ARMv8
 | 
						|
~~~~~
 | 
						|
 | 
						|
On the ARM 64-bit architecture CONFIG_ARMV8_SPL_EXCEPTION_VECTORS controls
 | 
						|
if the exception vector tables are set up in the Secondary Program Loader (SPL).
 | 
						|
Without initialization of the tables crash dumps cannot be shown. The feature is
 | 
						|
disabled by default on most boards to reduce the size of the SPL.
 | 
						|
 | 
						|
RISC-V
 | 
						|
~~~~~~
 | 
						|
 | 
						|
On the RISC-V architecture CONFIG_SHOW_REGS=y has to be specified to show
 | 
						|
all registers in crash dumps.
 | 
						|
 | 
						|
Sandbox
 | 
						|
~~~~~~~
 | 
						|
 | 
						|
The sandbox U-Boot binary must be invoked with parameter *-S* to display crash
 | 
						|
dumps:
 | 
						|
 | 
						|
.. code-block:: bash
 | 
						|
 | 
						|
    ./u-boot -S -T
 | 
						|
 | 
						|
Only with CONFIG_SANDBOX_CRASH_RESET=y the sandbox reboots after a crash.
 |