gdb.rs

 1use std::{collections::HashMap, ffi::OsStr};
 2
 3use anyhow::{Result, bail};
 4use async_trait::async_trait;
 5use dap::{StartDebuggingRequestArguments, adapters::DebugTaskDefinition};
 6use gpui::AsyncApp;
 7use task::DebugRequest;
 8
 9use crate::*;
10
11#[derive(Default)]
12pub(crate) struct GdbDebugAdapter;
13
14impl GdbDebugAdapter {
15    const ADAPTER_NAME: &'static str = "GDB";
16
17    fn request_args(&self, config: &DebugTaskDefinition) -> StartDebuggingRequestArguments {
18        let mut args = json!({
19            "request": match config.request {
20                DebugRequest::Launch(_) => "launch",
21                DebugRequest::Attach(_) => "attach",
22            },
23        });
24
25        let map = args.as_object_mut().unwrap();
26        match &config.request {
27            DebugRequest::Attach(attach) => {
28                map.insert("pid".into(), attach.process_id.into());
29            }
30
31            DebugRequest::Launch(launch) => {
32                map.insert("program".into(), launch.program.clone().into());
33
34                if !launch.args.is_empty() {
35                    map.insert("args".into(), launch.args.clone().into());
36                }
37
38                if let Some(stop_on_entry) = config.stop_on_entry {
39                    map.insert(
40                        "stopAtBeginningOfMainSubprogram".into(),
41                        stop_on_entry.into(),
42                    );
43                }
44                if let Some(cwd) = launch.cwd.as_ref() {
45                    map.insert("cwd".into(), cwd.to_string_lossy().into_owned().into());
46                }
47            }
48        }
49        StartDebuggingRequestArguments {
50            configuration: args,
51            request: config.request.to_dap(),
52        }
53    }
54}
55
56#[async_trait(?Send)]
57impl DebugAdapter for GdbDebugAdapter {
58    fn name(&self) -> DebugAdapterName {
59        DebugAdapterName(Self::ADAPTER_NAME.into())
60    }
61
62    async fn get_binary(
63        &self,
64        delegate: &dyn DapDelegate,
65        config: &DebugTaskDefinition,
66        user_installed_path: Option<std::path::PathBuf>,
67        _: &mut AsyncApp,
68    ) -> Result<DebugAdapterBinary> {
69        let user_setting_path = user_installed_path
70            .filter(|p| p.exists())
71            .and_then(|p| p.to_str().map(|s| s.to_string()));
72
73        let gdb_path = delegate
74            .which(OsStr::new("gdb"))
75            .and_then(|p| p.to_str().map(|s| s.to_string()))
76            .ok_or(anyhow!("Could not find gdb in path"));
77
78        if gdb_path.is_err() && user_setting_path.is_none() {
79            bail!("Could not find gdb path or it's not installed");
80        }
81
82        let gdb_path = user_setting_path.unwrap_or(gdb_path?);
83
84        Ok(DebugAdapterBinary {
85            command: gdb_path,
86            arguments: vec!["-i=dap".into()],
87            envs: HashMap::default(),
88            cwd: None,
89            connection: None,
90            request_args: self.request_args(config),
91        })
92    }
93}