inoculate/
gdb.rs

1use crate::Result;
2use color_eyre::eyre::WrapErr;
3use std::{
4    path::Path,
5    process::{Command, ExitStatus},
6};
7
8#[tracing::instrument(level = "debug")]
9pub fn run_gdb(binary: &Path, gdb_port: u16) -> Result<ExitStatus> {
10    let gdb_path = wheres_gdb().context("failed to find gdb executable")?;
11    tracing::info!("Found {}", gdb_path);
12    let mut gdb = Command::new(gdb_path);
13
14    // Set the file, and connect to the given remote, then advance to `kernel_main`.
15    //
16    // The `-ex` command provides a gdb command to which is run by gdb
17    // before handing control over to the user, and we can use it to
18    // configure the gdb session to connect to the gdb remote.
19    gdb.arg("-ex").arg(format!("file {}", binary.display()));
20    gdb.arg("-ex").arg(format!("target remote :{gdb_port}"));
21
22    // Set a temporary breakpoint on `kernel_main` and continue to it to
23    // skip the non-mycelium boot process.
24    // XXX: Add a flag to skip doing this to allow debugging the boot process.
25    gdb.arg("-ex").arg("tbreak mycelium_kernel::kernel_main");
26    gdb.arg("-ex").arg("continue");
27
28    tracing::info!("Running {gdb:?}");
29    // Try to run gdb.
30    let status = gdb.status().context("failed to run gdb")?;
31
32    tracing::debug!("gdb exited with status {:?}", status);
33    Ok(status)
34}
35
36fn wheres_gdb() -> Result<String> {
37    let output = Command::new("which")
38        .arg("rust-gdb")
39        .output()
40        .context("running `which rust-gdb` failed")?;
41    let mut which_gdb =
42        String::from_utf8(output.stdout).context("`which rust-gdb` output was not a string")?;
43    which_gdb.truncate(which_gdb.trim_end().len());
44    if which_gdb.ends_with("not found") {
45        return Ok(String::from("gdb"));
46    }
47
48    Ok(which_gdb)
49}