Debuggable Emulation¶
gdb-multiarch can be attached to a Styx emulator for debugging purposes. This allows you to set breakpoints, single step execution, or use other useful GDB features while emulating with Styx.
Spawning a Processor with a GDB Executor¶
Build your processor as usual but make sure to use the GdbExecutor. The example below shows adding a Gdb executor to a Kinetis21 processor.
use clap::Parser;
use styx_core::prelude::*;
use styx_core::processor::executor::Executor;
use styx_core::cpu::arch::arm::ArmVariants;
use styx_core::cpu::arch::arm::gdb_targets::Armv7emDescription;
use styx_core::cpu::{ArchEndian, Backend};
use styx_plugins::gdb::{GdbExecutor, GdbPluginParams};
use styx_loader::RawLoader;
use styx_processors::arm::kinetis21::Kinetis21Cpu;
#[derive(Debug, Parser)]
#[command(author, version, about, long_about = None)]
struct TargetArgs {
/// Path to the target firmware `.bin`, required.
#[arg(short, long)]
firmware_path: String,
}
fn main() -> Result<(), UnknownError> {
let args = TargetArgs::parse();
let gdb_params = GdbPluginParams::tcp("0.0.0.0", 9999, true);
let builder = ProcessorBuilder::default()
.with_endian(ArchEndian::LittleEndian)
.with_executor(
Executor::new_unlimited(
Arc::new(GdbExecutor::<Armv7emDescription>::new(gdb_params))
)
)
.with_backend(Backend::Pcode)
.with_loader(RawLoader)
.with_target_program(args.firmware_path)
.with_variant(ArmVariants::ArmCortexM4);
let proc = builder.build::<Kinetis21Cpu>()?;
proc.start()?;
Ok(())
}
Starting the Processor¶
The processor should initialize and then wait for a connection from GDB.
styx-emulator/examples/kinetis21-processor$ cargo run -- --firmware-path ../../data/test-binaries/arm/kinetis_21/bin/hello_world/hello_world_debug.bin
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.30s
Running `styx-emulator/target/debug/kinetis21-processor --firmware-path ../../data/test-binaries/arm/kinetis_21/bin/hello_world/hello_world_debug.bin`
Waiting for a GDB connection on "0.0.0.0:9999"...
Attaching and Running GDB¶
Using gdb-multiarch, connect to the remote server at 0.0.0.0:9999. The following example shows loading symbols from an elf, setting a breakpoint at main, and then running until we reach it.
styx-emulator$ gdb-multiarch
GNU gdb (Ubuntu 15.0.50.20240403-0ubuntu1) 15.0.50.20240403-git
Copyright (C) 2024 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word".
(gdb) file ./data/test-binaries/arm/kinetis_21/bin/hello_world/hello_world_debug.elf
Reading symbols from ./data/test-binaries/arm/kinetis_21/bin/hello_world/hello_world_debug.elf...
(gdb) target remote 0.0.0.0:9999
Remote debugging using 0.0.0.0:9999
Reset_Handler () at /home/ubuntu/sm/styx-emulator/data/test-binaries/arm/kinetis_21/twrk21f120m-sdk/devices/MK21FA12/gcc/startup_MK21FA12.S:330
warning: 330 /home/ubuntu/sm/styx-emulator/data/test-binaries/arm/kinetis_21/twrk21f120m-sdk/devices/MK21FA12/gcc/startup_MK21FA12.S: No such file or directory
(gdb) b main
Breakpoint 1 at 0xc06: file /home/ubuntu/sm/styx-emulator/data/test-binaries/arm/kinetis_21/twrk21f120m-sdk/boards/twrk21f120m/demo_apps/hello_world/hello_world.c, line 111.
(gdb) c
Continuing.
Breakpoint 1, main () at /home/ubuntu/sm/styx-emulator/data/test-binaries/arm/kinetis_21/twrk21f120m-sdk/boards/twrk21f120m/demo_apps/hello_world/hello_world.c:111
warning: 111 /home/ubuntu/sm/styx-emulator/data/test-binaries/arm/kinetis_21/twrk21f120m-sdk/boards/twrk21f120m/demo_apps/hello_world/hello_world.c: No such file or directory
(gdb)
After Connecting to GDB¶
After Styx connects with GDB you should see a log message stating that GDB was connected.
styx-emulator/examples/kinetis21-processor$ cargo run -- --firmware-path ../../data/test-binaries/arm/kinetis_21/bin/hello_world/hello_world_debug.bin
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.30s
Running `styx-emulator/target/debug/kinetis21-processor --firmware-path ../../data/test-binaries/arm/kinetis_21/bin/hello_world/hello_world_debug.bin`
Waiting for a GDB connection on "0.0.0.0:9999"...
Debugger connected from 127.0.0.1:40408
Most GDB functionality works. The following functionality is proven working. Open an issue if it is not working as expected.
Read/write registers
Read/write memory
Breakpoints
Watch points
Watch registers
This known to have a significant performance impact
Interrupt execution with ctrl-c
Stop execution in Styx hooks via
cpu.stop()
Additionally, use monitor to access custom Styx functionality at the GDB command line. Use this to interact with the emulator during debugging.
(gdb) monitor
Styx custom commands to evaluate styx internals from gdb
Usage: monitor [OPTIONS] <COMMAND>
Commands:
hooks View and list hooks.
events View and list events
help Print this message or the help of the given subcommand(s)
Options:
-v, --verbose Print backtraces on error
-h, --help Print help (see more with '--help')