blob: a360ee0f8d0975844dd0399c6055a44d41a0b8ee [file] [log] [blame] [view]
# How to Use GDB with Renode to Debug seL4 Threads with Symbols
## High-Level Usage
The method for debugging seL4 threads with Renode is relatively simple, and
involves the usual suspects of `m simulate-debug` and `kgdb.sh`, but the
interface through GDB has changed slightly. In general, a debugging session now
looks like the following:
On one terminal, start an instance of Renode:
```bash
source build/setup.sh
m simulate-debug
```
Once Renode has started and starts outputting green debug logs, in another
terminal start up GDB with:
```bash
kgdb.sh
```
At this point, GDB should connect to the running Renode instance started by
`simulate-debug`, and you'll see something equivalent to the following (output
is not exact -- symbol reading may differ):
```
ghost:~/$ kgdb.sh
Source directories searched: /usr/local/google/home/jtgans/shodan/sw/tock:$cdir:$cwd
Reading symbols from out/shodan_boot_rom/build-out/multihart_boot_rom/multihart_boot_rom_sim_verilator.elf...
add symbol table from file "out/shodan_boot_rom/build-out/multihart_boot_rom/multihart_boot_rom_sim_verilator.elf"
Reading symbols from out/shodan_boot_rom/build-out/multihart_boot_rom/multihart_boot_rom_sim_verilator.elf...
add symbol table from file "out/matcha/riscv32imc-unknown-none-elf/debug/matcha_platform"
Reading symbols from out/matcha/riscv32imc-unknown-none-elf/debug/matcha_platform...
add symbol table from file "out/matcha/riscv32imc-unknown-none-elf/debug/matcha_app"
Reading symbols from out/matcha/riscv32imc-unknown-none-elf/debug/matcha_app...
Remote debugging using localhost:3333
warning: multi-threaded target stopped without sending a thread-id, using first non-exited thread
0x20007b4a in tock_cells::map_cell::MapCell<kernel::callback::AppId>::is_some<kernel::callback::AppId> (self=0x10005af4 <matcha_platform::reset_handler::BUF>)
at /usr/local/google/home/jtgans/shodan/sw/tock/libraries/tock-cells/src/map_cell.rs:47
47 self.occupied.get()
(gdb)
```
At this point, GDB has stopped the simulator, giving you a chance to set
breakpoints and examine the system.
`kgdb.sh` will automatically load symbols on the seL4 side, based upon their
thread names, so there is no need to manually find the associated symbol file
and load it with the correct offsets. It may be necessary to switch symbol
tables, which can easily be done using `sel4 switch-symbols <threadname>`, which
will automatically load them with the appropriate offsets.
In this environment, there are two sets of breakpoints that can be used:
standard gdb `break`-style breakpoints, and renode-side `sel4 break`
breakpoints. The former work within the currently executing thread and can be
used for "local" breaks inside of a thread, whereas the latter can be set in any
thread that was previously discovered by the Renode extension.
Once you've setup your breakpoints using `sel4 break`, you'll need to tell
Renode to enable breakpoints as well with `sel4 breakpoints-enabled True`, and
then `continue`. For example, consider this debugging session:
```
<assuming cpu1 is halted and gdb is waiting at a prompt>
(gdb) # Wait until 'rootserver' thread is set up in seL4
(gdb) sel4 wait-for-thread rootserver
(gdb) # rootserver thread is now the symbol "main" in the thread/program, so we
(gdb) # can break on stopped and associated symbols are loaded.
(gdb) sel4 break rootserver main
(gdb) # Enable extension breakpoints (it's disabled by default as it's pretty
(gdb) # performance-heavy as Renode has to break on every context-switch)
(gdb) sel4 breakpoints-enabled True
(gdb) c
(gdb) # We are in capdl-loader main() function, disable extension breakpoints
(gdb) sel4 breakpoints-enabled False
(gdb) # As we are in capdl-loader thread and proper symbols are loaded, all commands
(gdb) # like break are working correctly
(gdb) b init_system
(gdb) c
```
## Theory of Operation
The kgdb.sh / Renode symbol lookup mechanism is composed of two parts: a custom
Renode extension in `sim/config/shodan_infrastructure/seL4Extensions.cs` and a
custom GDB extension in `sim/config/gdbscript.py`. `kgdb.sh` is a simple bash
script that starts GDB and connects to the appropriate remote with the extension
loaded.
The Renode extension tracks the VSpace setup for each thread and translates
virtual addresses to physical addresses. Without this work symbols may be
incorrectly resolved because every VSpace memory range starts at 0.
In addition, the extension provides commands to Renode to add debugging hooks to
an execution, all prefixed with the subcommand `seL4` (case matters at the
Renode prompt!). In our simulation config, Renode is configured to start the
seL4 extension on cpu1 using the `cpu1 CreateseL4` command.
The GDB extension provides a matching set of wrappers via the `sel4` command
prefix to examine the simulator state and take a look at threads in the system.
Both extensions provide built in help at their respective command lines, but
suffice it to say, the GDB extension is essentially just an automation mechanism
to load in symbols for the current thread context from disk when the Renode
extension detects a context switch.
During debugging, not all symbols will be loaded in GDB at the start, so it can
be helpful to use `sel4 wait-for-thread <threadname>` to tell Renode to break
execution upon entry of the given thread. When the break occurs, Renode will
instruct GDB to load the correct symbol table, and then symbols can be resolved
for later breakpoints, etc.
To set a breakpoint for a thread that is not the current context, use the `sel4
break <threadname> <symbol>` command. This will instruct Renode to load the
appropriate symbol table and break at the right place once that thread is
running. If, however, you need to set a breakpoint in the current thread
context, it's fine to use `break` as normal, since the symbols for the current
thread should be loaded.