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
 94    async fn install_binary(
 95        &self,
 96        _version: AdapterVersion,
 97        _delegate: &dyn DapDelegate,
 98    ) -> Result<()> {
 99        unimplemented!("GDB debug adapter cannot be installed by Zed (yet)")
100    }
101
102    async fn fetch_latest_adapter_version(&self, _: &dyn DapDelegate) -> Result<AdapterVersion> {
103        unimplemented!("Fetch latest GDB version not implemented (yet)")
104    }
105
106    async fn get_installed_binary(
107        &self,
108        _: &dyn DapDelegate,
109        _: &DebugTaskDefinition,
110        _: Option<std::path::PathBuf>,
111        _: &mut AsyncApp,
112    ) -> Result<DebugAdapterBinary> {
113        unimplemented!("GDB cannot be installed by Zed (yet)")
114    }
115}