U-Boot - How to debug

来自百问网嵌入式Linux wiki
Wiki讨论 | 贡献2020年11月3日 (二) 14:43的版本 →‎Debug with console

Debug with console

跟踪和错误在设备树的chosen 节点中通过 stdout-path 字段定义的控制台上可用,例如在serial0 = uart4上:

 chosen {
 	stdout-path = " serial0:115200n8";
 };
 aliases {
 	serial0 = &uart4;
 };

默认情况下,U-Boot使用的宏 (debug(), pr_debug()...)不打印任何跟踪;要激活特定文件上的调试跟踪,需要启用 DEBUG 编译标志并更改文件的LOGLEVEL:

  • define DEBUG before any include in the <file>.c file
 #define DEBUG
 #undef CONFIG_LOGLEVEL
 #define CONFIG_LOGLEVEL 8
  • with a Makefile
 CFLAGS_<file>.o+= -DDEBUG -DCONFIG_LOGLEVEL=8

如果在配置控制台之前(在执行U-Boot的第一阶段)U-Boot失败,则跟踪不可用。

在这种情况下,您需要:

  • 用GDB调试 (请参阅下一章)

或,

  • 激活调试UART功能:
    • U-Boot configuration的defconfig中添加
      • CONFIG_DEBUG_UART
      • CONFIG_DEBUG_UART_STM32
    • adpat 这个函数 board_debug_uart_init(): 在通过U-Boot驱动程序初始化之前配置所需的资源 (pad, clock)。
      此功能需要针对您的主板进行调整。

Debug with GDB

With OpenSTLinux, you can directly use GDB script Setup.gdb:

Or for manual GDB connection, you need to:

  1. get the elf files for U-Boot and/or SPL
    (u-boot and u-boot-spl available in the build directory)
  2. connect GDB to the target
  3. reset with attach the target with the gdb "monitor reset halt" command:
    execution is stopped in ROM code or at the beginning of FSBL execution.
  4. load the symbols of the binary to be debugged with commands available in next chapter:
    #Load U-Boot symbol, #Load SPL symbol, #Load SPL code and debug
  5. start execution with the "continue" command

Load U-Boot symbol

With U-Boot relocation, symbols are more difficult to load.

See https://www.denx.de/wiki/DULG/DebuggingUBoot

If you connect GDB on running target, you can load the debug symbols:

  • Before relocation with "symbol-file" command:
 (gdb) symbol-file u-boot
  • After relocation with "add-symbol-file" command to relocate the symbol with the code offset = gd->relocaddr:
 (gdb) symbol-file u-boot                            --> only for "gd_t" definition
 (gdb) set $offset = ((gd_t *)$r9)->relocaddr        --> get relocation offset
 (gdb) symbol-file                                   --> clear previous symbol 
 (gdb) add-symbol-file u-boot $offset

The following GDB example script automatically loads the U-Boot symbol before and after relocation for a programmed board, after "monitor reset halt" command:

 (gdb) thbreak *0xC0100000
 (gdb) commands
 > symbol-file u-boot
 > thbreak relocate_code
 > commands
   > print "RELOCATE U-Boot..."
   > set $offset = ((gd_t *)$r9)->relocaddr
   > print $offset
   > symbol-file
   > add-symbol-file u-boot $offset
   > thbreak boot_jump_linux
   > continue
   > end
 > continue
 > end

This script uses a temporary hardware breakpoint "thbreak" to load the symbol when U-Boot code is loaded in DDR by FSBL = TF-A or SPL at the U-Boot entry point (CONFIG_SYS_TEXT_BASE = 0xC0100000).

It allows the symbol to be loaded only when code is executed to avoid DDR access before DDR initialization.

Load SPL symbol

To debug SPL with GDB on a Flashed device, ROM code loads the binary and the GDB script just loads the SPL symbols:

 (gdb) symbol-file u-boot-spl

Load SPL code and debug

Sometimes you need to debug SPL execution on an unprogrammed target (for example for board bring-up), so you can use GDB to load the SPL code in embedded RAM and execute it.

When execution is stopped in ROM code, you need to execute the "load" commands, depending on the compilation flags defined in U-Boot device tree to load the SPL code and the associated device tree:

  • CONFIG_OF_SEPARATE = dtb appended at the end of the code, not present in the elf file (default configuration)
 (gdb) file u-boot-spl
 (gdb) load
 (gdb) set $dtb =  __bss_end
 (gdb) restore spl/dt.dtb binary $dtb
  • CONFIG_OF_EMBED = dtb embedded in the elf file (debug configuration)
 (gdb) file u-boot-spl
 (gdb) load

Debug the first SPL instructions

Sometime the SPL code execution is stopped by the gdb command "monitor reset halt" after the first instructions.

To debug this part, you can modify the code: add a infinite loop in SPL code to wait the gdb connection.

For example in arch/arm/mach-stm32mp/spl.c| |}} arch/arm/mach-stm32mp/spl.c  :

void board_init_f(ulong dummy)
{
	struct udevice *dev;
	int ret;

	/* volatile is needed to avoid gcc optimization */
	volatile int stop = 0;
	/* infinite debug loop */
	while ( !stop ) ;

	arch_cpu_init();

when gdb is attached and the SPL symbols are loaded, the infinite loop is interrupted by :

 (gdb) set var stop=1

And you can debug the SPL first instruction by gdb commands. <securetransclude src="ProtectedTemplate:PublicationRequestId" params="12894 | 2019-08-01 |"></securetransclude>