Last edited 6 months ago

U-Boot - How to debug: Difference between revisions

Registered User
mNo edit summary
Registered User
mNo edit summary
Tag: 2017 source edit
 
(34 intermediate revisions by 4 users not shown)
Line 1: Line 1:
<noinclude>{{ApplicableFor
|MPUs list=STM32MP13x, STM32MP15x,STM32MP21x,STM32MP23x,STM32MP25x
|MPUs checklist=STM32MP13x,STM32MP15x,STM32MP21x,STM32MP23x,STM32MP25x
}}</noinclude>
== Debug with console ==
== Debug with console ==
Trace and error are available on the console defined in the '''chosen''' node of the device tree by the '''stdout-path''' field, for example on serial0=uart4:


  chosen {
See {{DocSource | domain=U-Boot |path=develop/logging.html | text=U-Boot Documentation}} or {{CodeSource | U-Boot |doc/develop/logging.rst}} for U-Boot logging details.
  stdout-path = " {{Highlight|serial0}}:115200n8";
  };
  aliases {
  {{Highlight|serial0}} = &{{Highlight|uart4}};
  };


By default, the macros used by U-Boot (debug(), pr_debug()...) do not print any trace; to activate the debug traces on a specific file, you need to enable the '''DEBUG''' compilation flag and change the LOGLEVEL for the file:
'''CONFIG_LOG''' is enable in OpenSTLinux.
* define DEBUG before any include in the <file>.c file
 
   #define DEBUG
By default, traces are available on the U-Boot console which use <code>stdout-path</code> defined in the <code>chosen</code> node of the Linux kernel device tree as described in the Linux kernel binding<ref>[https://github.com/devicetree-org/dt-schema/blob/main/dtschema/schemas/chosen.yaml dtschema/schemas/chosen.yaml] the Linux kernel binding for chosen node</ref>.
   #undef CONFIG_LOGLEVEL
 
  #define CONFIG_LOGLEVEL 8
See page [[How_to_configure_U-Boot_for_your_board#Console|How to configure U-Boot for your board]] for configuration details.
 
The ST boards use the default logging configuration:
* {{highlight|CONFIG_LOG_DEFAULT_LEVEL}} = {{highlight|CONFIG_LOG_MAX_LEVEL}} =  {{highlightParam|LOGL_INFO}} = {{highlightParam|6}}<br/>the 'debug' macros used by U-Boot (log_debug(), debug(), pr_debug()...) are removed in the U-Boot binary.
* CONFIG_LOGF_FILE, CONFIG_LOGF_LINE, CONFIG_LOGF_FUNC are not activated<br/>no debug information in log messages by default.
 
To enable all the debug traces in U-Boot you need to increase the max logging level with a major impact on U-Boot size; e.g. set {{highlight|CONFIG_LOG_MAX_LEVEL}} to {{highlightParam|LOGL_DEBUG}} by adding in your defconfig file the line:
 
  {{highlight|CONFIG_LOG_MAX_LEVEL}}={{HighlightParam|7}}
 
When the traces are present in U-Boot, you can change the default trace level with {{highlight|CONFIG_LOG_DEFAULT_LEVEL}} or you can use the <code>log</code> command (CONFIG_CMD_LOG) to dynamically configure and filter the output:
 
  {{U-Boot$}}log level 7
  {{U-Boot$}}log format all
 
=== Activate debug trace on one file ===
 
To turn on this debug logging just in one file, you can define {{highlight|LOG_DEBUG}} for this file  
 
* add define before any include in the <file>.c file
   #define {{highlight|LOG_DEBUG}}
   #include <common.h>


* with a Makefile
* with a Makefile
   CFLAGS_<file>.o+= -DDEBUG -DCONFIG_LOGLEVEL=8
   CFLAGS_<file>.o+= -D{{highlight|LOG_DEBUG}}


For details, see {{CodeSource | U-Boot |doc/README.log}}.
=== Debug before console ===


If U-Boot fails before the console configuration (in the first stage of U-Boot execution), trace is not available.
If U-Boot fails before the console configuration (in the first stage of U-Boot execution), trace is not available.
Line 29: Line 48:
*** {{Highlight|CONFIG_DEBUG_UART}}
*** {{Highlight|CONFIG_DEBUG_UART}}
*** {{Highlight|CONFIG_DEBUG_UART_STM32}}
*** {{Highlight|CONFIG_DEBUG_UART_STM32}}
** adpat the function {{Highlight|board_debug_uart_init()}}: that configures the required resources (pad, clock) before initialization by the U-Boot driver.<br/>This function needs to be adapted for your board.
 
{{Info | For {{MicroprocessorDevice | device=1}}, the function {{CodeSource | U-Boot |board/st/stm32mp1/debug_uart.c|board_debug_uart_init()}} configures the required resources (pad, clock) before initialization by the U-Boot driver and this function can  be adapted for your board.<br/>This adaptation is '''not required for OpenSTLinux''' because UART is initialized in TF-A and in OP-TEE and <code>debug_uart_init()</code> is not called in {{CodeSource | U-Boot | board/st/stm32mp1/debug_uart.c |mach_cpu_init()}}.}}


== Debug with GDB ==
== Debug with GDB ==
Line 38: Line 58:


Or for manual GDB connection, you need to:
Or for manual GDB connection, you need to:
# get the [[U-Boot_overview#Output_files|elf files]] for U-Boot and/or SPL<br/>(u-boot and u-boot-spl available in the build directory)
# get the [[U-Boot_overview#Output_files|elf files]] for U-Boot = <code>u-boot</code> available in the build directory
# connect [[GDB]] to the target
# connect [[GDB]] to the target
# '''reset with attach''' the target with the gdb {{Highlight|"monitor reset halt"}} command:<br/>execution is stopped in ROM code or at the beginning of FSBL execution.
# '''reset with attach''' the target with the gdb {{Highlight|"monitor reset halt"}} command:<br/>execution is stopped in ROM code or at the beginning of FSBL execution.
# load the symbols of the binary to be debugged with commands available in next chapter:<br/>[[#Load U-Boot symbol]], [[#Load SPL symbol]],  [[#Load SPL code and debug]]
# load the symbols of the binary to be debugged with commands available in next chapter:<br/>[[#Load U-Boot symbol]]
# start execution with the {{Highlight|"continue"}} command
# start execution with the {{Highlight|"continue"}} command


=== Load U-Boot symbol ===
=== Load U-Boot symbol ===


With [[U-Boot_overview#U-Boot_phases|U-Boot relocation]], symbols are more difficult to load.
With [[U-Boot_overview#U-Boot_execution_sequence|U-Boot relocation]], symbols are more difficult to load, see {{CodeSource | U-Boot | doc/README.arm-relocation}} for details.  
 
See https://www.denx.de/wiki/DULG/DebuggingUBoot


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


* Before relocation with {{Highlight|"symbol-file"}} command:
* Before relocation with {{Highlight|"symbol-file"}} command:
   {{GDB$}} {{Highlight|symbol-file u-boot}}
   {{GDB$}}{{Highlight|symbol-file u-boot}}


* After relocation with {{Highlight|"add-symbol-file"}} command to relocate the symbol with the code offset = gd->relocaddr:
* After relocation with {{Highlight|"add-symbol-file"}} command to relocate the symbol with the code offset = gd->relocaddr:
  {{GDB$}} symbol-file u-boot                            {{Highlight|--> only for "gd_t" definition}}
  {{GDB$}} set $offset = ((gd_t *)$r9)->relocaddr        {{Highlight|--> get relocation offset}}
  {{GDB$}} symbol-file                                  {{Highlight|--> clear previous symbol }}
  {{GDB$}} {{Highlight|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 {{Highlight|"monitor reset halt"}} command:
:* for {{MicroprocessorDevice | device=1}} (AARCH32)
 
  {{GDB$}}symbol-file u-boot                            {{Highlight|--> only for "gd_t" definition}}
  {{GDB$}}set $offset = ((gd_t *)${{Highlight|r9}})->relocaddr        {{Highlight|--> get relocation offset, gd in r9 register}}
  {{GDB$}}symbol-file                                  {{Highlight|--> clear previous symbol }}
  {{GDB$}}{{Highlight|add-symbol-file u-boot $offset}}
 
:* for {{MicroprocessorDevice | device=2}} (AARCH64)
 
  {{GDB$}}symbol-file u-boot                            {{Highlight|--> only for "gd_t" definition}}
  {{GDB$}}set $offset = ((gd_t *)${{Highlight|x18}})->relocaddr      {{Highlight|--> get relocation offset, gd in x18 register}}
  {{GDB$}}symbol-file                                  {{Highlight|--> clear previous symbol }}
  {{GDB$}}{{Highlight|add-symbol-file u-boot $offset}}
 
The following GDB example scripts automatically loads the U-Boot symbol before and after relocation for a programmed board, after {{Highlight|"monitor reset halt"}} command.
 
These GDB scripts use a temporary hardware breakpoint {{Highlight|"thbreak"}} to load the symbol when U-Boot code is loaded in DDR by FSBL = TF-A at the U-Boot entry point, CONFIG_TEXT_BASE.<br/>It allows the symbol to be loaded only when code is executed to avoid DDR access before DDR initialization.
 
* for {{MicroprocessorDevice | device=1}} (AARCH32)


   {{GDB$}} thbreak *0xC0100000
   {{GDB$}}thbreak *{{HighlightParam|0xC0100000}}
   {{GDB$}} commands
   {{GDB$}}commands
   > symbol-file u-boot
   > symbol-file u-boot
   > thbreak relocate_code
   > thbreak relocate_code
   > commands
   > commands
     > print "RELOCATE U-Boot..."
     > print "RELOCATE U-Boot..."
     > set $offset = ((gd_t *)$r9)->relocaddr
     > set $offset = ((gd_t *)${{Highlight|r9}})->relocaddr
     > print $offset
     > print $offset
     > symbol-file
     > symbol-file
Line 79: Line 111:
   > end
   > end


This script uses a temporary hardware breakpoint {{Highlight|"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).
With CONFIG_TEXT_BASE =
:* {{HighlightParam|0xC0000000}} for {{MicroprocessorDevice | device=13}}
:* {{HighlightParam|0xC0100000}} for {{MicroprocessorDevice | device=15}}


It allows the symbol to be loaded only when code is executed to avoid DDR access before DDR initialization.
* for {{MicroprocessorDevice | device=2}} (AARCH64)


=== Load SPL symbol ===
   {{GDB$}}thbreak *{{HighlightParam|0x84000000}}
 
   {{GDB$}}commands
To debug SPL with GDB on a Flashed device, ROM code loads the binary and the GDB script just loads the SPL symbols:
  > symbol-file u-boot
 
   > thbreak relocate_code
   {{GDB$}} symbol-file u-boot-spl
   > commands
 
    > print "RELOCATE U-Boot..."
=== Load SPL code and debug ===
    > set $offset = ((gd_t *)${{Highlight|x18}}->relocaddr
 
    > print $offset
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.
    > symbol-file
 
    > add-symbol-file u-boot $offset
When execution is stopped in ROM code, you need to execute the {{Highlight|"load"}} commands, depending on the compilation flags defined in [[U-Boot_overview#Device_tree|U-Boot device tree]] to load the SPL code and the associated device tree:
    > thbreak boot_jump_linux
 
    > continue
* CONFIG_OF_SEPARATE = dtb appended at the end of the code, not present in the elf file (default configuration)
    > end
 
  > continue
   {{GDB$}} file u-boot-spl
  > end
   {{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 {{CodeSource | U-Boot | arch/arm/mach-stm32mp/spl.c}} :
 
<syntaxhighlight lang="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();
</syntaxhighlight>
 
when gdb is attached and the SPL symbols are loaded, the infinite loop is interrupted by :


  {{GDB$}} set var stop=1
With CONFIG_TEXT_BASE =
:* {{HighlightParam|0x84000000}} for {{MicroprocessorDevice | device=2}}


And you can debug the SPL first instruction by gdb commands.
== References ==
<references/>


<noinclude>
<noinclude>
[[Category:U-Boot]]
[[Category:U-Boot|U-Boot - 8]]
[[Category:Tracing tools]]
[[Category:Tracing tools]]
[[Category:Debugging tools]]
[[Category:Debugging tools]]
{{PublicationRequestId | 12894 | 2019-08-01}}
{{PublicationRequestId | 12894 | 2019-08-01}}
</noinclude>
</noinclude>

Latest revision as of 15:47, 4 November 2024

Applicable for STM32MP13x lines, STM32MP15x lines, STM32MP21x lines, STM32MP23x lines, STM32MP25x lines

1. Debug with console[edit | edit source]

See U-Boot Documentation or doc/develop/logging.rst for U-Boot logging details.

CONFIG_LOG is enable in OpenSTLinux.

By default, traces are available on the U-Boot console which use stdout-path defined in the chosen node of the Linux kernel device tree as described in the Linux kernel binding[1].

See page How to configure U-Boot for your board for configuration details.

The ST boards use the default logging configuration:

  • CONFIG_LOG_DEFAULT_LEVEL = CONFIG_LOG_MAX_LEVEL = LOGL_INFO = 6
    the 'debug' macros used by U-Boot (log_debug(), debug(), pr_debug()...) are removed in the U-Boot binary.
  • CONFIG_LOGF_FILE, CONFIG_LOGF_LINE, CONFIG_LOGF_FUNC are not activated
    no debug information in log messages by default.

To enable all the debug traces in U-Boot you need to increase the max logging level with a major impact on U-Boot size; e.g. set CONFIG_LOG_MAX_LEVEL to LOGL_DEBUG by adding in your defconfig file the line:

 CONFIG_LOG_MAX_LEVEL=7

When the traces are present in U-Boot, you can change the default trace level with CONFIG_LOG_DEFAULT_LEVEL or you can use the log command (CONFIG_CMD_LOG) to dynamically configure and filter the output:

 log level 7
 log format all

1.1. Activate debug trace on one file[edit | edit source]

To turn on this debug logging just in one file, you can define LOG_DEBUG for this file

  • add define before any include in the <file>.c file
 #define LOG_DEBUG
 #include <common.h>
  • with a Makefile
 CFLAGS_<file>.o+= -DLOG_DEBUG

1.2. Debug before console[edit | edit source]

If U-Boot fails before the console configuration (in the first stage of U-Boot execution), trace is not available.

In this case, you need to:

  • debug with GDB (see the next chapter)

or,

  • activate the debug UART feature:
Info white.png Information
For STM32MP1 series, the function board_debug_uart_init() configures the required resources (pad, clock) before initialization by the U-Boot driver and this function can be adapted for your board.
This adaptation is not required for OpenSTLinux because UART is initialized in TF-A and in OP-TEE and debug_uart_init() is not called in mach_cpu_init() .

2. Debug with GDB[edit | edit source]

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 = u-boot 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
  5. start execution with the "continue" command

2.1. Load U-Boot symbol[edit | edit source]

With U-Boot relocation, symbols are more difficult to load, see doc/README.arm-relocation for details.

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:
  • for STM32MP1 series (AARCH32)
 (gdb)symbol-file u-boot                            --> only for "gd_t" definition
 (gdb)set $offset = ((gd_t *)$r9)->relocaddr        --> get relocation offset, gd in r9 register
 (gdb)symbol-file                                   --> clear previous symbol 
 (gdb)add-symbol-file u-boot $offset
  • for STM32MP2 series (AARCH64)
 (gdb)symbol-file u-boot                            --> only for "gd_t" definition
 (gdb)set $offset = ((gd_t *)$x18)->relocaddr       --> get relocation offset, gd in x18 register
 (gdb)symbol-file                                   --> clear previous symbol 
 (gdb)add-symbol-file u-boot $offset

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

These GDB scripts use a temporary hardware breakpoint "thbreak" to load the symbol when U-Boot code is loaded in DDR by FSBL = TF-A at the U-Boot entry point, CONFIG_TEXT_BASE.
It allows the symbol to be loaded only when code is executed to avoid DDR access before DDR initialization.

  • for STM32MP1 series (AARCH32)
 (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

With CONFIG_TEXT_BASE =

  • 0xC0000000 for STM32MP13x lines More info.png
  • 0xC0100000 for STM32MP15x lines More info.png
  • for STM32MP2 series (AARCH64)
 (gdb)thbreak *0x84000000
 (gdb)commands
 > symbol-file u-boot
 > thbreak relocate_code
 > commands
   > print "RELOCATE U-Boot..."
   > set $offset = ((gd_t *)$x18->relocaddr
   > print $offset
   > symbol-file
   > add-symbol-file u-boot $offset
   > thbreak boot_jump_linux
   > continue
   > end
 > continue
 > end

With CONFIG_TEXT_BASE =

  • 0x84000000 for STM32MP2 series

3. References[edit | edit source]

  1. dtschema/schemas/chosen.yaml the Linux kernel binding for chosen node