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 !launch.env.is_empty() {
39                    map.insert("env".into(), launch.env_json());
40                }
41
42                if let Some(stop_on_entry) = config.stop_on_entry {
43                    map.insert(
44                        "stopAtBeginningOfMainSubprogram".into(),
45                        stop_on_entry.into(),
46                    );
47                }
48                if let Some(cwd) = launch.cwd.as_ref() {
49                    map.insert("cwd".into(), cwd.to_string_lossy().into_owned().into());
50                }
51            }
52        }
53        StartDebuggingRequestArguments {
54            configuration: args,
55            request: config.request.to_dap(),
56        }
57    }
58}
59
60#[async_trait(?Send)]
61impl DebugAdapter for GdbDebugAdapter {
62    fn name(&self) -> DebugAdapterName {
63        DebugAdapterName(Self::ADAPTER_NAME.into())
64    }
65
66    async fn get_binary(
67        &self,
68        delegate: &Arc<dyn DapDelegate>,
69        config: &DebugTaskDefinition,
70        user_installed_path: Option<std::path::PathBuf>,
71        _: &mut AsyncApp,
72    ) -> Result<DebugAdapterBinary> {
73        let user_setting_path = user_installed_path
74            .filter(|p| p.exists())
75            .and_then(|p| p.to_str().map(|s| s.to_string()));
76
77        let gdb_path = delegate
78            .which(OsStr::new("gdb"))
79            .await
80            .and_then(|p| p.to_str().map(|s| s.to_string()))
81            .ok_or(anyhow!("Could not find gdb in path"));
82
83        if gdb_path.is_err() && user_setting_path.is_none() {
84            bail!("Could not find gdb path or it's not installed");
85        }
86
87        let gdb_path = user_setting_path.unwrap_or(gdb_path?);
88
89        Ok(DebugAdapterBinary {
90            command: gdb_path,
91            arguments: vec!["-i=dap".into()],
92            envs: HashMap::default(),
93            cwd: None,
94            connection: None,
95            request_args: self.request_args(config),
96        })
97    }
98}