Debugging Multiple Binaries With GDB/Eclipse
Ever need to debug multiple binaries? Say, a library and your app? Not fun. Fortunately, you can use GDB commands, Eclipse, and symbols to make the process easier.
Join the DZone community and get the full member experience.
Join For FreeWhen working and debugging a bootloader, debugging can be a challenge: While debugging the bootloader, a new binary gets loaded into the microcontroller address space, which is unknown to the debugger. As soon as I step into the newly loaded binary, I only see assembly code — with that ugly “No source available” in Eclipse:
No source available, debugging in assembly
But wait: GDB is able to do pretty much everything you can imagine, so here is how to debug multiple binaries with GDB and Eclipse and turn the above into something which is easy to debug:
Debugging with Symbolics
Outline
In many use cases, it is necessary to debug multiple binaries. One use case is with a bootloader (see Serial Bootloader for the Freedom Board with Processor Expert) or with using libraries (see Creating and using Libraries with ARM GCC and Eclipse). What is common in these cases is that the debugger might not have the necessary debug information (or ‘symbolics’) to display the source files and the variable information.
Code and Debug Information
‘Debug information’ is embedded and part of the .elf (ELF), which usually has DWARF debug information. When debugging an .elf file, that combined information is passed to the debugger, as shown below in the Eclipse launch configuration for GDB:
- Symbols file: This specifies which file is used for the debug information. The debug information is kept on the host and not downloaded to the target.
- Executable file: This file is used to download the code to the target. Only the code will be stored on the target.
Symbols and executable information
As above, usually, the symbols and executable file are the same, as the .elf file can contain both the code (ELF) and the debug (DWARF) information. Unless debug information is removed, of course (see Debug vs. Release?).
Adding Symbols
In the above setting, I have specified an executable and a symbols file. But how can I add more symbols for debugging? For example, a bootloader loads another executable or library. Or my microcontroller has a built-in library I need to debug.
What I need is the symbols or symbolic information. The easiest way is if I have that library (archive) or executable (.elf) with debug information. Then, I need to tell the debugger (GDB) that extra information needs to be added.
It is possible to generate files with symbolic information only (without the code) using the GNU tools.
The GNU debugger has the command:
add-symbol-file
(See GDB File Handling for a full description and other options.)
That adds extra debugging information the current debugging session.
For example, I use the following command to add symbolic information in the Eclipse (or GDB) console:
add-symbol-file "c://tmp//FRDM-K64F_Bootloader_test.elf" 0x8200
Adding symbols in GDB command line session
This adds that set of other debug information to the information already present, allowing me to debug that code:
Debugging with Symbolics
Offset for the Symbols
You might wonder about that offset of 0x8200 in the command at the end:
add-symbol-file "c://tmp//FRDM-K64F_Bootloader_test.elf" 0x8200
That’s the offset of the .text section of the code I have loaded. In my bootloader example, I load an executable with the vector table at 0x8000 and the code starting at 0x8200. The approach I’m using to determine that offset is to use the readelf program which is part of the GNU compiler suite. For example, it is part of the Kinetis Design Studio, too:
c:\nxp\KDS_3.2.0\Toolchain\bin\arm-none-eabi-readelf.exe -WS c:\tmp\FRDM-K64F_Bootloader_Test.elf
The -WS option dumps the symbolics (-S) in wide (-W) format: For the above case it produces the following:
There are 23 section headers, starting at offset 0x1354e8:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interrupts PROGBITS 00008000 008000 000198 00 A 0 0 4
[ 2] .text PROGBITS 00008200 008200 000da0 00 AX 0 0 4
[ 3] .ARM ARM_EXIDX 00008fa0 008fa0 000008 00 AL 2 0 4
[ 4] .init_array INIT_ARRAY 00008fa8 008fa8 000004 00 WA 0 0 4
[ 5] .fini_array FINI_ARRAY 00008fac 008fac 000004 00 WA 0 0 4
[ 6] .data PROGBITS 20000000 010000 000060 00 WA 0 0 4
[ 7] .bss NOBITS 20000060 010060 000034 00 WA 0 0 4
[ 8] .romp PROGBITS 20000094 010094 000024 00 WA 0 0 1
[ 9] ._user_heap_stack NOBITS 200000b8 0100b8 000400 00 WA 0 0 1
[10] .ARM.attributes ARM_ATTRIBUTES 00000000 0100b8 000030 00 0 0 1
[11] .debug_info PROGBITS 00000000 0100e8 002cbc 00 0 0 1
[12] .debug_abbrev PROGBITS 00000000 012da4 000c85 00 0 0 1
[13] .debug_aranges PROGBITS 00000000 013a29 0005c0 00 0 0 1
[14] .debug_ranges PROGBITS 00000000 013fe9 0004f0 00 0 0 1
[15] .debug_macro PROGBITS 00000000 0144d9 02f96a 00 0 0 1
[16] .debug_line PROGBITS 00000000 043e43 005026 00 0 0 1
[17] .debug_str PROGBITS 00000000 048e69 0eb25b 01 MS 0 0 1
[18] .comment PROGBITS 00000000 1340c4 000070 01 MS 0 0 1
[19] .debug_frame PROGBITS 00000000 134134 0012c4 00 0 0 4
[20] .shstrtab STRTAB 00000000 1353f8 0000ee 00 0 0 1
[21] .symtab SYMTAB 00000000 135880 000f90 10 22 182 4
[22] .strtab STRTAB 00000000 136810 000803 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
For the add-symbol-file
GDB command, the offset of the .text section is relevant:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 2] .text PROGBITS 00008200 008200 000da0 00 AX 0 0 4
With this, I have the offset I can use with the command:
add-symbol-file c://tmp//FRDM-K64F_Bootloader_test.elf 0x8200
add symbol table from file "c://tmp//FRDM-K64F_Bootloader_test.elf" at
.text_addr = 0x8200
(y or n) [answered Y; input not from terminal]
Reading symbols from c:\tmp\FRDM-K64F_Bootloader_test.elf...done.
With this, I’m able to debug the loaded code because I have told GDB that the debug information (line and debug information) is loaded at 0x8200.
Finding and Checking Symbol Information
With the symbol information loaded, I should be able to debug that newly loaded code like normal code. I can use the GDB ‘info symbol’ command with an address to check which function is located at address 0x8254:
info symbol 0x8254
_start in section .text of c:\tmp\FRDM-K64F_Bootloader_test.elf
So gdb tells me that at the address 0x8254 the function _start() is loaded (based on the symbols I have provided).
Automating Adding Symbols
Instead of adding symbols interactively during the debug session, I can pass that information at debugger startup. Most Eclipse-based GDB debuggers (including the NXP Kinetis Design Studio) have a setting in the launch configuration to pass commands and scripting to the GDB. Below, you can see an example with the GNU ARM Eclipse plugins:
Running the GDB command to load symbols
There, I can add any kind of GDB commands I like.
Summary
Typically, all the debug information needed is in the binary under debug. But often, the debugger doesn't have all the information needed. In that case, I can use GDB commands to add the necessary debug information and symbolics information. I can add this information during debug, or I can automate things using the Eclipse launch configuration.
Published at DZone with permission of Erich Styger, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments