1use std::collections::BTreeMap;
2
3use crate::{
4 diag::{Error, Result},
5 handler::{self, CommandFn},
6 param::{Extend, Join, Type, Value},
7 progress::State,
8};
9
10#[derive(PartialEq, Debug)]
11enum Status {
12 Handled,
13 NotHandled,
14}
15
16enum Node {
17 Command(CommandFn, Vec<Type>),
18 Subcommands(Registry),
19 Alias(&'static str),
20 HelpCommand,
21}
22
23impl Node {
24 fn command_no_params(f: CommandFn) -> Self {
25 Node::Command(f, vec![])
26 }
27}
28
29pub struct Registry {
35 nodes: BTreeMap<&'static str, Vec<Node>>,
37}
38
39impl Registry {
40 fn new() -> Self {
41 Self {
42 nodes: BTreeMap::new(),
43 }
44 }
45
46 fn register(mut self, name: &'static str, node: Node) -> Self {
47 self.nodes.entry(name).or_default().push(node);
48 self
49 }
50
51 fn alias(mut self, alias: &'static str, target: &'static str) -> Self {
52 self.nodes
53 .entry(alias)
54 .or_default()
55 .push(Node::Alias(target));
56 self
57 }
58
59 fn walk<'a, F>(&'a self, prefix: &mut Vec<&'a str>, f: &mut F)
60 where
61 F: FnMut(&[&'a str], Option<&'a [Type]>),
62 {
63 for (name, nodes) in &self.nodes {
64 if nodes.iter().all(|n| matches!(n, Node::Alias(_))) {
65 continue;
66 }
67
68 if !name.is_empty() {
69 prefix.push(name);
70 }
71
72 for entry in nodes {
73 match entry {
74 Node::Command(_, param_types) => f(prefix, Some(param_types)),
75 Node::Subcommands(sub) => sub.walk(prefix, f),
76 Node::Alias(_) => {}
77 Node::HelpCommand => f(&[*name], None),
78 }
79 }
80
81 if !name.is_empty() {
82 prefix.pop();
83 }
84 }
85 }
86
87 fn collect<F>(&self, mut f: F)
88 where
89 F: FnMut(&[&str], Option<&[Type]>),
90 {
91 let mut prefix = Vec::new();
92 self.walk(&mut prefix, &mut f);
93 }
94
95 #[must_use]
96 pub fn completions(&self) -> Vec<String> {
108 let mut out = Vec::new();
109
110 self.collect(|names, _| {
111 out.push(names.join(" "));
112 });
113
114 out.dedup();
115 out
116 }
117
118 #[must_use]
119 pub fn usages(&self) -> Vec<String> {
131 let mut out = Vec::new();
132
133 self.collect(|names, param_types| {
134 let mut usage = names.join(" ");
135 if let Some(params) = param_types {
136 if !params.is_empty() {
137 let params_str = params
138 .iter()
139 .map(std::string::ToString::to_string)
140 .collect::<Vec<_>>()
141 .join(" ");
142 usage.push(' ');
143 usage.push_str(¶ms_str);
144 }
145 }
146
147 out.push(usage);
148 });
149
150 out
151 }
152
153 fn parse_params<'a>(
154 param_types: &[Type],
155 params: &'a [&'a str],
156 ) -> Vec<Value<'a>> {
157 param_types
158 .iter()
159 .enumerate()
160 .filter_map(|(i, param_type)| Value::new(param_type, params[i]).ok())
161 .collect()
162 }
163
164 fn handle_command(
165 handler: CommandFn,
166 param_types: &[Type],
167 rest: &[&str],
168 state: &mut State,
169 ) -> Result<Status> {
170 let mut status = Status::NotHandled;
171
172 let num_params = param_types.len();
173 if rest.len() == num_params {
174 let parsed = Self::parse_params(param_types, rest);
175 if parsed.len() == num_params {
176 handler(&parsed, state)?;
177 status = Status::Handled;
178 }
179 }
180
181 Ok(status)
182 }
183
184 fn handle_subcommands(
185 registry: &Registry,
186 path: &[Value],
187 first: &str,
188 rest: &[&str],
189 state: &mut State,
190 ) -> Result<()> {
191 let path = path.extend(first, &[]);
192 if rest.is_empty() {
193 handler::do_ambiguous(&path, state)
194 } else {
195 registry.dispatch(rest, &path, state)
196 }
197 }
198
199 fn handle_help(
200 &self,
201 path: &[Value],
202 first: &str,
203 rest: &[&str],
204 state: &mut State,
205 ) -> Result<()> {
206 if rest.is_empty() {
207 let commands = self.usages();
208 let commands: Vec<Value> =
209 commands.iter().map(|s| Value::String(s)).collect();
210 handler::do_help(&commands, state)
211 } else {
212 let path = path.extend(first, rest);
213 handler::do_unknown(&path, state)
214 }
215 }
216
217 fn handle_no_entry(
218 &self,
219 path: &[Value],
220 first: &str,
221 rest: &[&str],
222 state: &mut State,
223 ) -> Result<()> {
224 let matches: Vec<_> = self
225 .nodes
226 .keys()
227 .filter(|name| name.starts_with(first))
228 .collect();
229
230 match matches.len() {
231 1 => {
232 let mut args = vec![*matches[0]];
233 args.extend_from_slice(rest);
234 self.dispatch(&args, path, state)
235 }
236 n if n > 1 => {
237 let path = path.extend(first, &[]);
238 handler::do_ambiguous(&path, state)
239 }
240 _ => {
241 let path = path.extend(first, rest);
242 handler::do_unknown(&path, state)
243 }
244 }
245 }
246
247 fn handle_node(
248 &self,
249 node: &Node,
250 path: &[Value],
251 first: &str,
252 rest: &[&str],
253 state: &mut State,
254 ) -> Result<bool> {
255 match node {
256 Node::Command(handler, param_types) => {
257 match Self::handle_command(*handler, param_types, rest, state)? {
258 Status::Handled => Ok(true),
259 Status::NotHandled => Ok(false),
260 }
261 }
262 Node::Subcommands(registry) => {
263 let res =
264 Self::handle_subcommands(registry, path, first, rest, state);
265 Ok(res.is_ok())
266 }
267 Node::Alias(target) => {
268 let mut new_args = vec![*target];
269 new_args.extend_from_slice(rest);
270 let res = self.dispatch(&new_args, path, state);
271 Ok(res.is_ok())
272 }
273 Node::HelpCommand => {
274 let res = self.handle_help(path, first, rest, state);
275 Ok(res.is_ok())
276 }
277 }
278 }
279
280 fn dispatch(
281 &self,
282 args: &[&str],
283 path: &[Value],
284 state: &mut State,
285 ) -> Result<()> {
286 match args.split_first() {
287 Some((first, rest)) => match self.nodes.get(*first) {
288 Some(nodes) => {
289 let handled =
290 nodes.iter().try_fold(false, |handled, node| {
291 Ok::<bool, Error>(
292 handled
293 | self.handle_node(
294 node, path, first, rest, state,
295 )?,
296 )
297 })?;
298 if !handled {
299 let path = path.extend(first, &[]);
300 let args = format!("{}: {}", path.join(" "), rest.join(" "));
301 handler::do_invalid_arguments(
302 &[Value::String(&args)],
303 state,
304 )?;
305 }
306 Ok(())
307 }
308 None => self.handle_no_entry(path, first, rest, state),
309 },
310 None => handler::do_nothing(&[], state),
311 }
312 }
313
314 pub fn run(&self, input: &str, state: &mut State) -> Result<()> {
326 let args: Vec<&str> = input.split_whitespace().collect();
327 self.dispatch(&args, &[], state)?;
328 Ok(())
329 }
330}
331
332impl Default for Registry {
333 fn default() -> Self {
334 let info_registry = Registry::new()
335 .register(
336 "breakpoints",
337 Node::command_no_params(handler::do_info_breakpoints),
338 )
339 .register("memory", Node::command_no_params(handler::do_info_memory))
340 .register(
341 "registers",
342 Node::command_no_params(handler::do_info_registers),
343 );
344
345 let layout_registry = Registry::new()
346 .register("asm", Node::command_no_params(handler::do_layout_asm))
347 .register("src", Node::command_no_params(handler::do_layout_src));
348
349 Registry::new()
350 .register("backtrace", Node::command_no_params(handler::do_backtrace))
351 .alias("bt", "backtrace")
352 .register(
353 "breakpoint",
354 Node::command_no_params(handler::do_breakpoint),
355 )
356 .register(
357 "breakpoint",
358 Node::Command(handler::do_breakpoint, vec![Type::Address]),
359 )
360 .alias("b", "breakpoint") .register("continue", Node::command_no_params(handler::do_continue))
362 .register("delete", Node::Command(handler::do_delete, vec![Type::Id]))
363 .register(
364 "examine",
365 Node::Command(
366 handler::do_examine,
367 vec![Type::Format, Type::Size, Type::Address],
368 ),
369 )
370 .alias("x", "examine")
371 .register("help", Node::HelpCommand)
372 .register("info", Node::Subcommands(info_registry))
373 .register("layout", Node::Subcommands(layout_registry))
374 .register("list", Node::command_no_params(handler::do_list))
375 .alias("l", "list") .register("quit", Node::command_no_params(handler::do_quit))
377 .register("step", Node::command_no_params(handler::do_step))
378 .register("next", Node::command_no_params(handler::do_next))
379 .register(
380 "tbreakpoint",
381 Node::command_no_params(handler::do_tbreakpoint),
382 )
383 .register(
384 "tbreakpoint",
385 Node::Command(handler::do_tbreakpoint, vec![Type::Address]),
386 )
387 }
388}
389
390#[cfg(test)]
391mod tests {
392 use super::*;
393
394 use nix::unistd::Pid;
395
396 use crate::{
397 param::{Type, Value},
398 progress::{Execution, State},
399 };
400
401 #[test]
402 fn test_registry_completions_and_usages() {
403 let reg = Registry::new()
404 .register("foo", Node::command_no_params(handler::do_nothing))
405 .register(
406 "bar",
407 Node::Command(handler::do_nothing, vec![Type::Address, Type::Id]),
408 );
409
410 let comps = reg.completions();
411 assert!(comps.contains(&"foo".to_string()));
412 assert!(comps.contains(&"bar".to_string()));
413
414 let usages = reg.usages();
415 assert!(usages.iter().any(|s| s.starts_with("bar ")));
416 }
417
418 #[test]
419 fn test_handle_command_param_matching() {
420 fn my_handler(_args: &[Value], _state: &mut State) -> Result<()> {
421 Ok(())
422 }
423
424 let mut state = State::new(Pid::from_raw(1), None);
425 let res = Registry::handle_command(
426 my_handler,
427 &[Type::Address],
428 &["0x100"],
429 &mut state,
430 )
431 .expect("handle_command failed");
432 assert_eq!(res, Status::Handled);
433
434 let res = Registry::handle_command(
435 my_handler,
436 &[Type::Address, Type::Id],
437 &["0x100"],
438 &mut state,
439 )
440 .expect("handle_command failed");
441 assert_eq!(res, Status::NotHandled);
442 }
443
444 #[test]
445 fn test_handle_no_entry_ambiguous() {
446 let reg = Registry::new()
447 .register("foo", Node::command_no_params(handler::do_nothing))
448 .register("fop", Node::command_no_params(handler::do_nothing));
449
450 let mut state = State::new(Pid::from_raw(1), None);
451 reg.dispatch(&["fo"], &[], &mut state)
452 .expect("dispatch failed");
453 assert!(matches!(state.execution(), Execution::Skip));
454 }
455
456 #[test]
457 fn test_alias_dispatch() {
458 let reg = Registry::new()
459 .register("target", Node::command_no_params(handler::do_nothing))
460 .alias("a", "target");
461
462 let mut state = State::new(Pid::from_raw(1), None);
463 reg.dispatch(&["a"], &[], &mut state)
464 .expect("dispatch failed");
465 assert!(matches!(state.execution(), Execution::Skip));
466 }
467
468 #[test]
469 fn test_handle_help_and_run() {
470 let reg = Registry::new().register("help", Node::HelpCommand);
471
472 let mut state = State::new(Pid::from_raw(1), None);
473 reg.dispatch(&["help"], &[], &mut state)
474 .expect("dispatch failed");
475 assert!(matches!(state.execution(), Execution::Skip));
476
477 let mut state2 = State::new(Pid::from_raw(1), None);
478 reg.run("help", &mut state2).expect("run failed");
479 assert!(matches!(state2.execution(), Execution::Skip));
480 }
481}