U-Boot - How to debug

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

Debug with console

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

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

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

  • 在<file>.c文件包含任何之前定义调试
 #define DEBUG
 #undef CONFIG_LOGLEVEL
 #define CONFIG_LOGLEVEL 8
  • 使用 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

在OpenSTLinux中,可以直接使用GDB脚本Setup.gdb:

或者对于手动GDB连接,您需要:

  1. 获取U-Boot和/或SPL的elf files
    (构建目录中提供了u-boot和u-boot-spl)
  2. GDB连接到目标
  3. 使用 gdb"monitor reset halt"命令reset with attach复位目标:
    在ROM代码中或在FSBL执行开始时停止执行。
  4. 加载二进制文件的符号,以便在下一章中用可用的命令进行调试:
    #Load U-Boot symbol, #Load SPL symbol, #Load SPL code and debug
  5. 使用 "continue" 命令开始执行。

Load U-Boot symbol

使用U-Boot relocation时,符号更难加载。

请参阅 https://www.denx.de/wiki/DULG/DebuggingUBoot

如果在运行的目标上连接GDB,则可以加载调试符号:

  • 在使用 "symbol-file" 命令进行重定位之前:
 (gdb) symbol-file u-boot
  • 使用"add-symbol-file" 命令重定位后,使用代码 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

以下GDB示例脚本在"monitor reset halt" 命令之后,在为编程板重定位前后自动加载U-Boot符号:

 (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

当通过U-Boot入口点(CONFIG_SYS_TEXT_BASE = 0xC0100000)处的FSBL=TF-A或SPL将U-Boot代码加载到DDR中时,此脚本使用临时硬件断点"thbreak" 加载符号。 它只允许在执行代码时加载符号,以避免在DDR初始化之前访问DDR。

Load SPL symbol

要在闪存设备上使用GDB调试SPL,ROM代码加载二进制文件,GDB脚本只加载SPL符号:

 (gdb) symbol-file u-boot-spl

Load SPL code and debug

有时,您需要在未编程的目标上调试SPL执行(例如,用于电路板启动),因此您可以使用GDB将SPL代码加载到嵌入式RAM中并执行。

在ROM代码中停止执行时,您需要执行"load"命令,具体取决于 U-Boot device tree 中定义的编译标志来加载SPL代码和关联的设备树:

  • CONFIG_OF_SEPARATE = dtb 附加在代码末尾,不存在于elf文件中(默认配置)
 (gdb) file u-boot-spl
 (gdb) load
 (gdb) set $dtb =  __bss_end
 (gdb) restore spl/dt.dtb binary $dtb
  • CONFIG_OF_EMBED = dtb 嵌入elf文件中(调试配置)
 (gdb) file u-boot-spl
 (gdb) load

Debug the first SPL instructions

有时,在第一条指令之后,gdb命令 "monitor reset halt" 会停止SPL代码的执行。

要调试这部分代码,可以修改代码:在SPL代码中添加一个无限循环以等待gdb连接。

例如,在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();

当连接gdb并加载SPL符号时,无限循环会因以下原因中断:

 (gdb) set var stop=1

您可以通过gdb命令调试SPL first指令。 <securetransclude src="ProtectedTemplate:PublicationRequestId" params="12894 | 2019-08-01 |"></securetransclude>