Skip to repository content

tenant.openagents/omega

No repository description is available.

OpenAgents Git authority 2026-07-28T02:37:07.013Z Public web read
NIP-34 coordinate30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omega
MaintainersHidden in public view
References2 branches · 1 tag
Read-only clonegit clone https://openagents.com/git/tenant.openagents/omega.git
Browse files

gdb.rs

266 lines · 11.0 KB · rust
1use anyhow::{Context as _, Result, bail};
2use async_trait::async_trait;
3use collections::HashMap;
4use dap::{StartDebuggingRequestArguments, adapters::DebugTaskDefinition};
5use gpui::AsyncApp;
6use std::ffi::OsStr;
7use task::{DebugScenario, ZedDebugConfig};
8
9use crate::*;
10
11#[derive(Default)]
12pub(crate) struct GdbDebugAdapter;
13
14impl GdbDebugAdapter {
15    const ADAPTER_NAME: &'static str = "GDB";
16}
17
18/// Ensures that "-i=dap" is present in the GDB argument list.
19fn ensure_dap_interface(mut gdb_args: Vec<String>) -> Vec<String> {
20    if !gdb_args.iter().any(|arg| arg.trim() == "-i=dap") {
21        gdb_args.insert(0, "-i=dap".to_string());
22    }
23    gdb_args
24}
25
26#[async_trait(?Send)]
27impl DebugAdapter for GdbDebugAdapter {
28    fn name(&self) -> DebugAdapterName {
29        DebugAdapterName(Self::ADAPTER_NAME.into())
30    }
31
32    async fn config_from_zed_format(&self, zed_scenario: ZedDebugConfig) -> Result<DebugScenario> {
33        let mut obj = serde_json::Map::default();
34
35        match &zed_scenario.request {
36            dap::DebugRequest::Attach(attach) => {
37                obj.insert("request".into(), "attach".into());
38                obj.insert("pid".into(), attach.process_id.into());
39            }
40
41            dap::DebugRequest::Launch(launch) => {
42                obj.insert("request".into(), "launch".into());
43                obj.insert("program".into(), launch.program.clone().into());
44
45                if !launch.args.is_empty() {
46                    obj.insert("args".into(), launch.args.clone().into());
47                }
48
49                if !launch.env.is_empty() {
50                    obj.insert("env".into(), launch.env_json());
51                }
52
53                if let Some(stop_on_entry) = zed_scenario.stop_on_entry {
54                    obj.insert(
55                        "stopAtBeginningOfMainSubprogram".into(),
56                        stop_on_entry.into(),
57                    );
58                }
59                if let Some(cwd) = launch.cwd.as_ref() {
60                    obj.insert("cwd".into(), cwd.to_string_lossy().into_owned().into());
61                }
62            }
63        }
64
65        Ok(DebugScenario {
66            adapter: zed_scenario.adapter,
67            label: zed_scenario.label,
68            build: None,
69            config: serde_json::Value::Object(obj),
70            tcp_connection: None,
71        })
72    }
73
74    fn dap_schema(&self) -> serde_json::Value {
75        json!({
76            "oneOf": [
77                {
78                    "allOf": [
79                        {
80                            "type": "object",
81                            "required": ["request"],
82                            "properties": {
83                                "request": {
84                                    "type": "string",
85                                    "enum": ["launch"],
86                                    "description": "Request to launch a new process"
87                                }
88                            }
89                        },
90                        {
91                            "type": "object",
92                            "properties": {
93                                "program": {
94                                    "type": "string",
95                                    "description": "The program to debug. This corresponds to the GDB 'file' command."
96                                },
97                                "args": {
98                                    "type": "array",
99                                    "items": {
100                                        "type": "string"
101                                    },
102                                    "description": "Command line arguments passed to the program. These strings are provided as command-line arguments to the inferior.",
103                                    "default": []
104                                },
105                                "cwd": {
106                                    "type": "string",
107                                    "description": "Working directory for the debugged program. GDB will change its working directory to this directory."
108                                },
109                                "gdb_path": {
110                                    "type": "string",
111                                    "description": "Alternative path to the GDB executable, if the one in standard path is not desirable"
112                                },
113                                "gdb_args": {
114                                    "type": "array",
115                                    "items": {
116                                        "type":"string"
117                                    },
118                                    "description": "additional arguments given to GDB at startup, not the program debugged",
119                                    "default": []
120                                },
121                                "env": {
122                                    "type": "object",
123                                    "description": "Environment variables for the debugged program. Each key is the name of an environment variable; each value is the value of that variable."
124                                },
125                                "stopAtBeginningOfMainSubprogram": {
126                                    "type": "boolean",
127                                    "description": "When true, GDB will set a temporary breakpoint at the program's main procedure, like the 'start' command.",
128                                    "default": false
129                                },
130                                "stopOnEntry": {
131                                    "type": "boolean",
132                                    "description": "When true, GDB will set a temporary breakpoint at the program's first instruction, like the 'starti' command.",
133                                    "default": false
134                                }
135                            },
136                            "required": ["program"]
137                        }
138                    ]
139                },
140                {
141                    "allOf": [
142                        {
143                            "type": "object",
144                            "required": ["request"],
145                            "properties": {
146                                "request": {
147                                    "type": "string",
148                                    "enum": ["attach"],
149                                    "description": "Request to attach to an existing process"
150                                }
151                            }
152                        },
153                        {
154                            "type": "object",
155                            "properties": {
156                                "pid": {
157                                    "type": "number",
158                                    "description": "The process ID to which GDB should attach."
159                                },
160                                "program": {
161                                    "type": "string",
162                                    "description": "The program to debug (optional). This corresponds to the GDB 'file' command. In many cases, GDB can determine which program is running automatically."
163                                },
164                                "target": {
165                                    "type": "string",
166                                    "description": "The target to which GDB should connect. This is passed to the 'target remote' command."
167                                }
168                            },
169                            "required": ["pid"]
170                        }
171                    ]
172                }
173            ]
174        })
175    }
176
177    async fn get_binary(
178        &self,
179        delegate: &Arc<dyn DapDelegate>,
180        config: &DebugTaskDefinition,
181        user_installed_path: Option<std::path::PathBuf>,
182        user_args: Option<Vec<String>>,
183        user_env: Option<HashMap<String, String>>,
184        _: &mut AsyncApp,
185    ) -> Result<DebugAdapterBinary> {
186        // Try to get gdb_path from config
187        let gdb_path_from_config = config
188            .config
189            .get("gdb_path")
190            .and_then(|v| v.as_str())
191            .map(|s| s.to_string());
192
193        let gdb_path = if let Some(path) = gdb_path_from_config {
194            path
195        } else {
196            // Original logic: use user_installed_path or search in system path
197            let user_setting_path = user_installed_path
198                .filter(|p| p.exists())
199                .and_then(|p| p.to_str().map(|s| s.to_string()));
200
201            let gdb_path_result = delegate
202                .which(OsStr::new("gdb"))
203                .await
204                .and_then(|p| p.to_str().map(|s| s.to_string()))
205                .context("Could not find gdb in path");
206
207            if gdb_path_result.is_err() && user_setting_path.is_none() {
208                bail!("Could not find gdb path or it's not installed");
209            }
210
211            user_setting_path.unwrap_or_else(|| gdb_path_result.unwrap())
212        };
213
214        // Arguments: use gdb_args from config if present, else user_args, else default
215        let gdb_args = {
216            let args = config
217                .config
218                .get("gdb_args")
219                .and_then(|v| v.as_array())
220                .map(|arr| {
221                    arr.iter()
222                        .filter_map(|v| v.as_str().map(|s| s.to_string()))
223                        .collect::<Vec<_>>()
224                })
225                .or(user_args.clone())
226                .unwrap_or_else(|| vec!["-i=dap".into()]);
227            ensure_dap_interface(args)
228        };
229
230        let mut configuration = config.config.clone();
231        if let Some(configuration) = configuration.as_object_mut() {
232            configuration
233                .entry("cwd")
234                .or_insert_with(|| delegate.worktree_root_path().to_string_lossy().into());
235        }
236
237        let mut base_env = delegate.shell_env().await;
238        base_env.extend(user_env.unwrap_or_default());
239
240        let config_env: HashMap<String, String> = config
241            .config
242            .get("env")
243            .and_then(|v| v.as_object())
244            .map(|obj| {
245                obj.iter()
246                    .filter_map(|(k, v)| v.as_str().map(|s| (k.clone(), s.to_string())))
247                    .collect::<HashMap<String, String>>()
248            })
249            .unwrap_or_else(HashMap::default);
250
251        base_env.extend(config_env);
252
253        Ok(DebugAdapterBinary {
254            command: Some(gdb_path),
255            arguments: gdb_args,
256            envs: base_env,
257            cwd: Some(delegate.worktree_root_path().to_path_buf()),
258            connection: None,
259            request_args: StartDebuggingRequestArguments {
260                request: self.request_kind(&config.config).await?,
261                configuration,
262            },
263        })
264    }
265}
266
Served at tenant.openagents/omega Member data and write actions are omitted.