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