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}