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}