Debugging via gdb - DragonMinded/libdragon GitHub Wiki

This guide shows you how to setup gdb to debug a libdragon N64 rom running in the ares emulator.

These instructions were tested on Xubuntu 24.04.

  1. Make sure you have the latest build of ares
  2. Enable Homebrew mode and GDB debugging in ares settings

image image

In this example I also enabled IPv4 mode so the local address will be 127.0.0.1:9123

  1. Acquire a gdb build with MIPS support.

Your libdragon toolchain install should already have a gdb with MIPS support in $N64_INST/bin/mips64-elf-gdb. If not you can install it on Ubuntu sudo apt install gdb-multiarch (which I used in this guide) or build it via libdragon's tools/build_gdb.sh

  1. Build your rom with make D=1 to enable debugging. This flag is interpreted in the n64.mk file to add debug info but it doesn't explicitly change any optimization flags:
ifeq ($(D),1)
CFLAGS+=-g3
CXXFLAGS+=-g3
ASFLAGS+=-g
RSPASFLAGS+=-g
LDFLAGS+=-g
endif
  1. Test that gdb works on the command line. Load your ROM in ares:
ares myrom.z64

You should see the message "GDB Listening [::1]:9123" or "GDB Listening 127.0.0.1:9123" on the status bar, depending on if you use IPv6 or not:

image image

In another command-line window, run gdb-multiarch build/myrom.elf.

If you see a "safe-path" warning and the symbols aren't loaded, do as it says and create a ~/.config/gdb/gdbinit file that lists where you expect to load symbols.

warning: File "./build/myrom.elf" auto-loading has been declined by your `auto-load safe-path'
set to "$debugdir:$datadir/auto-load".
To enable execution of this file add
	add-auto-load-safe-path /home/user/dev/n64/myproject/build/myrom.elf

For example I have my code in ~/dev so my config looks like this:

cat ~/.config/gdb/gdbinit
set auto-load safe-path /home/user/dev/

Then try connecting to ares with the gdb command target remote 127.0.0.1:9123

(gdb) target remote 127.0.0.1:9123
Remote debugging using 127.0.0.1:9123
0x80031084 in __rsp_check_assert ()

Now ares should say "GDB Connected": image

We can verify it works by printing a backtrace with bt:

(gdb) bt
#0  0x80031084 in __rsp_check_assert ()
#1  0x8002ba68 in display_get ()
#2  0x800246c0 in main ()

You can continue execution with the c command. See this tutorial by Dragorn421 for an introduction to the gdb command line.

Great it works. Let's hook it up to VS Code.

  1. Set up Visual Studio Code GDB debugging.

Install the Microsoft "C/C++" ms-vscode.cpptools extension.

Then in your launch.json add the following entry. Click the gear icon in the debugging sidebar tab to access the file:

image

This is how my config looks:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "gdb",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceRoot}/build/myrom.elf",
            "miDebuggerServerAddress": "127.0.0.1:9123",
            "miDebuggerPath": "gdb-multiarch",
            "MIMode": "gdb",
            "cwd": "${workspaceFolder}",
            "miDebuggerArgs": "-readnow",
            "stopAtEntry": true,
            "sourceFileMap": {
                "libdragon": "../libdragon",
                "src/t3d": "../tiny3d/src/t3d"
            }
        }
    ]
}

The sourceFileMap object sets replacements of prefixes (keys) of source file paths reported by gdb with the given real paths (values). In my case I have the LibDragon and Tiny3D repos next to my project repo, so I added relative paths there.

Now when you start ares and then run your new launch config, the debugger should break into a random location:

image

image

Happy debugging! You can learn more about VS Code's debugger again in a guide by Dragorn421.

Troubleshooting

Constantly trapping

You need to update your ares emulator if you get an error like below and can't set any breakpoints.

Program received signal SIGTRAP, Trace/breakpoint trap.
0x8002aae4 in __display_callback ()
(gdb) bt
#0  0x8002aae4 in __display_callback ()
#1  0x80026e40 in __MI_handler ()
#2  0x80000628 in notcart ()
Backtrace stopped: frame did not save the PC

No symbols

If gdb-multiarch can't find any symbols, it might be out of date and the libdragon toolchain's gcc is generating symbols in an unsupported DWARF format. The "multiarch" version is nothing more than gdb built with more architectures in it. Unfortunately it's difficult to build on your own, so it's better to download a binary. On Ubuntu-based systems you can download a version for a different distro and hope it works despite dependencies being out of date!

If you're running an ancient Ubuntu, you can download a .deb for a newer version and extract the binary with

cd ~/Downloads
wget http://ge.archive.ubuntu.com/ubuntu/pool/universe/g/gdb/gdb-multiarch_15.1-1ubuntu2_amd64.deb 
ar -xvf gdb-multiarch_15.1-1ubuntu2_amd64.deb
# Warning: The following command generates ./usr/bin directories
tar -xvf data.tar.zst
./usr/bin/gdb-multiarch --version