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