-
Notifications
You must be signed in to change notification settings - Fork 68
Source Level Debug with XQEMU
One method to debug your nxdk application is to run it within XQEMU, and connect using GDB, or another debugger which can communicate through the GDB remote protocol. In this example, GDB is used.
Note: this is not an introduction to XQEMU, nor GDB, just a quick-start guide.
Let's start with a simple example and try to build a sample:
cd <path to nxdk>/samples/mesh
We need to explicitly specify that we want debug information to be included in the binary. To do this, specify DEBUG=y
(or define it in your project Makefile). For example, to build with debugging symbols:
make clean
make DEBUG=y -j12
Now we need to get the virtual address of the sections which we are interested in. There are several ways to do this, such as using the xbedump tool.
$ ../../tools/xbedump/xbe bin/default.xbe -ds | grep -i "address"
Virtual address : 0x00011000
File address : 0x00001000
Section name Address : 0x00010676 (".rdata")
Virtual address : 0x00055000
File address : 0x00045000
Section name Address : 0x0001067D (".bss")
Virtual address : 0x00058000
File address : 0x00046000
Section name Address : 0x00010682 (".data")
Virtual address : 0x00060000
File address : 0x0004E000
Section name Address : 0x00010688 (".text")
Virtual address : 0x00095000
File address : 0x00083000
Section name Address : 0x0001068E (".tls")
Virtual address : 0x00096000
File address : 0x00084000
Section name Address : 0x00010693 (".idata")
...
Here you can see that the ".text" section is loaded at virtual address 0x60000, .bss at 0x55000, .data at 0x58000, and .rdata 0x11000. There are other sections which we will ignore for now.
Run XQEMU as normal, but append to the command line the -s
flag to enable the GDB server, and the -S
flag to get XQEMU to wait for you to connect before allowing the virtual CPU to execute any code. A GDB server is now running at 127.0.0.1:1234
, halted at the reset vector (CPU startup), waiting for you to connect.
Start gdb
and run the following commands, or put them in a .gdbinit
file to be run automatically whenever you start GDB in this directory:
# Tell GDB that we are using 32-bit x86 architecture
set arch i386
# Tell GDB to load symbols from main.exe, with the addresses of all
# sections (e.g. .text section at virtual address 0x60000).
#
# Notice here that we are using the .exe file, not the .xbe file, as
# GDB does not understand the .xbe format.
#
add-symbol-file main.exe 0x60000 -s .bss 0x55000 -s .data 0x58000 -s .rdata 0x11000
# Use a layout which shows source code
layout src
# Connect to the XQEMU GDB server
target remote 127.0.0.1:1234
# Stop execution at the beginning of the `main` function
b main
# Let XQEMU run until the CPU tries to execute from the address
# we have placed our breakpoint(s)
c
Now XQEMU will run until the CPU begins executing the main
function. Once the breakpoint is hit, or if you press Ctrl-C
at any time, GDB will present an interactive shell. From here, you can:
- Print (or modify) variables (
p var
), - Navigate stack frames (
up
,down
), - Set additional breakpoints (
b
, e.g. at line 120b main.c:120
), - Step to the next line of source code (
n
), or - Allow the CPU to run normally (
c
) until the next breakpoint is encountered.