Remote Debugging with GDB
This is adapted from xv6 instructions.
You’ll need two terminal windows. In the first window:
- ssh to gojira
cd /raid/$(whoami)/os-*
make qemu-gdb
- Note the last line of the output of the previous command. It should say something like
tcp::<PORT NUMBER HERE>
. For example, you might seetcp::26000
In the second window:
- ssh to gojira
cd /raid/$(whoami)/os-*
/opt/riscv/bin/riscv64-unknown-elf-gdb
- Inside the gdb prompt:
target remote localhost:<PORT NUMBER FROM POINT 4 ABOVE>
Once you’ve got that set up, you’re ready to debug!
NOTE: it might be worth creating an alias for /opt/riscv/bin/riscv64-unknown-elf-gdb
or adding /opt/riscv/bin/
to your $PATH
to make running it straightforward.
Making it easier
You might notice a warning like this when you start riscv64-unknown-elf-gdb
:
warning: File "/raid/mmalensek/os-malensek/.gdbinit" 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 /raid/mmalensek/os-malensek/.gdbinit
line to your configuration file "/home/mmalensek/.config/gdb/gdbinit".
If we fix this, then the last step in the section above isn’t needed. Using the paths in the warning message, I would run the following to add the necessary configuration to my .gdbinit
:
echo 'add-auto-load-safe-path /raid/mmalensek/os-malensek/.gdbinit' >> ~/.gdbinit
Now when you run /opt/riscv/bin/riscv64-unknown-elf-gdb
it will automatically connect to your qemu-gdb
instance.
gdb Dashboard
A nice improvement to the gdb UI is the gdb Dashboard. To use it, run:
wget -O - https://github.com/cyrus-and/gdb-dashboard/raw/master/.gdbinit >> ~/.gdbinit
Next time you run gdb you’ll see the changes.
Using gdb
Say you wanted to break every time the kernel enters the function syscall from kernel/syscall.c.
- Inside the gdb prompt:
file kernel/kernel
(this is a binary that has all kernel code) - Inside the gdb prompt:
b syscall
- Hit
c
. At this point you will start hitting the breakpoint above - Keep hitting
c
to see where the kernel hits the syscall function. You will how the output in the first window is progressing.
Now, say you wanted to break in the ls function in user/ls.c. Then, you would need to run file user/_ls at step 6 since this is the name of the binary where that function is. You would also run b ls like above.