.. SPDX-License-Identifier: GPL-2.0+ .. Copyright (c) 2024 Alexander Dahl Debugging U-Boot with GDB ========================= Using a JTAG adapter it is possible to debug a running U-Boot with GDB. A common way is to connect a debug adapter to the JTAG connector of your board, run a GDB server, connect GDB to the GDB server, and use GDB as usual. Similarly QEMU can provide a GDB server. Preparing build --------------- Building U-Boot with with reduced optimization (-Og) and without link time optimization is recommended for easier debugging:: CONFIG_CC_OPTIMIZE_FOR_DEBUG=y CONFIG_LTO=n Otherwise build, install, and run U-Boot as usual. Using OpenOCD as GDB server --------------------------- `OpenOCD `_ is an open source tool supporting hardware debug probes, and providing a GDB server. It is readily available in major Linux distributions or you can build it from source. Here is example of starting OpenOCD on Debian using a J-Link adapter and a board with an AT91 SAMA5D2 SoC: .. code-block:: console $ openocd -f interface/jlink.cfg -f target/at91sama5d2.cfg -c 'adapter speed 4000' Open On-Chip Debugger 0.12.0 Licensed under GNU GPL v2 For bug reports, read http://openocd.org/doc/doxygen/bugs.html Info : auto-selecting first available session transport "jtag". To override use 'transport select '. adapter speed: 4000 kHz Info : Listening on port 6666 for tcl connections Info : Listening on port 4444 for telnet connections Info : J-Link V10 compiled Jan 30 2023 11:28:07 Info : Hardware version: 10.10 Info : VTarget = 3.244 V Info : clock speed 4000 kHz Info : JTAG tap: at91sama5d2.cpu tap/device found: 0x5ba00477 (mfg: 0x23b (ARM Ltd), part: 0xba00, ver: 0x5) Info : at91sama5d2.cpu_a5.0: hardware has 3 breakpoints, 2 watchpoints Info : at91sama5d2.cpu_a5.0: MPIDR level2 0, cluster 0, core 0, mono core, no SMT Info : starting gdb server for at91sama5d2.cpu_a5.0 on 3333 Info : Listening on port 3333 for gdb connections Notice that OpenOCD is listening on port 3333 for GDB connections. Using QEMU as GDB server ------------------------ When running U-Boot on QEMU you can used the '-gdb' parameter to provide a GDB server: qemu-system-riscv64 -M virt -nographic -gdb tcp::3333 -kernel u-boot Running a GDB session ---------------------- You need a GDB suited for your target. This can be the GDB coming with your toolchain or *gdb-multiarch* available in your Linux distribution. .. prompt:: bash $ gdb-multiarch u-boot In the above command-line *u-boot* is the U-boot binary in your build directory. You may need to adjust the path when calling GDB. Connect to the GDB server like this: .. code-block:: console (gdb) target extended-remote :3333 Remote debugging using :3333 0x27fa9ac6 in ?? () (gdb) This is fine for debugging before U-Boot relocates itself. For debugging U-Boot after relocation you need to indicate the relocation address to GDB. You can retrieve the relocation address from the U-Boot shell with the command *bdinfo*: .. code-block:: console U-Boot> bdinfo boot_params = 0x20000100 DRAM bank = 0x00000000 -> start = 0x20000000 -> size = 0x08000000 flashstart = 0x00000000 flashsize = 0x00000000 flashoffset = 0x00000000 baudrate = 115200 bps relocaddr = 0x27f7a000 reloc off = 0x0607a000 Build = 32-bit current eth = ethernet@f8008000 ethaddr = 00:50:c2:31:58:d4 IP addr = fdt_blob = 0x27b36060 new_fdt = 0x27b36060 fdt_size = 0x00003e40 lmb_dump_all: memory.cnt = 0x1 / max = 0x10 memory[0] [0x20000000-0x27ffffff], 0x08000000 bytes flags: 0 reserved.cnt = 0x1 / max = 0x10 reserved[0] [0x27b31d00-0x27ffffff], 0x004ce300 bytes flags: 0 devicetree = separate arch_number = 0x00000000 TLB addr = 0x27ff0000 irq_sp = 0x27b36050 sp start = 0x27b36040 Early malloc usage: cd8 / 2000 Look out for the line starting with *relocaddr* which has the address you need, ``0x27f7a000`` in this case. On most architectures (not sandbox, x86, Xtensa) the global data pointer is stored in a fixed register: ============ ======== Architecture Register ============ ======== arc r25 arm r9 arm64 x18 m68k d7 microblaze r31 mips k0 nios2 gp powerpc r2 riscv gp sh r13 ============ ======== On these architecture the relocation address cat be determined by dereferencing the global data pointer stored in register, *r9* in the example: .. code-block:: console (gdb) p/x (*(struct global_data*)$r9)->relocaddr $1 = 0x27f7a000 In the GDB shell discard the previously loaded symbol file and add it once again with the relocation address like this: .. code-block:: console (gdb) symbol-file Discard symbol table from `/home/adahl/build/u-boot/v2024.04.x/u-boot'? (y or n) y No symbol file now. (gdb) add-symbol-file u-boot 0x27f7a000 add symbol table from file "u-boot" at .text_addr = 0x27f7a000 (y or n) y Reading symbols from u-boot... (gdb) You can now use GDB as usual, setting breakpoints, printing backtraces, inspecting variables, stepping through the code, etc.