xref: /netbsd-src/external/gpl3/gdb/dist/gdb/mi/mi-cmds.c (revision d32db8d4612ca6060a50acb83ce8551b64c2d595)
1 /* MI Command Set for GDB, the GNU debugger.
2    Copyright (C) 2000-2024 Free Software Foundation, Inc.
3 
4    Contributed by Cygnus Solutions (a Red Hat company).
5 
6    This file is part of GDB.
7 
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12 
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
20 
21 #include "top.h"
22 #include "mi-cmds.h"
23 #include "mi-main.h"
24 #include "mi-parse.h"
25 #include <map>
26 #include <string>
27 
28 /* MI command table (built at run time). */
29 
30 static std::map<std::string, mi_command_up> mi_cmd_table;
31 
32 /* MI command with a pure MI implementation.  */
33 
34 struct mi_command_mi : public mi_command
35 {
36   /* Constructor.  For NAME and SUPPRESS_NOTIFICATION see mi_command
37      constructor, FUNC is the function called from do_invoke, which
38      implements this MI command.  */
39   mi_command_mi (const char *name, mi_cmd_argv_ftype func,
40 		 int *suppress_notification)
41     : mi_command (name, suppress_notification),
42       m_argv_function (func)
43   {
44     gdb_assert (func != nullptr);
45   }
46 
47   /* Called when this MI command has been invoked, calls m_argv_function
48      with arguments contained within PARSE.  */
49   void invoke (struct mi_parse *parse) const override
50   {
51     parse->parse_argv ();
52 
53     if (parse->argv == nullptr)
54       error (_("Problem parsing arguments: %s %s"), parse->command.get (),
55 	     parse->args ());
56 
57     this->m_argv_function (parse->command.get (), parse->argv, parse->argc);
58   }
59 
60 private:
61 
62   /* The function that implements this MI command.  */
63   mi_cmd_argv_ftype *m_argv_function;
64 };
65 
66 /* MI command implemented on top of a CLI command.  */
67 
68 struct mi_command_cli : public mi_command
69 {
70   /* Constructor.  For NAME and SUPPRESS_NOTIFICATION see mi_command
71      constructor, CLI_NAME is the name of a CLI command that should be
72      invoked to implement this MI command.  If ARGS_P is true then any
73      arguments from entered by the user as part of the MI command line are
74      forwarded to CLI_NAME as its argument string, otherwise, if ARGS_P is
75      false, nullptr is send to CLI_NAME as its argument string.  */
76   mi_command_cli (const char *name, const char *cli_name, bool args_p,
77 		  int *suppress_notification)
78     : mi_command (name, suppress_notification),
79       m_cli_name (cli_name),
80       m_args_p (args_p)
81   { /* Nothing.  */ }
82 
83   /* Called when this MI command has been invoked, calls the m_cli_name
84      CLI function.  In m_args_p is true then the argument string from
85      within PARSE is passed through to the CLI function, otherwise nullptr
86      is passed through to the CLI function as its argument string.  */
87   void invoke (struct mi_parse *parse) const override
88   {
89     const char *args = m_args_p ? parse->args () : nullptr;
90     mi_execute_cli_command (m_cli_name, m_args_p, args);
91   }
92 
93 private:
94 
95   /* The name of the CLI command to execute.  */
96   const char *m_cli_name;
97 
98   /* Should we be passing an argument string to the m_cli_name function?  */
99   bool m_args_p;
100 };
101 
102 /* See mi-cmds.h.  */
103 
104 bool
105 insert_mi_cmd_entry (mi_command_up command)
106 {
107   gdb_assert (command != nullptr);
108 
109   const std::string &name = command->name ();
110 
111   if (mi_cmd_table.find (name) != mi_cmd_table.end ())
112     return false;
113 
114   mi_cmd_table[name] = std::move (command);
115   return true;
116 }
117 
118 /* See mi-cmds.h.  */
119 
120 bool
121 remove_mi_cmd_entry (const std::string &name)
122 {
123   if (mi_cmd_table.find (name) == mi_cmd_table.end ())
124     return false;
125 
126   mi_cmd_table.erase (name);
127   return true;
128 }
129 
130 /* See mi-cmds.h.  */
131 
132 void
133 remove_mi_cmd_entries (remove_mi_cmd_entries_ftype callback)
134 {
135   for (auto it = mi_cmd_table.cbegin (); it != mi_cmd_table.cend (); )
136     {
137       if (callback (it->second.get ()))
138 	it = mi_cmd_table.erase (it);
139       else
140 	++it;
141     }
142 }
143 
144 /* Create and register a new MI command with an MI specific implementation.
145    NAME must name an MI command that does not already exist, otherwise an
146    assertion will trigger.  */
147 
148 static void
149 add_mi_cmd_mi (const char *name, mi_cmd_argv_ftype function,
150 	       int *suppress_notification = nullptr)
151 {
152   mi_command_up command (new mi_command_mi (name, function,
153 					    suppress_notification));
154 
155   bool success = insert_mi_cmd_entry (std::move (command));
156   gdb_assert (success);
157 }
158 
159 /* Create and register a new MI command implemented on top of a CLI
160    command.  NAME must name an MI command that does not already exist,
161    otherwise an assertion will trigger.  */
162 
163 static void
164 add_mi_cmd_cli (const char *name, const char *cli_name, int args_p,
165 		int *suppress_notification = nullptr)
166 {
167   mi_command_up command (new mi_command_cli (name, cli_name, args_p != 0,
168 					     suppress_notification));
169 
170   bool success = insert_mi_cmd_entry (std::move (command));
171   gdb_assert (success);
172 }
173 
174 /* See mi-cmds.h.  */
175 
176 mi_command::mi_command (const char *name, int *suppress_notification)
177   : m_name (name),
178     m_suppress_notification (suppress_notification)
179 {
180   gdb_assert (m_name != nullptr && m_name[0] != '\0');
181 }
182 
183 /* See mi-cmds.h.  */
184 
185 std::optional<scoped_restore_tmpl<int>>
186 mi_command::do_suppress_notification () const
187 {
188   if (m_suppress_notification != nullptr)
189     return scoped_restore_tmpl<int> (m_suppress_notification, 1);
190   else
191     return {};
192 }
193 
194 /* Initialize the available MI commands.  */
195 
196 static void
197 add_builtin_mi_commands ()
198 {
199   add_mi_cmd_mi ("ada-task-info", mi_cmd_ada_task_info);
200   add_mi_cmd_mi ("add-inferior", mi_cmd_add_inferior);
201   add_mi_cmd_cli ("break-after", "ignore", 1,
202 		  &mi_suppress_notification.breakpoint);
203   add_mi_cmd_mi ("break-condition",mi_cmd_break_condition,
204 		  &mi_suppress_notification.breakpoint);
205   add_mi_cmd_mi ("break-commands", mi_cmd_break_commands,
206 		 &mi_suppress_notification.breakpoint);
207   add_mi_cmd_cli ("break-delete", "delete breakpoint", 1,
208 		  &mi_suppress_notification.breakpoint);
209   add_mi_cmd_cli ("break-disable", "disable breakpoint", 1,
210 		  &mi_suppress_notification.breakpoint);
211   add_mi_cmd_cli ("break-enable", "enable breakpoint", 1,
212 		  &mi_suppress_notification.breakpoint);
213   add_mi_cmd_cli ("break-info", "info break", 1);
214   add_mi_cmd_mi ("break-insert", mi_cmd_break_insert,
215 		 &mi_suppress_notification.breakpoint);
216   add_mi_cmd_mi ("dprintf-insert", mi_cmd_dprintf_insert,
217 		 &mi_suppress_notification.breakpoint);
218   add_mi_cmd_cli ("break-list", "info break", 0);
219   add_mi_cmd_mi ("break-passcount", mi_cmd_break_passcount,
220 		 &mi_suppress_notification.breakpoint);
221   add_mi_cmd_mi ("break-watch", mi_cmd_break_watch,
222 		 &mi_suppress_notification.breakpoint);
223   add_mi_cmd_mi ("catch-assert", mi_cmd_catch_assert,
224 		 &mi_suppress_notification.breakpoint);
225   add_mi_cmd_mi ("catch-exception", mi_cmd_catch_exception,
226 		 &mi_suppress_notification.breakpoint);
227   add_mi_cmd_mi ("catch-handlers", mi_cmd_catch_handlers,
228 		 &mi_suppress_notification.breakpoint);
229   add_mi_cmd_mi ("catch-load", mi_cmd_catch_load,
230 		 &mi_suppress_notification.breakpoint);
231   add_mi_cmd_mi ("catch-unload", mi_cmd_catch_unload,
232 		 &mi_suppress_notification.breakpoint);
233   add_mi_cmd_mi ("catch-throw", mi_cmd_catch_throw,
234 		 &mi_suppress_notification.breakpoint),
235   add_mi_cmd_mi ("catch-rethrow", mi_cmd_catch_rethrow,
236 		 &mi_suppress_notification.breakpoint),
237   add_mi_cmd_mi ("catch-catch", mi_cmd_catch_catch,
238 		 &mi_suppress_notification.breakpoint),
239   add_mi_cmd_mi ("complete", mi_cmd_complete);
240   add_mi_cmd_mi ("data-disassemble", mi_cmd_disassemble);
241   add_mi_cmd_mi ("data-evaluate-expression", mi_cmd_data_evaluate_expression);
242   add_mi_cmd_mi ("data-list-changed-registers",
243 		 mi_cmd_data_list_changed_registers);
244   add_mi_cmd_mi ("data-list-register-names", mi_cmd_data_list_register_names);
245   add_mi_cmd_mi ("data-list-register-values",
246 		 mi_cmd_data_list_register_values);
247   add_mi_cmd_mi ("data-read-memory", mi_cmd_data_read_memory);
248   add_mi_cmd_mi ("data-read-memory-bytes", mi_cmd_data_read_memory_bytes);
249   add_mi_cmd_mi ("data-write-memory", mi_cmd_data_write_memory,
250 		 &mi_suppress_notification.memory);
251   add_mi_cmd_mi ("data-write-memory-bytes", mi_cmd_data_write_memory_bytes,
252 		 &mi_suppress_notification.memory);
253   add_mi_cmd_mi ("data-write-register-values",
254 		 mi_cmd_data_write_register_values);
255   add_mi_cmd_mi ("enable-timings", mi_cmd_enable_timings);
256   add_mi_cmd_mi ("enable-pretty-printing", mi_cmd_enable_pretty_printing);
257   add_mi_cmd_mi ("enable-frame-filters", mi_cmd_enable_frame_filters);
258   add_mi_cmd_mi ("environment-cd", mi_cmd_env_cd);
259   add_mi_cmd_mi ("environment-directory", mi_cmd_env_dir);
260   add_mi_cmd_mi ("environment-path", mi_cmd_env_path);
261   add_mi_cmd_mi ("environment-pwd", mi_cmd_env_pwd);
262   add_mi_cmd_cli ("exec-arguments", "set args", 1,
263 		  &mi_suppress_notification.cmd_param_changed);
264   add_mi_cmd_mi ("exec-continue", mi_cmd_exec_continue);
265   add_mi_cmd_mi ("exec-finish", mi_cmd_exec_finish);
266   add_mi_cmd_mi ("exec-jump", mi_cmd_exec_jump);
267   add_mi_cmd_mi ("exec-interrupt", mi_cmd_exec_interrupt);
268   add_mi_cmd_mi ("exec-next", mi_cmd_exec_next);
269   add_mi_cmd_mi ("exec-next-instruction", mi_cmd_exec_next_instruction);
270   add_mi_cmd_mi ("exec-return", mi_cmd_exec_return);
271   add_mi_cmd_mi ("exec-run", mi_cmd_exec_run);
272   add_mi_cmd_mi ("exec-step", mi_cmd_exec_step);
273   add_mi_cmd_mi ("exec-step-instruction", mi_cmd_exec_step_instruction);
274   add_mi_cmd_cli ("exec-until", "until", 1);
275   add_mi_cmd_cli ("file-exec-and-symbols", "file", 1);
276   add_mi_cmd_cli ("file-exec-file", "exec-file", 1);
277   add_mi_cmd_mi ("file-list-exec-source-file",
278 		 mi_cmd_file_list_exec_source_file);
279   add_mi_cmd_mi ("file-list-exec-source-files",
280 		 mi_cmd_file_list_exec_source_files);
281   add_mi_cmd_mi ("file-list-shared-libraries",
282      mi_cmd_file_list_shared_libraries),
283   add_mi_cmd_cli ("file-symbol-file", "symbol-file", 1);
284   add_mi_cmd_mi ("fix-breakpoint-script-output",
285 		 mi_cmd_fix_breakpoint_script_output),
286   add_mi_cmd_mi ("fix-multi-location-breakpoint-output",
287 		 mi_cmd_fix_multi_location_breakpoint_output),
288   add_mi_cmd_mi ("gdb-exit", mi_cmd_gdb_exit);
289   add_mi_cmd_cli ("gdb-set", "set", 1,
290 		  &mi_suppress_notification.cmd_param_changed);
291   add_mi_cmd_cli ("gdb-show", "show", 1);
292   add_mi_cmd_cli ("gdb-version", "show version", 0);
293   add_mi_cmd_mi ("inferior-tty-set", mi_cmd_inferior_tty_set);
294   add_mi_cmd_mi ("inferior-tty-show", mi_cmd_inferior_tty_show);
295   add_mi_cmd_mi ("info-ada-exceptions", mi_cmd_info_ada_exceptions);
296   add_mi_cmd_mi ("info-gdb-mi-command", mi_cmd_info_gdb_mi_command);
297   add_mi_cmd_mi ("info-os", mi_cmd_info_os);
298   add_mi_cmd_mi ("interpreter-exec", mi_cmd_interpreter_exec);
299   add_mi_cmd_mi ("list-features", mi_cmd_list_features);
300   add_mi_cmd_mi ("list-target-features", mi_cmd_list_target_features);
301   add_mi_cmd_mi ("list-thread-groups", mi_cmd_list_thread_groups);
302   add_mi_cmd_mi ("remove-inferior", mi_cmd_remove_inferior);
303   add_mi_cmd_mi ("stack-info-depth", mi_cmd_stack_info_depth);
304   add_mi_cmd_mi ("stack-info-frame", mi_cmd_stack_info_frame);
305   add_mi_cmd_mi ("stack-list-arguments", mi_cmd_stack_list_args);
306   add_mi_cmd_mi ("stack-list-frames", mi_cmd_stack_list_frames);
307   add_mi_cmd_mi ("stack-list-locals", mi_cmd_stack_list_locals);
308   add_mi_cmd_mi ("stack-list-variables", mi_cmd_stack_list_variables);
309   add_mi_cmd_mi ("stack-select-frame", mi_cmd_stack_select_frame,
310 		 &mi_suppress_notification.user_selected_context);
311   add_mi_cmd_mi ("symbol-list-lines", mi_cmd_symbol_list_lines);
312   add_mi_cmd_mi ("symbol-info-functions", mi_cmd_symbol_info_functions);
313   add_mi_cmd_mi ("symbol-info-variables", mi_cmd_symbol_info_variables);
314   add_mi_cmd_mi ("symbol-info-types", mi_cmd_symbol_info_types);
315   add_mi_cmd_mi ("symbol-info-modules", mi_cmd_symbol_info_modules);
316   add_mi_cmd_mi ("symbol-info-module-functions",
317 		 mi_cmd_symbol_info_module_functions);
318   add_mi_cmd_mi ("symbol-info-module-variables",
319 		 mi_cmd_symbol_info_module_variables);
320   add_mi_cmd_cli ("target-attach", "attach", 1);
321   add_mi_cmd_mi ("target-detach", mi_cmd_target_detach);
322   add_mi_cmd_cli ("target-disconnect", "disconnect", 0);
323   add_mi_cmd_cli ("target-download", "load", 1);
324   add_mi_cmd_mi ("target-file-delete", mi_cmd_target_file_delete);
325   add_mi_cmd_mi ("target-file-get", mi_cmd_target_file_get);
326   add_mi_cmd_mi ("target-file-put", mi_cmd_target_file_put);
327   add_mi_cmd_mi ("target-flash-erase", mi_cmd_target_flash_erase);
328   add_mi_cmd_cli ("target-select", "target", 1);
329   add_mi_cmd_mi ("thread-info", mi_cmd_thread_info);
330   add_mi_cmd_mi ("thread-list-ids", mi_cmd_thread_list_ids);
331   add_mi_cmd_mi ("thread-select", mi_cmd_thread_select,
332 		 &mi_suppress_notification.user_selected_context);
333   add_mi_cmd_mi ("trace-define-variable", mi_cmd_trace_define_variable);
334   add_mi_cmd_mi ("trace-find", mi_cmd_trace_find,
335 		 &mi_suppress_notification.traceframe);
336   add_mi_cmd_mi ("trace-frame-collected", mi_cmd_trace_frame_collected);
337   add_mi_cmd_mi ("trace-list-variables", mi_cmd_trace_list_variables);
338   add_mi_cmd_mi ("trace-save", mi_cmd_trace_save);
339   add_mi_cmd_mi ("trace-start", mi_cmd_trace_start);
340   add_mi_cmd_mi ("trace-status", mi_cmd_trace_status);
341   add_mi_cmd_mi ("trace-stop", mi_cmd_trace_stop);
342   add_mi_cmd_mi ("var-assign", mi_cmd_var_assign);
343   add_mi_cmd_mi ("var-create", mi_cmd_var_create);
344   add_mi_cmd_mi ("var-delete", mi_cmd_var_delete);
345   add_mi_cmd_mi ("var-evaluate-expression", mi_cmd_var_evaluate_expression);
346   add_mi_cmd_mi ("var-info-path-expression", mi_cmd_var_info_path_expression);
347   add_mi_cmd_mi ("var-info-expression", mi_cmd_var_info_expression);
348   add_mi_cmd_mi ("var-info-num-children", mi_cmd_var_info_num_children);
349   add_mi_cmd_mi ("var-info-type", mi_cmd_var_info_type);
350   add_mi_cmd_mi ("var-list-children", mi_cmd_var_list_children);
351   add_mi_cmd_mi ("var-set-format", mi_cmd_var_set_format);
352   add_mi_cmd_mi ("var-set-frozen", mi_cmd_var_set_frozen);
353   add_mi_cmd_mi ("var-set-update-range", mi_cmd_var_set_update_range);
354   add_mi_cmd_mi ("var-set-visualizer", mi_cmd_var_set_visualizer);
355   add_mi_cmd_mi ("var-show-attributes", mi_cmd_var_show_attributes);
356   add_mi_cmd_mi ("var-show-format", mi_cmd_var_show_format);
357   add_mi_cmd_mi ("var-update", mi_cmd_var_update);
358 }
359 
360 /* See mi-cmds.h.  */
361 
362 mi_command *
363 mi_cmd_lookup (const char *command)
364 {
365   gdb_assert (command != nullptr);
366 
367   auto it = mi_cmd_table.find (command);
368   if (it == mi_cmd_table.end ())
369     return nullptr;
370   return it->second.get ();
371 }
372 
373 void _initialize_mi_cmds ();
374 void
375 _initialize_mi_cmds ()
376 {
377   add_builtin_mi_commands ();
378 }
379