bootstrap/core/debuggers/
gdb.rs

1use std::borrow::Cow;
2use std::path::Path;
3
4use crate::core::android;
5use crate::core::builder::Builder;
6use crate::utils::exec::BootstrapCommand;
7
8pub(crate) struct Gdb<'a> {
9    pub(crate) gdb: Cow<'a, Path>,
10}
11
12pub(crate) fn discover_gdb<'a>(
13    builder: &'a Builder<'_>,
14    android: Option<&android::Android>,
15) -> Option<Gdb<'a>> {
16    // If there's an explicitly-configured gdb, use that.
17    if let Some(gdb) = builder.config.gdb.as_deref() {
18        // FIXME(Zalathar): Consider returning None if gdb is an empty string,
19        // as a way to explicitly disable ambient gdb discovery.
20        let gdb = Cow::Borrowed(gdb);
21        return Some(Gdb { gdb });
22    }
23
24    // Otherwise, fall back to whatever gdb is sitting around in PATH.
25    // (That's the historical behavior, but maybe we should require opt-in?)
26
27    let gdb: Cow<'_, Path> = match android {
28        Some(android::Android { android_cross_path, .. }) => {
29            android_cross_path.join("bin/gdb").into()
30        }
31        None => Path::new("gdb").into(),
32    };
33
34    // Check whether an ambient gdb exists, by running `gdb --version`.
35    let output = {
36        let mut gdb_command = BootstrapCommand::new(gdb.as_ref()).allow_failure();
37        gdb_command.arg("--version");
38        gdb_command.run_capture(builder)
39    };
40
41    if output.is_success() { Some(Gdb { gdb }) } else { None }
42}