]>
Commit | Line | Data |
---|---|---|
4a8f6654 AC |
1 | /* MI Interpreter Definitions and Commands for GDB, the GNU debugger. |
2 | ||
213516ef | 3 | Copyright (C) 2002-2023 Free Software Foundation, Inc. |
4a8f6654 AC |
4 | |
5 | This file is part of GDB. | |
6 | ||
7 | This program is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
a9762ec7 | 9 | the Free Software Foundation; either version 3 of the License, or |
4a8f6654 AC |
10 | (at your option) any later version. |
11 | ||
12 | This program is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
a9762ec7 | 18 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
4a8f6654 AC |
19 | |
20 | #include "defs.h" | |
23baa4cc SM |
21 | |
22 | #include "mi-interp.h" | |
23 | ||
4a8f6654 AC |
24 | #include "interps.h" |
25 | #include "event-top.h" | |
400b5eca | 26 | #include "gdbsupport/event-loop.h" |
4a8f6654 | 27 | #include "inferior.h" |
45741a9c | 28 | #include "infrun.h" |
4a8f6654 | 29 | #include "ui-out.h" |
13d03262 | 30 | #include "ui.h" |
4a8f6654 AC |
31 | #include "mi-main.h" |
32 | #include "mi-cmds.h" | |
33 | #include "mi-out.h" | |
34 | #include "mi-console.h" | |
66bb093b | 35 | #include "mi-common.h" |
76727919 | 36 | #include "observable.h" |
683f2885 | 37 | #include "gdbthread.h" |
c86cf029 | 38 | #include "solist.h" |
8de0566d | 39 | #include "objfiles.h" |
134a2066 | 40 | #include "tracepoint.h" |
17b2616c | 41 | #include "cli-out.h" |
243a9253 | 42 | #include "thread-fsm.h" |
26cde2cc | 43 | #include "cli/cli-interp.h" |
268a13a5 | 44 | #include "gdbsupport/scope-exit.h" |
4a8f6654 | 45 | |
2b03b41d SS |
46 | /* These are the interpreter setup, etc. functions for the MI |
47 | interpreter. */ | |
48 | ||
ee047554 | 49 | static void mi_execute_command_wrapper (const char *cmd); |
95bc9f0b TT |
50 | static void mi_execute_command_input_handler |
51 | (gdb::unique_xmalloc_ptr<char> &&cmd); | |
4a8f6654 AC |
52 | |
53 | /* These are hooks that we put in place while doing interpreter_exec | |
2b03b41d SS |
54 | so we can report interesting things that happened "behind the MI's |
55 | back" in this command. */ | |
56 | ||
bee0189a | 57 | static int mi_interp_query_hook (const char *ctlstr, va_list ap) |
2b03b41d | 58 | ATTRIBUTE_PRINTF (1, 0); |
4a8f6654 | 59 | |
4a8f6654 AC |
60 | static void mi_insert_notify_hooks (void); |
61 | static void mi_remove_notify_hooks (void); | |
fd664c91 | 62 | |
8d3788bd | 63 | static void mi_breakpoint_modified (struct breakpoint *b); |
5b9afe8a | 64 | static void mi_command_param_changed (const char *param, const char *value); |
8de0566d YQ |
65 | static void mi_memory_changed (struct inferior *inf, CORE_ADDR memaddr, |
66 | ssize_t len, const bfd_byte *myaddr); | |
683f2885 | 67 | |
05beb275 PA |
68 | /* Display the MI prompt. */ |
69 | ||
70 | static void | |
9204d692 | 71 | display_mi_prompt (struct mi_interp *mi) |
05beb275 | 72 | { |
3b12939d PA |
73 | struct ui *ui = current_ui; |
74 | ||
0426ad51 | 75 | gdb_puts ("(gdb) \n", mi->raw_stdout); |
9204d692 | 76 | gdb_flush (mi->raw_stdout); |
3b12939d | 77 | ui->prompt_state = PROMPTED; |
05beb275 PA |
78 | } |
79 | ||
73ab01a0 PA |
80 | /* Returns the INTERP's data cast as mi_interp if INTERP is an MI, and |
81 | returns NULL otherwise. */ | |
82 | ||
83 | static struct mi_interp * | |
84 | as_mi_interp (struct interp *interp) | |
85 | { | |
716b8bc5 | 86 | return dynamic_cast<mi_interp *> (interp); |
73ab01a0 PA |
87 | } |
88 | ||
2736b771 SM |
89 | void |
90 | mi_interp::on_command_error () | |
e8b4efc3 | 91 | { |
2736b771 | 92 | display_mi_prompt (this); |
e8b4efc3 TT |
93 | } |
94 | ||
d6f9b0fb PA |
95 | void |
96 | mi_interp::init (bool top_level) | |
4a8f6654 | 97 | { |
d6f9b0fb | 98 | mi_interp *mi = this; |
4a8f6654 | 99 | |
9204d692 PA |
100 | /* Store the current output channel, so that we can create a console |
101 | channel that encapsulates and prefixes all gdb_output-type bits | |
102 | coming from the rest of the debugger. */ | |
103 | mi->raw_stdout = gdb_stdout; | |
4a8f6654 | 104 | |
2b03b41d SS |
105 | /* Create MI console channels, each with a different prefix so they |
106 | can be distinguished. */ | |
d7e74731 PA |
107 | mi->out = new mi_console_file (mi->raw_stdout, "~", '"'); |
108 | mi->err = new mi_console_file (mi->raw_stdout, "&", '"'); | |
4a8f6654 | 109 | mi->log = mi->err; |
d7e74731 PA |
110 | mi->targ = new mi_console_file (mi->raw_stdout, "@", '"'); |
111 | mi->event_channel = new mi_console_file (mi->raw_stdout, "=", 0); | |
8e5e5494 SM |
112 | mi->mi_uiout = mi_out_new (name ()); |
113 | gdb_assert (mi->mi_uiout != nullptr); | |
66fd2c67 | 114 | mi->cli_uiout = new cli_ui_out (mi->out); |
fd664c91 | 115 | |
683f2885 | 116 | if (top_level) |
063bfe2e | 117 | { |
788eca49 SM |
118 | /* The initial inferior is created before this function is called, so we |
119 | need to report it explicitly when initializing the top-level MI | |
120 | interpreter. | |
121 | ||
122 | This is also called when additional MI interpreters are added (using | |
123 | the new-ui command), when multiple inferiors possibly exist, so we need | |
023c6d45 | 124 | to use iteration to report all the inferiors. */ |
788eca49 SM |
125 | |
126 | for (inferior *inf : all_inferiors ()) | |
023c6d45 | 127 | mi->on_inferior_added (inf); |
788eca49 | 128 | } |
4a8f6654 AC |
129 | } |
130 | ||
d6f9b0fb PA |
131 | void |
132 | mi_interp::resume () | |
4a8f6654 | 133 | { |
d6f9b0fb | 134 | struct mi_interp *mi = this; |
a74e1786 | 135 | struct ui *ui = current_ui; |
4a8f6654 | 136 | |
2b03b41d SS |
137 | /* As per hack note in mi_interpreter_init, swap in the output |
138 | channels... */ | |
3c216924 | 139 | gdb_setup_readline (0); |
4a8f6654 | 140 | |
a74e1786 PA |
141 | ui->call_readline = gdb_readline_no_editing_callback; |
142 | ui->input_handler = mi_execute_command_input_handler; | |
4a8f6654 AC |
143 | |
144 | gdb_stdout = mi->out; | |
2b03b41d | 145 | /* Route error and log output through the MI. */ |
4a8f6654 AC |
146 | gdb_stderr = mi->err; |
147 | gdb_stdlog = mi->log; | |
2b03b41d | 148 | /* Route target output through the MI. */ |
4a8f6654 | 149 | gdb_stdtarg = mi->targ; |
2b03b41d | 150 | /* Route target error through the MI as well. */ |
1f20321b | 151 | gdb_stdtargerr = mi->targ; |
4a8f6654 | 152 | |
9a4105ab | 153 | deprecated_show_load_progress = mi_load_progress; |
4a8f6654 AC |
154 | } |
155 | ||
d6f9b0fb PA |
156 | void |
157 | mi_interp::suspend () | |
4a8f6654 AC |
158 | { |
159 | gdb_disable_readline (); | |
4a8f6654 AC |
160 | } |
161 | ||
b885aea1 | 162 | void |
d6f9b0fb | 163 | mi_interp::exec (const char *command) |
4a8f6654 | 164 | { |
ee047554 | 165 | mi_execute_command_wrapper (command); |
4a8f6654 AC |
166 | } |
167 | ||
ce8f13f8 | 168 | void |
9158e49a TT |
169 | mi_cmd_interpreter_exec (const char *command, const char *const *argv, |
170 | int argc) | |
4a8f6654 AC |
171 | { |
172 | struct interp *interp_to_use; | |
4a8f6654 | 173 | int i; |
4a8f6654 AC |
174 | |
175 | if (argc < 2) | |
1b05df00 | 176 | error (_("-interpreter-exec: " |
9b20d036 | 177 | "Usage: -interpreter-exec interp command")); |
4a8f6654 | 178 | |
8322445e | 179 | interp_to_use = interp_lookup (current_ui, argv[0]); |
4a8f6654 | 180 | if (interp_to_use == NULL) |
1b05df00 | 181 | error (_("-interpreter-exec: could not find interpreter \"%s\""), |
9a2b4c1b | 182 | argv[0]); |
4a8f6654 | 183 | |
17b2616c PA |
184 | /* Note that unlike the CLI version of this command, we don't |
185 | actually set INTERP_TO_USE as the current interpreter, as we | |
186 | still want gdb_stdout, etc. to point at MI streams. */ | |
187 | ||
2b03b41d SS |
188 | /* Insert the MI out hooks, making sure to also call the |
189 | interpreter's hooks if it has any. */ | |
190 | /* KRS: We shouldn't need this... Events should be installed and | |
191 | they should just ALWAYS fire something out down the MI | |
192 | channel. */ | |
4a8f6654 AC |
193 | mi_insert_notify_hooks (); |
194 | ||
2b03b41d | 195 | /* Now run the code. */ |
4a8f6654 | 196 | |
3d6e9d23 TT |
197 | SCOPE_EXIT |
198 | { | |
199 | mi_remove_notify_hooks (); | |
200 | }; | |
201 | ||
4a8f6654 | 202 | for (i = 1; i < argc; i++) |
b885aea1 | 203 | interp_exec (interp_to_use, argv[i]); |
4a8f6654 AC |
204 | } |
205 | ||
2b03b41d SS |
206 | /* This inserts a number of hooks that are meant to produce |
207 | async-notify ("=") MI messages while running commands in another | |
208 | interpreter using mi_interpreter_exec. The canonical use for this | |
209 | is to allow access to the gdb CLI interpreter from within the MI, | |
210 | while still producing MI style output when actions in the CLI | |
211 | command change GDB's state. */ | |
4a8f6654 AC |
212 | |
213 | static void | |
214 | mi_insert_notify_hooks (void) | |
215 | { | |
9a4105ab | 216 | deprecated_query_hook = mi_interp_query_hook; |
4a8f6654 AC |
217 | } |
218 | ||
219 | static void | |
11308a41 | 220 | mi_remove_notify_hooks (void) |
4a8f6654 | 221 | { |
9a4105ab | 222 | deprecated_query_hook = NULL; |
4a8f6654 AC |
223 | } |
224 | ||
225 | static int | |
226 | mi_interp_query_hook (const char *ctlstr, va_list ap) | |
227 | { | |
228 | return 1; | |
229 | } | |
230 | ||
4a8f6654 | 231 | static void |
ee047554 | 232 | mi_execute_command_wrapper (const char *cmd) |
4a8f6654 | 233 | { |
f38d3ad1 PA |
234 | struct ui *ui = current_ui; |
235 | ||
268a799a | 236 | mi_execute_command (cmd, ui->instream == ui->stdin_stream); |
4a8f6654 AC |
237 | } |
238 | ||
c3d321de SM |
239 | void |
240 | mi_interp::on_sync_execution_done () | |
329ea579 | 241 | { |
0b333c5e PA |
242 | /* If MI is sync, then output the MI prompt now, indicating we're |
243 | ready for further input. */ | |
329ea579 | 244 | if (!mi_async_p ()) |
c3d321de | 245 | display_mi_prompt (this); |
329ea579 PA |
246 | } |
247 | ||
e837f12a JK |
248 | /* mi_execute_command_wrapper wrapper suitable for INPUT_HANDLER. */ |
249 | ||
250 | static void | |
95bc9f0b | 251 | mi_execute_command_input_handler (gdb::unique_xmalloc_ptr<char> &&cmd) |
e837f12a | 252 | { |
9204d692 | 253 | struct mi_interp *mi = as_mi_interp (top_level_interpreter ()); |
3b12939d PA |
254 | struct ui *ui = current_ui; |
255 | ||
256 | ui->prompt_state = PROMPT_NEEDED; | |
9204d692 | 257 | |
95bc9f0b | 258 | mi_execute_command_wrapper (cmd.get ()); |
e837f12a | 259 | |
0b333c5e PA |
260 | /* Print a prompt, indicating we're ready for further input, unless |
261 | we just started a synchronous command. In that case, we're about | |
262 | to go back to the event loop and will output the prompt in the | |
263 | 'synchronous_command_done' observer when the target next | |
264 | stops. */ | |
3b12939d | 265 | if (ui->prompt_state == PROMPT_NEEDED) |
9204d692 | 266 | display_mi_prompt (mi); |
e837f12a JK |
267 | } |
268 | ||
d6f9b0fb PA |
269 | void |
270 | mi_interp::pre_command_loop () | |
4a8f6654 | 271 | { |
d6f9b0fb | 272 | struct mi_interp *mi = this; |
9204d692 | 273 | |
4a8f6654 | 274 | /* Turn off 8 bit strings in quoted output. Any character with the |
2b03b41d | 275 | high bit set is printed using C's octal format. */ |
4a8f6654 | 276 | sevenbit_strings = 1; |
2b03b41d SS |
277 | |
278 | /* Tell the world that we're alive. */ | |
9204d692 | 279 | display_mi_prompt (mi); |
4a8f6654 AC |
280 | } |
281 | ||
30e7e0a9 SM |
282 | void |
283 | mi_interp::on_new_thread (thread_info *t) | |
683f2885 | 284 | { |
30e7e0a9 SM |
285 | target_terminal::scoped_restore_terminal_state term_state; |
286 | target_terminal::ours_for_output (); | |
73ab01a0 | 287 | |
30e7e0a9 SM |
288 | gdb_printf (this->event_channel, "thread-created,id=\"%d\",group-id=\"i%d\"", |
289 | t->global_num, t->inf->num); | |
290 | gdb_flush (this->event_channel); | |
683f2885 VP |
291 | } |
292 | ||
8e7af843 SM |
293 | void |
294 | mi_interp::on_thread_exited (thread_info *t, int silent) | |
063bfe2e | 295 | { |
8e7af843 SM |
296 | target_terminal::scoped_restore_terminal_state term_state; |
297 | target_terminal::ours_for_output (); | |
298 | gdb_printf (this->event_channel, "thread-exited,id=\"%d\",group-id=\"i%d\"", | |
299 | t->global_num, t->inf->num); | |
300 | gdb_flush (this->event_channel); | |
063bfe2e VP |
301 | } |
302 | ||
44fbffc6 SM |
303 | void |
304 | mi_interp::on_record_changed (inferior *inferior, int started, | |
305 | const char *method, const char *format) | |
82a90ccf | 306 | { |
44fbffc6 SM |
307 | target_terminal::scoped_restore_terminal_state term_state; |
308 | target_terminal::ours_for_output (); | |
73ab01a0 | 309 | |
44fbffc6 SM |
310 | if (started) |
311 | { | |
312 | if (format != NULL) | |
313 | gdb_printf (this->event_channel, | |
314 | "record-started,thread-group=\"i%d\"," | |
315 | "method=\"%s\",format=\"%s\"", | |
316 | inferior->num, method, format); | |
38b022b4 | 317 | else |
44fbffc6 SM |
318 | gdb_printf (this->event_channel, |
319 | "record-started,thread-group=\"i%d\"," | |
320 | "method=\"%s\"", | |
321 | inferior->num, method); | |
73ab01a0 | 322 | } |
44fbffc6 SM |
323 | else |
324 | gdb_printf (this->event_channel, | |
325 | "record-stopped,thread-group=\"i%d\"", | |
326 | inferior->num); | |
327 | ||
328 | gdb_flush (this->event_channel); | |
82a90ccf YQ |
329 | } |
330 | ||
023c6d45 SM |
331 | void |
332 | mi_interp::on_inferior_added (inferior *inf) | |
a79b8f6e | 333 | { |
023c6d45 SM |
334 | target_terminal::scoped_restore_terminal_state term_state; |
335 | target_terminal::ours_for_output (); | |
73ab01a0 | 336 | |
023c6d45 SM |
337 | gdb_printf (this->event_channel, "thread-group-added,id=\"i%d\"", inf->num); |
338 | gdb_flush (this->event_channel); | |
a79b8f6e VP |
339 | } |
340 | ||
0c613e17 SM |
341 | void |
342 | mi_interp::on_inferior_appeared (inferior *inf) | |
4a92f99b | 343 | { |
0c613e17 SM |
344 | target_terminal::scoped_restore_terminal_state term_state; |
345 | target_terminal::ours_for_output (); | |
73ab01a0 | 346 | |
0c613e17 SM |
347 | gdb_printf (this->event_channel, "thread-group-started,id=\"i%d\",pid=\"%d\"", |
348 | inf->num, inf->pid); | |
349 | gdb_flush (this->event_channel); | |
4a92f99b VP |
350 | } |
351 | ||
d38086cc SM |
352 | void |
353 | mi_interp::on_inferior_disappeared (inferior *inf) | |
4a92f99b | 354 | { |
d38086cc SM |
355 | target_terminal::scoped_restore_terminal_state term_state; |
356 | target_terminal::ours_for_output (); | |
73ab01a0 | 357 | |
d38086cc SM |
358 | if (inf->has_exit_code) |
359 | gdb_printf (this->event_channel, | |
360 | "thread-group-exited,id=\"i%d\",exit-code=\"%s\"", | |
361 | inf->num, int_string (inf->exit_code, 8, 0, 0, 1)); | |
362 | else | |
363 | gdb_printf (this->event_channel, | |
364 | "thread-group-exited,id=\"i%d\"", inf->num); | |
73ab01a0 | 365 | |
d38086cc | 366 | gdb_flush (this->event_channel); |
4a92f99b VP |
367 | } |
368 | ||
2646bfa7 SM |
369 | void |
370 | mi_interp::on_inferior_removed (inferior *inf) | |
a79b8f6e | 371 | { |
2646bfa7 SM |
372 | target_terminal::scoped_restore_terminal_state term_state; |
373 | target_terminal::ours_for_output (); | |
73ab01a0 | 374 | |
2646bfa7 SM |
375 | gdb_printf (this->event_channel, "thread-group-removed,id=\"i%d\"", inf->num); |
376 | gdb_flush (this->event_channel); | |
a79b8f6e VP |
377 | } |
378 | ||
fd664c91 | 379 | /* Observers for several run control events that print why the |
6471e7d2 | 380 | inferior has stopped to both the MI event channel and to the MI |
fd664c91 PA |
381 | console. If the MI interpreter is not active, print nothing. */ |
382 | ||
3f75a984 SM |
383 | void |
384 | mi_interp::on_signal_received (enum gdb_signal siggnal) | |
fd664c91 | 385 | { |
3f75a984 SM |
386 | print_signal_received_reason (this->mi_uiout, siggnal); |
387 | print_signal_received_reason (this->cli_uiout, siggnal); | |
fd664c91 PA |
388 | } |
389 | ||
d6bd2ef5 SM |
390 | void |
391 | mi_interp::on_signal_exited (gdb_signal sig) | |
17b2616c | 392 | { |
d6bd2ef5 SM |
393 | print_signal_exited_reason (this->mi_uiout, sig); |
394 | print_signal_exited_reason (this->cli_uiout, sig); | |
fd664c91 PA |
395 | } |
396 | ||
bf64d1d5 SM |
397 | void |
398 | mi_interp::on_exited (int status) | |
fd664c91 | 399 | { |
bf64d1d5 SM |
400 | print_exited_reason (this->mi_uiout, status); |
401 | print_exited_reason (this->cli_uiout, status); | |
fd664c91 PA |
402 | } |
403 | ||
2e5dbfab SM |
404 | void |
405 | mi_interp::on_no_history () | |
fd664c91 | 406 | { |
2e5dbfab SM |
407 | print_no_history_reason (this->mi_uiout); |
408 | print_no_history_reason (this->cli_uiout); | |
17b2616c PA |
409 | } |
410 | ||
87829267 SM |
411 | void |
412 | mi_interp::on_normal_stop (struct bpstat *bs, int print_frame) | |
f7f9a841 VP |
413 | { |
414 | /* Since this can be called when CLI command is executing, | |
415 | using cli interpreter, be sure to use MI uiout for output, | |
416 | not the current one. */ | |
87829267 | 417 | ui_out *mi_uiout = this->interp_ui_out (); |
f7f9a841 | 418 | |
1d33d6ba VP |
419 | if (print_frame) |
420 | { | |
87829267 | 421 | thread_info *tp = inferior_thread (); |
36dfb11c | 422 | |
573269a8 LS |
423 | if (tp->thread_fsm () != nullptr |
424 | && tp->thread_fsm ()->finished_p ()) | |
243a9253 | 425 | { |
87829267 SM |
426 | async_reply_reason reason |
427 | = tp->thread_fsm ()->async_reply_reason (); | |
112e8700 | 428 | mi_uiout->field_string ("reason", async_reason_lookup (reason)); |
1d33d6ba | 429 | } |
243a9253 | 430 | |
87829267 SM |
431 | interp *console_interp = interp_lookup (current_ui, INTERP_CONSOLE); |
432 | ||
4c7d57e7 TT |
433 | /* We only want to print the displays once, and we want it to |
434 | look just how it would on the console, so we use this to | |
435 | decide whether the MI stop should include them. */ | |
436 | bool console_print = should_print_stop_to_console (console_interp, tp); | |
437 | print_stop_event (mi_uiout, !console_print); | |
438 | ||
439 | if (console_print) | |
87829267 | 440 | print_stop_event (this->cli_uiout); |
1d33d6ba | 441 | |
381befee | 442 | mi_uiout->field_signed ("thread-id", tp->global_num); |
1d33d6ba VP |
443 | if (non_stop) |
444 | { | |
10f489e5 | 445 | ui_out_emit_list list_emitter (mi_uiout, "stopped-threads"); |
102040f0 | 446 | |
381befee | 447 | mi_uiout->field_signed (NULL, tp->global_num); |
1d33d6ba VP |
448 | } |
449 | else | |
112e8700 | 450 | mi_uiout->field_string ("stopped-threads", "all"); |
dc146f7c | 451 | |
87829267 | 452 | int core = target_core_of_thread (tp->ptid); |
dc146f7c | 453 | if (core != -1) |
381befee | 454 | mi_uiout->field_signed ("core", core); |
1d33d6ba | 455 | } |
f7f9a841 | 456 | |
87829267 SM |
457 | gdb_puts ("*stopped", this->raw_stdout); |
458 | mi_out_put (mi_uiout, this->raw_stdout); | |
459 | mi_out_rewind (mi_uiout); | |
460 | mi_print_timing_maybe (this->raw_stdout); | |
461 | gdb_puts ("\n", this->raw_stdout); | |
462 | gdb_flush (this->raw_stdout); | |
73ab01a0 PA |
463 | } |
464 | ||
7603ea6a SM |
465 | void |
466 | mi_interp::on_about_to_proceed () | |
f3b1572e PA |
467 | { |
468 | /* Suppress output while calling an inferior function. */ | |
469 | ||
d7e15655 | 470 | if (inferior_ptid != null_ptid) |
f3b1572e PA |
471 | { |
472 | struct thread_info *tp = inferior_thread (); | |
102040f0 | 473 | |
16c381f0 | 474 | if (tp->control.in_infcall) |
f3b1572e PA |
475 | return; |
476 | } | |
477 | ||
7603ea6a | 478 | this->mi_proceeded = 1; |
f3b1572e PA |
479 | } |
480 | ||
5b9afe8a YQ |
481 | /* When the element is non-zero, no MI notifications will be emitted in |
482 | response to the corresponding observers. */ | |
2b03b41d | 483 | |
5b9afe8a YQ |
484 | struct mi_suppress_notification mi_suppress_notification = |
485 | { | |
486 | 0, | |
487 | 0, | |
201b4506 | 488 | 0, |
4034d0ff | 489 | 0, |
5b9afe8a | 490 | }; |
8d3788bd | 491 | |
0bc845fc SM |
492 | void |
493 | mi_interp::on_traceframe_changed (int tfnum, int tpnum) | |
201b4506 | 494 | { |
201b4506 YQ |
495 | if (mi_suppress_notification.traceframe) |
496 | return; | |
497 | ||
0bc845fc SM |
498 | target_terminal::scoped_restore_terminal_state term_state; |
499 | target_terminal::ours_for_output (); | |
5fe96654 | 500 | |
0bc845fc SM |
501 | if (tfnum >= 0) |
502 | gdb_printf (this->event_channel, "traceframe-changed," | |
503 | "num=\"%d\",tracepoint=\"%d\"", | |
504 | tfnum, tpnum); | |
505 | else | |
506 | gdb_printf (this->event_channel, "traceframe-changed,end"); | |
73ab01a0 | 507 | |
0bc845fc | 508 | gdb_flush (this->event_channel); |
201b4506 YQ |
509 | } |
510 | ||
bf506f27 SM |
511 | void |
512 | mi_interp::on_tsv_created (const trace_state_variable *tsv) | |
bb25a15c | 513 | { |
bf506f27 SM |
514 | target_terminal::scoped_restore_terminal_state term_state; |
515 | target_terminal::ours_for_output (); | |
5fe96654 | 516 | |
bf506f27 SM |
517 | gdb_printf (this->event_channel, "tsv-created," |
518 | "name=\"%s\",initial=\"%s\"", | |
519 | tsv->name.c_str (), plongest (tsv->initial_value)); | |
73ab01a0 | 520 | |
bf506f27 | 521 | gdb_flush (this->event_channel); |
bb25a15c YQ |
522 | } |
523 | ||
f0dffaff SM |
524 | void |
525 | mi_interp::on_tsv_deleted (const trace_state_variable *tsv) | |
bb25a15c | 526 | { |
f0dffaff SM |
527 | target_terminal::scoped_restore_terminal_state term_state; |
528 | target_terminal::ours_for_output (); | |
5fe96654 | 529 | |
f0dffaff SM |
530 | if (tsv != nullptr) |
531 | gdb_printf (this->event_channel, "tsv-deleted,name=\"%s\"", | |
532 | tsv->name.c_str ()); | |
533 | else | |
534 | gdb_printf (this->event_channel, "tsv-deleted"); | |
73ab01a0 | 535 | |
f0dffaff | 536 | gdb_flush (this->event_channel); |
bb25a15c YQ |
537 | } |
538 | ||
c27ec5c0 SM |
539 | void |
540 | mi_interp::on_tsv_modified (const trace_state_variable *tsv) | |
134a2066 | 541 | { |
c27ec5c0 | 542 | ui_out *mi_uiout = this->interp_ui_out (); |
134a2066 | 543 | |
c27ec5c0 SM |
544 | target_terminal::scoped_restore_terminal_state term_state; |
545 | target_terminal::ours_for_output (); | |
134a2066 | 546 | |
c27ec5c0 SM |
547 | gdb_printf (this->event_channel, |
548 | "tsv-modified"); | |
134a2066 | 549 | |
c27ec5c0 | 550 | ui_out_redirect_pop redir (mi_uiout, this->event_channel); |
5fe96654 | 551 | |
c27ec5c0 SM |
552 | mi_uiout->field_string ("name", tsv->name); |
553 | mi_uiout->field_string ("initial", | |
554 | plongest (tsv->initial_value)); | |
555 | if (tsv->value_known) | |
556 | mi_uiout->field_string ("current", plongest (tsv->value)); | |
73ab01a0 | 557 | |
c27ec5c0 | 558 | gdb_flush (this->event_channel); |
134a2066 YQ |
559 | } |
560 | ||
65630365 PA |
561 | /* Print breakpoint BP on MI's event channel. */ |
562 | ||
563 | static void | |
564 | mi_print_breakpoint_for_event (struct mi_interp *mi, breakpoint *bp) | |
565 | { | |
29f94340 | 566 | ui_out *mi_uiout = mi->interp_ui_out (); |
65630365 PA |
567 | |
568 | /* We want the output from print_breakpoint to go to | |
569 | mi->event_channel. One approach would be to just call | |
570 | print_breakpoint, and then use mi_out_put to send the current | |
571 | content of mi_uiout into mi->event_channel. However, that will | |
572 | break if anything is output to mi_uiout prior to calling the | |
573 | breakpoint_created notifications. So, we use | |
574 | ui_out_redirect. */ | |
992aeed8 | 575 | ui_out_redirect_pop redir (mi_uiout, mi->event_channel); |
65630365 | 576 | |
a70b8144 | 577 | try |
65630365 PA |
578 | { |
579 | scoped_restore restore_uiout | |
580 | = make_scoped_restore (¤t_uiout, mi_uiout); | |
581 | ||
582 | print_breakpoint (bp); | |
583 | } | |
b1ffd112 | 584 | catch (const gdb_exception_error &ex) |
65630365 PA |
585 | { |
586 | exception_print (gdb_stderr, ex); | |
587 | } | |
65630365 PA |
588 | } |
589 | ||
e7692320 SM |
590 | void |
591 | mi_interp::on_breakpoint_created (breakpoint *b) | |
8d3788bd | 592 | { |
5b9afe8a | 593 | if (mi_suppress_notification.breakpoint) |
8d3788bd VP |
594 | return; |
595 | ||
596 | if (b->number <= 0) | |
597 | return; | |
598 | ||
e7692320 SM |
599 | target_terminal::scoped_restore_terminal_state term_state; |
600 | target_terminal::ours_for_output (); | |
73ab01a0 | 601 | |
e7692320 SM |
602 | gdb_printf (this->event_channel, "breakpoint-created"); |
603 | mi_print_breakpoint_for_event (this, b); | |
73ab01a0 | 604 | |
e7692320 | 605 | gdb_flush (this->event_channel); |
8d3788bd VP |
606 | } |
607 | ||
e4239559 SM |
608 | void |
609 | mi_interp::on_breakpoint_deleted (breakpoint *b) | |
8d3788bd | 610 | { |
5b9afe8a | 611 | if (mi_suppress_notification.breakpoint) |
8d3788bd VP |
612 | return; |
613 | ||
614 | if (b->number <= 0) | |
615 | return; | |
616 | ||
e4239559 SM |
617 | target_terminal::scoped_restore_terminal_state term_state; |
618 | target_terminal::ours_for_output (); | |
73ab01a0 | 619 | |
e4239559 SM |
620 | gdb_printf (this->event_channel, "breakpoint-deleted,id=\"%d\"", b->number); |
621 | gdb_flush (this->event_channel); | |
8d3788bd VP |
622 | } |
623 | ||
624 | /* Emit notification about modified breakpoint. */ | |
2b03b41d | 625 | |
8d3788bd VP |
626 | static void |
627 | mi_breakpoint_modified (struct breakpoint *b) | |
628 | { | |
5b9afe8a | 629 | if (mi_suppress_notification.breakpoint) |
8d3788bd VP |
630 | return; |
631 | ||
632 | if (b->number <= 0) | |
633 | return; | |
634 | ||
0e454242 | 635 | SWITCH_THRU_ALL_UIS () |
492d29ea | 636 | { |
73ab01a0 | 637 | struct mi_interp *mi = as_mi_interp (top_level_interpreter ()); |
492d29ea | 638 | |
73ab01a0 PA |
639 | if (mi == NULL) |
640 | continue; | |
8d3788bd | 641 | |
223ffa71 TT |
642 | target_terminal::scoped_restore_terminal_state term_state; |
643 | target_terminal::ours_for_output (); | |
6cb06a8c TT |
644 | gdb_printf (mi->event_channel, |
645 | "breakpoint-modified"); | |
65630365 | 646 | mi_print_breakpoint_for_event (mi, b); |
73ab01a0 PA |
647 | |
648 | gdb_flush (mi->event_channel); | |
73ab01a0 | 649 | } |
8d3788bd VP |
650 | } |
651 | ||
00431a78 PA |
652 | static void |
653 | mi_output_running (struct thread_info *thread) | |
d90e17a7 | 654 | { |
0e454242 | 655 | SWITCH_THRU_ALL_UIS () |
73ab01a0 PA |
656 | { |
657 | struct mi_interp *mi = as_mi_interp (top_level_interpreter ()); | |
658 | ||
659 | if (mi == NULL) | |
660 | continue; | |
661 | ||
6cb06a8c TT |
662 | gdb_printf (mi->raw_stdout, |
663 | "*running,thread-id=\"%d\"\n", | |
664 | thread->global_num); | |
73ab01a0 | 665 | } |
d90e17a7 PA |
666 | } |
667 | ||
08036331 PA |
668 | /* Return true if there are multiple inferiors loaded. This is used |
669 | for backwards compatibility -- if there's only one inferior, output | |
670 | "all", otherwise, output each resumed thread individually. */ | |
671 | ||
672 | static bool | |
673 | multiple_inferiors_p () | |
674 | { | |
675 | int count = 0; | |
676 | for (inferior *inf ATTRIBUTE_UNUSED : all_non_exited_inferiors ()) | |
677 | { | |
678 | count++; | |
679 | if (count > 1) | |
680 | return true; | |
681 | } | |
682 | ||
683 | return false; | |
684 | } | |
685 | ||
e1ac3328 | 686 | static void |
5b6d1e4f PA |
687 | mi_on_resume_1 (struct mi_interp *mi, |
688 | process_stratum_target *targ, ptid_t ptid) | |
e1ac3328 | 689 | { |
a2840c35 VP |
690 | /* To cater for older frontends, emit ^running, but do it only once |
691 | per each command. We do it here, since at this point we know | |
692 | that the target was successfully resumed, and in non-async mode, | |
693 | we won't return back to MI interpreter code until the target | |
694 | is done running, so delaying the output of "^running" until then | |
695 | will make it impossible for frontend to know what's going on. | |
696 | ||
697 | In future (MI3), we'll be outputting "^done" here. */ | |
f818c32b | 698 | if (!mi->running_result_record_printed && mi->mi_proceeded) |
a2840c35 | 699 | { |
6cb06a8c TT |
700 | gdb_printf (mi->raw_stdout, "%s^running\n", |
701 | current_token ? current_token : ""); | |
a2840c35 VP |
702 | } |
703 | ||
08036331 PA |
704 | /* Backwards compatibility. If doing a wildcard resume and there's |
705 | only one inferior, output "all", otherwise, output each resumed | |
706 | thread individually. */ | |
707 | if ((ptid == minus_one_ptid || ptid.is_pid ()) | |
708 | && !multiple_inferiors_p ()) | |
6cb06a8c | 709 | gdb_printf (mi->raw_stdout, "*running,thread-id=\"all\"\n"); |
e1ac3328 | 710 | else |
5b6d1e4f | 711 | for (thread_info *tp : all_non_exited_threads (targ, ptid)) |
08036331 | 712 | mi_output_running (tp); |
a2840c35 | 713 | |
f818c32b | 714 | if (!mi->running_result_record_printed && mi->mi_proceeded) |
a2840c35 | 715 | { |
f818c32b | 716 | mi->running_result_record_printed = 1; |
3b12939d PA |
717 | /* This is what gdb used to do historically -- printing prompt |
718 | even if it cannot actually accept any input. This will be | |
719 | surely removed for MI3, and may be removed even earlier. */ | |
720 | if (current_ui->prompt_state == PROMPT_BLOCKED) | |
0426ad51 | 721 | gdb_puts ("(gdb) \n", mi->raw_stdout); |
a2840c35 | 722 | } |
9204d692 | 723 | gdb_flush (mi->raw_stdout); |
e1ac3328 VP |
724 | } |
725 | ||
52d98df7 SM |
726 | void |
727 | mi_interp::on_target_resumed (ptid_t ptid) | |
c86cf029 | 728 | { |
73ab01a0 | 729 | struct thread_info *tp = NULL; |
6ef284bd | 730 | |
5b6d1e4f | 731 | process_stratum_target *target = current_inferior ()->process_target (); |
d7e15655 | 732 | if (ptid == minus_one_ptid || ptid.is_pid ()) |
73ab01a0 PA |
733 | tp = inferior_thread (); |
734 | else | |
9213a6d7 | 735 | tp = target->find_thread (ptid); |
6ef284bd | 736 | |
73ab01a0 PA |
737 | /* Suppress output while calling an inferior function. */ |
738 | if (tp->control.in_infcall) | |
739 | return; | |
6ef284bd | 740 | |
52d98df7 SM |
741 | target_terminal::scoped_restore_terminal_state term_state; |
742 | target_terminal::ours_for_output (); | |
73ab01a0 | 743 | |
52d98df7 | 744 | mi_on_resume_1 (this, target, ptid); |
73ab01a0 | 745 | } |
6ef284bd | 746 | |
51457a05 MAL |
747 | /* See mi-interp.h. */ |
748 | ||
749 | void | |
750 | mi_output_solib_attribs (ui_out *uiout, struct so_list *solib) | |
751 | { | |
752 | struct gdbarch *gdbarch = target_gdbarch (); | |
753 | ||
754 | uiout->field_string ("id", solib->so_original_name); | |
755 | uiout->field_string ("target-name", solib->so_original_name); | |
756 | uiout->field_string ("host-name", solib->so_name); | |
381befee | 757 | uiout->field_signed ("symbols-loaded", solib->symbols_loaded); |
51457a05 MAL |
758 | if (!gdbarch_has_global_solist (target_gdbarch ())) |
759 | uiout->field_fmt ("thread-group", "i%d", current_inferior ()->num); | |
760 | ||
10f489e5 TT |
761 | ui_out_emit_list list_emitter (uiout, "ranges"); |
762 | ui_out_emit_tuple tuple_emitter (uiout, NULL); | |
51457a05 MAL |
763 | if (solib->addr_high != 0) |
764 | { | |
765 | uiout->field_core_addr ("from", gdbarch, solib->addr_low); | |
766 | uiout->field_core_addr ("to", gdbarch, solib->addr_high); | |
767 | } | |
51457a05 MAL |
768 | } |
769 | ||
f6485481 SM |
770 | void |
771 | mi_interp::on_solib_loaded (so_list *solib) | |
73ab01a0 | 772 | { |
f6485481 | 773 | ui_out *uiout = this->interp_ui_out (); |
5fe96654 | 774 | |
f6485481 SM |
775 | target_terminal::scoped_restore_terminal_state term_state; |
776 | target_terminal::ours_for_output (); | |
73ab01a0 | 777 | |
f6485481 | 778 | gdb_printf (this->event_channel, "library-loaded"); |
73ab01a0 | 779 | |
f6485481 | 780 | ui_out_redirect_pop redir (uiout, this->event_channel); |
73ab01a0 | 781 | |
f6485481 | 782 | mi_output_solib_attribs (uiout, solib); |
73ab01a0 | 783 | |
f6485481 | 784 | gdb_flush (this->event_channel); |
c86cf029 VP |
785 | } |
786 | ||
d711fe3b SM |
787 | void |
788 | mi_interp::on_solib_unloaded (so_list *solib) | |
c86cf029 | 789 | { |
d711fe3b | 790 | ui_out *uiout = this->interp_ui_out (); |
6ef284bd | 791 | |
d711fe3b SM |
792 | target_terminal::scoped_restore_terminal_state term_state; |
793 | target_terminal::ours_for_output (); | |
6ef284bd | 794 | |
d711fe3b | 795 | gdb_printf (this->event_channel, "library-unloaded"); |
a79b8f6e | 796 | |
d711fe3b | 797 | ui_out_redirect_pop redir (uiout, this->event_channel); |
5fe96654 | 798 | |
d711fe3b SM |
799 | uiout->field_string ("id", solib->so_original_name); |
800 | uiout->field_string ("target-name", solib->so_original_name); | |
801 | uiout->field_string ("host-name", solib->so_name); | |
802 | if (!gdbarch_has_global_solist (target_gdbarch ())) | |
803 | uiout->field_fmt ("thread-group", "i%d", current_inferior ()->num); | |
73ab01a0 | 804 | |
d711fe3b | 805 | gdb_flush (this->event_channel); |
c86cf029 VP |
806 | } |
807 | ||
5b9afe8a YQ |
808 | /* Emit notification about the command parameter change. */ |
809 | ||
810 | static void | |
811 | mi_command_param_changed (const char *param, const char *value) | |
812 | { | |
5b9afe8a YQ |
813 | if (mi_suppress_notification.cmd_param_changed) |
814 | return; | |
815 | ||
0e454242 | 816 | SWITCH_THRU_ALL_UIS () |
73ab01a0 PA |
817 | { |
818 | struct mi_interp *mi = as_mi_interp (top_level_interpreter ()); | |
819 | struct ui_out *mi_uiout; | |
5b9afe8a | 820 | |
73ab01a0 PA |
821 | if (mi == NULL) |
822 | continue; | |
5b9afe8a | 823 | |
29f94340 | 824 | mi_uiout = top_level_interpreter ()->interp_ui_out (); |
5b9afe8a | 825 | |
223ffa71 TT |
826 | target_terminal::scoped_restore_terminal_state term_state; |
827 | target_terminal::ours_for_output (); | |
5b9afe8a | 828 | |
6cb06a8c | 829 | gdb_printf (mi->event_channel, "cmd-param-changed"); |
5b9afe8a | 830 | |
992aeed8 | 831 | ui_out_redirect_pop redir (mi_uiout, mi->event_channel); |
5fe96654 | 832 | |
112e8700 SM |
833 | mi_uiout->field_string ("param", param); |
834 | mi_uiout->field_string ("value", value); | |
73ab01a0 | 835 | |
73ab01a0 | 836 | gdb_flush (mi->event_channel); |
73ab01a0 | 837 | } |
5b9afe8a YQ |
838 | } |
839 | ||
8de0566d YQ |
840 | /* Emit notification about the target memory change. */ |
841 | ||
842 | static void | |
843 | mi_memory_changed (struct inferior *inferior, CORE_ADDR memaddr, | |
844 | ssize_t len, const bfd_byte *myaddr) | |
845 | { | |
8de0566d YQ |
846 | if (mi_suppress_notification.memory) |
847 | return; | |
848 | ||
0e454242 | 849 | SWITCH_THRU_ALL_UIS () |
73ab01a0 PA |
850 | { |
851 | struct mi_interp *mi = as_mi_interp (top_level_interpreter ()); | |
852 | struct ui_out *mi_uiout; | |
853 | struct obj_section *sec; | |
8de0566d | 854 | |
73ab01a0 PA |
855 | if (mi == NULL) |
856 | continue; | |
8de0566d | 857 | |
29f94340 | 858 | mi_uiout = top_level_interpreter ()->interp_ui_out (); |
8de0566d | 859 | |
223ffa71 TT |
860 | target_terminal::scoped_restore_terminal_state term_state; |
861 | target_terminal::ours_for_output (); | |
8de0566d | 862 | |
6cb06a8c | 863 | gdb_printf (mi->event_channel, "memory-changed"); |
8de0566d | 864 | |
992aeed8 | 865 | ui_out_redirect_pop redir (mi_uiout, mi->event_channel); |
8de0566d | 866 | |
112e8700 SM |
867 | mi_uiout->field_fmt ("thread-group", "i%d", inferior->num); |
868 | mi_uiout->field_core_addr ("addr", target_gdbarch (), memaddr); | |
33eca680 | 869 | mi_uiout->field_string ("len", hex_string (len)); |
8de0566d | 870 | |
73ab01a0 PA |
871 | /* Append 'type=code' into notification if MEMADDR falls in the range of |
872 | sections contain code. */ | |
873 | sec = find_pc_section (memaddr); | |
874 | if (sec != NULL && sec->objfile != NULL) | |
875 | { | |
fd361982 | 876 | flagword flags = bfd_section_flags (sec->the_bfd_section); |
5fe96654 | 877 | |
73ab01a0 | 878 | if (flags & SEC_CODE) |
112e8700 | 879 | mi_uiout->field_string ("type", "code"); |
73ab01a0 PA |
880 | } |
881 | ||
73ab01a0 | 882 | gdb_flush (mi->event_channel); |
73ab01a0 | 883 | } |
8de0566d YQ |
884 | } |
885 | ||
77cd03e2 SM |
886 | void |
887 | mi_interp::on_user_selected_context_changed (user_selected_what selection) | |
4034d0ff | 888 | { |
4034d0ff AT |
889 | /* Don't send an event if we're responding to an MI command. */ |
890 | if (mi_suppress_notification.user_selected_context) | |
891 | return; | |
892 | ||
77cd03e2 SM |
893 | thread_info *tp = inferior_ptid != null_ptid ? inferior_thread () : nullptr; |
894 | ui_out *mi_uiout = this->interp_ui_out (); | |
895 | ui_out_redirect_pop redirect_popper (mi_uiout, this->event_channel); | |
4034d0ff | 896 | |
77cd03e2 SM |
897 | target_terminal::scoped_restore_terminal_state term_state; |
898 | target_terminal::ours_for_output (); | |
4034d0ff | 899 | |
77cd03e2 SM |
900 | if (selection & USER_SELECTED_INFERIOR) |
901 | print_selected_inferior (this->cli_uiout); | |
4034d0ff | 902 | |
77cd03e2 SM |
903 | if (tp != NULL |
904 | && (selection & (USER_SELECTED_THREAD | USER_SELECTED_FRAME))) | |
905 | { | |
906 | print_selected_thread_frame (this->cli_uiout, selection); | |
4034d0ff | 907 | |
77cd03e2 SM |
908 | gdb_printf (this->event_channel, "thread-selected,id=\"%d\"", |
909 | tp->global_num); | |
4034d0ff | 910 | |
77cd03e2 | 911 | if (tp->state != THREAD_RUNNING) |
4034d0ff | 912 | { |
77cd03e2 SM |
913 | if (has_stack_frames ()) |
914 | print_stack_frame_to_uiout (mi_uiout, get_selected_frame (NULL), | |
915 | 1, SRC_AND_LOC, 1); | |
4034d0ff | 916 | } |
4034d0ff | 917 | } |
77cd03e2 SM |
918 | |
919 | gdb_flush (this->event_channel); | |
4034d0ff AT |
920 | } |
921 | ||
d6f9b0fb PA |
922 | ui_out * |
923 | mi_interp::interp_ui_out () | |
4801a9a3 | 924 | { |
d6f9b0fb | 925 | return this->mi_uiout; |
4801a9a3 PA |
926 | } |
927 | ||
37ce89eb SS |
928 | /* Do MI-specific logging actions; save raw_stdout, and change all |
929 | the consoles to use the supplied ui-file(s). */ | |
930 | ||
d6f9b0fb | 931 | void |
ca1285d1 AH |
932 | mi_interp::set_logging (ui_file_up logfile, bool logging_redirect, |
933 | bool debug_redirect) | |
37ce89eb | 934 | { |
d6f9b0fb | 935 | struct mi_interp *mi = this; |
37ce89eb | 936 | |
616268b6 | 937 | if (logfile != NULL) |
37ce89eb | 938 | { |
9204d692 | 939 | mi->saved_raw_stdout = mi->raw_stdout; |
616268b6 | 940 | |
2b141965 | 941 | ui_file *logfile_p = logfile.get (); |
016c606c | 942 | mi->logfile_holder = std::move (logfile); |
f3a09c80 AH |
943 | |
944 | /* If something is not being redirected, then a tee containing both the | |
945 | logfile and stdout. */ | |
946 | ui_file *tee = nullptr; | |
ca1285d1 AH |
947 | if (!logging_redirect || !debug_redirect) |
948 | { | |
2b141965 | 949 | tee = new tee_file (mi->raw_stdout, logfile_p); |
016c606c | 950 | mi->stdout_holder.reset (tee); |
ca1285d1 | 951 | } |
f3a09c80 AH |
952 | |
953 | mi->raw_stdout = logging_redirect ? logfile_p : tee; | |
37ce89eb SS |
954 | } |
955 | else | |
956 | { | |
016c606c TT |
957 | mi->logfile_holder.reset (); |
958 | mi->stdout_holder.reset (); | |
9204d692 | 959 | mi->raw_stdout = mi->saved_raw_stdout; |
f3a09c80 | 960 | mi->saved_raw_stdout = nullptr; |
37ce89eb | 961 | } |
f3a09c80 | 962 | |
d7e74731 PA |
963 | mi->out->set_raw (mi->raw_stdout); |
964 | mi->err->set_raw (mi->raw_stdout); | |
965 | mi->log->set_raw (mi->raw_stdout); | |
966 | mi->targ->set_raw (mi->raw_stdout); | |
967 | mi->event_channel->set_raw (mi->raw_stdout); | |
37ce89eb SS |
968 | } |
969 | ||
8322445e PA |
970 | /* Factory for MI interpreters. */ |
971 | ||
972 | static struct interp * | |
973 | mi_interp_factory (const char *name) | |
974 | { | |
d6f9b0fb | 975 | return new mi_interp (name); |
8322445e PA |
976 | } |
977 | ||
6c265988 | 978 | void _initialize_mi_interp (); |
4a8f6654 | 979 | void |
6c265988 | 980 | _initialize_mi_interp () |
4a8f6654 | 981 | { |
2fcf52f0 | 982 | /* The various interpreter levels. */ |
8322445e PA |
983 | interp_factory_register (INTERP_MI2, mi_interp_factory); |
984 | interp_factory_register (INTERP_MI3, mi_interp_factory); | |
9db0d853 | 985 | interp_factory_register (INTERP_MI4, mi_interp_factory); |
8322445e | 986 | interp_factory_register (INTERP_MI, mi_interp_factory); |
73ab01a0 | 987 | |
c90e7d63 SM |
988 | gdb::observers::breakpoint_modified.attach (mi_breakpoint_modified, |
989 | "mi-interp"); | |
990 | gdb::observers::command_param_changed.attach (mi_command_param_changed, | |
991 | "mi-interp"); | |
992 | gdb::observers::memory_changed.attach (mi_memory_changed, "mi-interp"); | |
4a8f6654 | 993 | } |