X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fmi%2Fmi-interp.c;h=72d63d0a05f44a2d39fc99c5320a2cbb7c1f004f;hb=0e454242cc1527e49ad0ea795614ac94a083b68a;hp=99ce385169cc659adbe671643fcc4e3738ab2eb4;hpb=492d29ea1c9a8b2c7d5193908119a4e27c045687;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c index 99ce385169..72d63d0a05 100644 --- a/gdb/mi/mi-interp.c +++ b/gdb/mi/mi-interp.c @@ -1,6 +1,6 @@ /* MI Interpreter Definitions and Commands for GDB, the GNU debugger. - Copyright (C) 2002-2015 Free Software Foundation, Inc. + Copyright (C) 2002-2016 Free Software Foundation, Inc. This file is part of GDB. @@ -37,13 +37,14 @@ #include "objfiles.h" #include "tracepoint.h" #include "cli-out.h" +#include "thread-fsm.h" +#include "cli/cli-interp.h" /* These are the interpreter setup, etc. functions for the MI interpreter. */ static void mi_execute_command_wrapper (const char *cmd); static void mi_execute_command_input_handler (char *cmd); -static void mi_command_loop (void *data); /* These are hooks that we put in place while doing interpreter_exec so we can report interesting things that happened "behind the MI's @@ -64,7 +65,8 @@ static void mi_on_no_history (void); static void mi_new_thread (struct thread_info *t); static void mi_thread_exit (struct thread_info *t, int silent); -static void mi_record_changed (struct inferior*, int); +static void mi_record_changed (struct inferior*, int, const char *, + const char *); static void mi_inferior_added (struct inferior *inf); static void mi_inferior_appeared (struct inferior *inf); static void mi_inferior_exit (struct inferior *inf); @@ -87,6 +89,29 @@ static void mi_on_sync_execution_done (void); static int report_initial_inferior (struct inferior *inf, void *closure); +/* Display the MI prompt. */ + +static void +display_mi_prompt (struct mi_interp *mi) +{ + struct ui *ui = current_ui; + + fputs_unfiltered ("(gdb) \n", mi->raw_stdout); + gdb_flush (mi->raw_stdout); + ui->prompt_state = PROMPTED; +} + +/* Returns the INTERP's data cast as mi_interp if INTERP is an MI, and + returns NULL otherwise. */ + +static struct mi_interp * +as_mi_interp (struct interp *interp) +{ + if (ui_out_is_mi_like_p (interp_ui_out (interp))) + return (struct mi_interp *) interp_data (interp); + return NULL; +} + static void * mi_interpreter_init (struct interp *interp, int top_level) { @@ -94,20 +119,18 @@ mi_interpreter_init (struct interp *interp, int top_level) const char *name; int mi_version; - /* Assign the output channel created at startup to its own global, - so that we can create a console channel that encapsulates and - prefixes all gdb_output-type bits coming from the rest of the - debugger. */ - - raw_stdout = gdb_stdout; + /* Store the current output channel, so that we can create a console + channel that encapsulates and prefixes all gdb_output-type bits + coming from the rest of the debugger. */ + mi->raw_stdout = gdb_stdout; /* Create MI console channels, each with a different prefix so they can be distinguished. */ - mi->out = mi_console_file_new (raw_stdout, "~", '"'); - mi->err = mi_console_file_new (raw_stdout, "&", '"'); + mi->out = mi_console_file_new (mi->raw_stdout, "~", '"'); + mi->err = mi_console_file_new (mi->raw_stdout, "&", '"'); mi->log = mi->err; - mi->targ = mi_console_file_new (raw_stdout, "@", '"'); - mi->event_channel = mi_console_file_new (raw_stdout, "=", 0); + mi->targ = mi_console_file_new (mi->raw_stdout, "@", '"'); + mi->event_channel = mi_console_file_new (mi->raw_stdout, "=", 0); name = interp_name (interp); /* INTERP_MI selects the most recent released version. "mi2" was @@ -126,39 +149,8 @@ mi_interpreter_init (struct interp *interp, int top_level) mi->mi_uiout = mi_out_new (mi_version); mi->cli_uiout = cli_out_new (mi->out); - /* There are installed even if MI is not the top level interpreter. - The callbacks themselves decide whether to be skipped. */ - observer_attach_signal_received (mi_on_signal_received); - observer_attach_end_stepping_range (mi_on_end_stepping_range); - observer_attach_signal_exited (mi_on_signal_exited); - observer_attach_exited (mi_on_exited); - observer_attach_no_history (mi_on_no_history); - if (top_level) { - observer_attach_new_thread (mi_new_thread); - observer_attach_thread_exit (mi_thread_exit); - observer_attach_inferior_added (mi_inferior_added); - observer_attach_inferior_appeared (mi_inferior_appeared); - observer_attach_inferior_exit (mi_inferior_exit); - observer_attach_inferior_removed (mi_inferior_removed); - observer_attach_record_changed (mi_record_changed); - observer_attach_normal_stop (mi_on_normal_stop); - observer_attach_target_resumed (mi_on_resume); - observer_attach_solib_loaded (mi_solib_loaded); - observer_attach_solib_unloaded (mi_solib_unloaded); - observer_attach_about_to_proceed (mi_about_to_proceed); - observer_attach_traceframe_changed (mi_traceframe_changed); - observer_attach_tsv_created (mi_tsv_created); - observer_attach_tsv_deleted (mi_tsv_deleted); - observer_attach_tsv_modified (mi_tsv_modified); - observer_attach_breakpoint_created (mi_breakpoint_created); - observer_attach_breakpoint_deleted (mi_breakpoint_deleted); - observer_attach_breakpoint_modified (mi_breakpoint_modified); - observer_attach_command_param_changed (mi_command_param_changed); - observer_attach_memory_changed (mi_memory_changed); - observer_attach_sync_execution_done (mi_on_sync_execution_done); - /* The initial inferior is created before this function is called, so we need to report it explicitly. Use iteration in case future version of GDB creates more than one inferior @@ -172,24 +164,15 @@ mi_interpreter_init (struct interp *interp, int top_level) static int mi_interpreter_resume (void *data) { - struct mi_interp *mi = data; + struct mi_interp *mi = (struct mi_interp *) data; + struct ui *ui = current_ui; /* As per hack note in mi_interpreter_init, swap in the output channels... */ - gdb_setup_readline (); - - /* These overwrite some of the initialization done in - _intialize_event_loop. */ - call_readline = gdb_readline2; - input_handler = mi_execute_command_input_handler; - async_command_editing_p = 0; - /* FIXME: This is a total hack for now. PB's use of the MI - implicitly relies on a bug in the async support which allows - asynchronous commands to leak through the commmand loop. The bug - involves (but is not limited to) the fact that sync_execution was - erroneously initialized to 0. Duplicate by initializing it thus - here... */ - sync_execution = 0; + gdb_setup_readline (0); + + ui->call_readline = gdb_readline_no_editing_callback; + ui->input_handler = mi_execute_command_input_handler; gdb_stdout = mi->out; /* Route error and log output through the MI. */ @@ -235,7 +218,7 @@ mi_cmd_interpreter_exec (char *command, char **argv, int argc) error (_("-interpreter-exec: " "Usage: -interpreter-exec interp command")); - interp_to_use = interp_lookup (argv[0]); + interp_to_use = interp_lookup (current_ui, argv[0]); if (interp_to_use == NULL) error (_("-interpreter-exec: could not find interpreter \"%s\""), argv[0]); @@ -301,7 +284,9 @@ mi_interp_query_hook (const char *ctlstr, va_list ap) static void mi_execute_command_wrapper (const char *cmd) { - mi_execute_command (cmd, stdin == instream); + struct ui *ui = current_ui; + + mi_execute_command (cmd, ui->instream == ui->stdin_stream); } /* Observer for the synchronous_command_done notification. */ @@ -309,21 +294,16 @@ mi_execute_command_wrapper (const char *cmd) static void mi_on_sync_execution_done (void) { - /* MI generally prints a prompt after a command, indicating it's - ready for further input. However, due to an historical wart, if - MI async, and a (CLI) synchronous command was issued, then we - will print the prompt right after printing "^running", even if we - cannot actually accept any input until the target stops. See - mi_on_resume. However, if the target is async but MI is sync, - then we need to output the MI prompt now, to replicate gdb's - behavior when neither the target nor MI are async. (Note this - observer is only called by the asynchronous target event handling - code.) */ + struct ui *ui = current_ui; + struct mi_interp *mi = as_mi_interp (top_level_interpreter ()); + + if (mi == NULL) + return; + + /* If MI is sync, then output the MI prompt now, indicating we're + ready for further input. */ if (!mi_async_p ()) - { - fputs_unfiltered ("(gdb) \n", raw_stdout); - gdb_flush (raw_stdout); - } + display_mi_prompt (mi); } /* mi_execute_command_wrapper wrapper suitable for INPUT_HANDLER. */ @@ -331,185 +311,254 @@ mi_on_sync_execution_done (void) static void mi_execute_command_input_handler (char *cmd) { + struct mi_interp *mi = as_mi_interp (top_level_interpreter ()); + struct ui *ui = current_ui; + + ui->prompt_state = PROMPT_NEEDED; + mi_execute_command_wrapper (cmd); - /* MI generally prints a prompt after a command, indicating it's - ready for further input. However, due to an historical wart, if - MI is async, and a synchronous command was issued, then we will - print the prompt right after printing "^running", even if we - cannot actually accept any input until the target stops. See - mi_on_resume. - - If MI is not async, then we print the prompt when the command - finishes. If the target is sync, that means output the prompt - now, as in that case executing a command doesn't return until the - command is done. However, if the target is async, we go back to - the event loop and output the prompt in the - 'synchronous_command_done' observer. */ - if (!target_is_async_p () || !sync_execution) - { - fputs_unfiltered ("(gdb) \n", raw_stdout); - gdb_flush (raw_stdout); - } + /* Print a prompt, indicating we're ready for further input, unless + we just started a synchronous command. In that case, we're about + to go back to the event loop and will output the prompt in the + 'synchronous_command_done' observer when the target next + stops. */ + if (ui->prompt_state == PROMPT_NEEDED) + display_mi_prompt (mi); } static void -mi_command_loop (void *data) +mi_interpreter_pre_command_loop (struct interp *self) { + struct mi_interp *mi = (struct mi_interp *) interp_data (self); + /* Turn off 8 bit strings in quoted output. Any character with the high bit set is printed using C's octal format. */ sevenbit_strings = 1; /* Tell the world that we're alive. */ - fputs_unfiltered ("(gdb) \n", raw_stdout); - gdb_flush (raw_stdout); - - start_event_loop (); + display_mi_prompt (mi); } static void mi_new_thread (struct thread_info *t) { - struct mi_interp *mi = top_level_interpreter_data (); struct inferior *inf = find_inferior_ptid (t->ptid); gdb_assert (inf); - fprintf_unfiltered (mi->event_channel, - "thread-created,id=\"%d\",group-id=\"i%d\"", - t->num, inf->num); - gdb_flush (mi->event_channel); + SWITCH_THRU_ALL_UIS () + { + struct mi_interp *mi = as_mi_interp (top_level_interpreter ()); + struct cleanup *old_chain; + + if (mi == NULL) + continue; + + old_chain = make_cleanup_restore_target_terminal (); + target_terminal_ours_for_output (); + + fprintf_unfiltered (mi->event_channel, + "thread-created,id=\"%d\",group-id=\"i%d\"", + t->global_num, inf->num); + gdb_flush (mi->event_channel); + + do_cleanups (old_chain); + } } static void mi_thread_exit (struct thread_info *t, int silent) { - struct mi_interp *mi; - struct inferior *inf; - struct cleanup *old_chain; - if (silent) return; - inf = find_inferior_ptid (t->ptid); + SWITCH_THRU_ALL_UIS () + { + struct mi_interp *mi = as_mi_interp (top_level_interpreter ()); + struct cleanup *old_chain; - mi = top_level_interpreter_data (); - old_chain = make_cleanup_restore_target_terminal (); - target_terminal_ours (); - fprintf_unfiltered (mi->event_channel, - "thread-exited,id=\"%d\",group-id=\"i%d\"", - t->num, inf->num); - gdb_flush (mi->event_channel); + if (mi == NULL) + continue; - do_cleanups (old_chain); + old_chain = make_cleanup_restore_target_terminal (); + target_terminal_ours_for_output (); + fprintf_unfiltered (mi->event_channel, + "thread-exited,id=\"%d\",group-id=\"i%d\"", + t->global_num, t->inf->num); + gdb_flush (mi->event_channel); + + do_cleanups (old_chain); + } } /* Emit notification on changing the state of record. */ static void -mi_record_changed (struct inferior *inferior, int started) +mi_record_changed (struct inferior *inferior, int started, const char *method, + const char *format) { - struct mi_interp *mi = top_level_interpreter_data (); + SWITCH_THRU_ALL_UIS () + { + struct mi_interp *mi = as_mi_interp (top_level_interpreter ()); + struct cleanup *old_chain; - fprintf_unfiltered (mi->event_channel, "record-%s,thread-group=\"i%d\"", - started ? "started" : "stopped", inferior->num); + if (mi == NULL) + continue; - gdb_flush (mi->event_channel); + old_chain = make_cleanup_restore_target_terminal (); + target_terminal_ours_for_output (); + + if (started) + { + if (format != NULL) + { + fprintf_unfiltered (mi->event_channel, + "record-started,thread-group=\"i%d\"," + "method=\"%s\",format=\"%s\"", + inferior->num, method, format); + } + else + { + fprintf_unfiltered (mi->event_channel, + "record-started,thread-group=\"i%d\"," + "method=\"%s\"", + inferior->num, method); + } + } + else + { + fprintf_unfiltered (mi->event_channel, + "record-stopped,thread-group=\"i%d\"", + inferior->num); + } + + gdb_flush (mi->event_channel); + + do_cleanups (old_chain); + } } static void mi_inferior_added (struct inferior *inf) { - struct mi_interp *mi = top_level_interpreter_data (); + SWITCH_THRU_ALL_UIS () + { + struct interp *interp; + struct mi_interp *mi; + struct cleanup *old_chain; - target_terminal_ours (); - fprintf_unfiltered (mi->event_channel, - "thread-group-added,id=\"i%d\"", - inf->num); - gdb_flush (mi->event_channel); + /* We'll be called once for the initial inferior, before the top + level interpreter is set. */ + interp = top_level_interpreter (); + if (interp == NULL) + continue; + + mi = as_mi_interp (interp); + if (mi == NULL) + continue; + + old_chain = make_cleanup_restore_target_terminal (); + target_terminal_ours_for_output (); + + fprintf_unfiltered (mi->event_channel, + "thread-group-added,id=\"i%d\"", + inf->num); + gdb_flush (mi->event_channel); + + do_cleanups (old_chain); + } } static void mi_inferior_appeared (struct inferior *inf) { - struct mi_interp *mi = top_level_interpreter_data (); + SWITCH_THRU_ALL_UIS () + { + struct mi_interp *mi = as_mi_interp (top_level_interpreter ()); + struct cleanup *old_chain; - target_terminal_ours (); - fprintf_unfiltered (mi->event_channel, - "thread-group-started,id=\"i%d\",pid=\"%d\"", - inf->num, inf->pid); - gdb_flush (mi->event_channel); + if (mi == NULL) + continue; + + old_chain = make_cleanup_restore_target_terminal (); + target_terminal_ours_for_output (); + + fprintf_unfiltered (mi->event_channel, + "thread-group-started,id=\"i%d\",pid=\"%d\"", + inf->num, inf->pid); + gdb_flush (mi->event_channel); + do_cleanups (old_chain); + } } static void mi_inferior_exit (struct inferior *inf) { - struct mi_interp *mi = top_level_interpreter_data (); + SWITCH_THRU_ALL_UIS () + { + struct mi_interp *mi = as_mi_interp (top_level_interpreter ()); + struct cleanup *old_chain; - target_terminal_ours (); - if (inf->has_exit_code) - fprintf_unfiltered (mi->event_channel, - "thread-group-exited,id=\"i%d\",exit-code=\"%s\"", - inf->num, int_string (inf->exit_code, 8, 0, 0, 1)); - else - fprintf_unfiltered (mi->event_channel, - "thread-group-exited,id=\"i%d\"", inf->num); + if (mi == NULL) + continue; + + old_chain = make_cleanup_restore_target_terminal (); + target_terminal_ours_for_output (); - gdb_flush (mi->event_channel); + if (inf->has_exit_code) + fprintf_unfiltered (mi->event_channel, + "thread-group-exited,id=\"i%d\",exit-code=\"%s\"", + inf->num, int_string (inf->exit_code, 8, 0, 0, 1)); + else + fprintf_unfiltered (mi->event_channel, + "thread-group-exited,id=\"i%d\"", inf->num); + + gdb_flush (mi->event_channel); + do_cleanups (old_chain); + } } static void mi_inferior_removed (struct inferior *inf) { - struct mi_interp *mi = top_level_interpreter_data (); + SWITCH_THRU_ALL_UIS () + { + struct mi_interp *mi = as_mi_interp (top_level_interpreter ()); + struct cleanup *old_chain; - target_terminal_ours (); - fprintf_unfiltered (mi->event_channel, - "thread-group-removed,id=\"i%d\"", - inf->num); - gdb_flush (mi->event_channel); -} + if (mi == NULL) + continue; -/* Cleanup that restores a previous current uiout. */ + old_chain = make_cleanup_restore_target_terminal (); + target_terminal_ours_for_output (); -static void -restore_current_uiout_cleanup (void *arg) -{ - struct ui_out *saved_uiout = arg; + fprintf_unfiltered (mi->event_channel, + "thread-group-removed,id=\"i%d\"", + inf->num); + gdb_flush (mi->event_channel); - current_uiout = saved_uiout; + do_cleanups (old_chain); + } } /* Return the MI interpreter, if it is active -- either because it's the top-level interpreter or the interpreter executing the current command. Returns NULL if the MI interpreter is not being used. */ -static struct interp * -find_mi_interpreter (void) +static struct mi_interp * +find_mi_interp (void) { - struct interp *interp; - - interp = top_level_interpreter (); - if (ui_out_is_mi_like_p (interp_ui_out (interp))) - return interp; - - interp = command_interp (); - if (ui_out_is_mi_like_p (interp_ui_out (interp))) - return interp; - - return NULL; -} + struct mi_interp *mi; -/* Return the MI_INTERP structure of the active MI interpreter. - Returns NULL if MI is not active. */ + mi = as_mi_interp (top_level_interpreter ()); + if (mi != NULL) + return mi; -static struct mi_interp * -mi_interp_data (void) -{ - struct interp *interp = find_mi_interpreter (); + mi = as_mi_interp (command_interp ()); + if (mi != NULL) + return mi; - if (interp != NULL) - return interp_data (interp); return NULL; } @@ -522,13 +571,16 @@ mi_interp_data (void) static void mi_on_signal_received (enum gdb_signal siggnal) { - struct mi_interp *mi = mi_interp_data (); + SWITCH_THRU_ALL_UIS () + { + struct mi_interp *mi = find_mi_interp (); - if (mi == NULL) - return; + if (mi == NULL) + continue; - print_signal_received_reason (mi->mi_uiout, siggnal); - print_signal_received_reason (mi->cli_uiout, siggnal); + print_signal_received_reason (mi->mi_uiout, siggnal); + print_signal_received_reason (mi->cli_uiout, siggnal); + } } /* Observer for the end_stepping_range notification. */ @@ -536,13 +588,16 @@ mi_on_signal_received (enum gdb_signal siggnal) static void mi_on_end_stepping_range (void) { - struct mi_interp *mi = mi_interp_data (); + SWITCH_THRU_ALL_UIS () + { + struct mi_interp *mi = find_mi_interp (); - if (mi == NULL) - return; + if (mi == NULL) + continue; - print_end_stepping_range_reason (mi->mi_uiout); - print_end_stepping_range_reason (mi->cli_uiout); + print_end_stepping_range_reason (mi->mi_uiout); + print_end_stepping_range_reason (mi->cli_uiout); + } } /* Observer for the signal_exited notification. */ @@ -550,13 +605,16 @@ mi_on_end_stepping_range (void) static void mi_on_signal_exited (enum gdb_signal siggnal) { - struct mi_interp *mi = mi_interp_data (); + SWITCH_THRU_ALL_UIS () + { + struct mi_interp *mi = find_mi_interp (); - if (mi == NULL) - return; + if (mi == NULL) + continue; - print_signal_exited_reason (mi->mi_uiout, siggnal); - print_signal_exited_reason (mi->cli_uiout, siggnal); + print_signal_exited_reason (mi->mi_uiout, siggnal); + print_signal_exited_reason (mi->cli_uiout, siggnal); + } } /* Observer for the exited notification. */ @@ -564,13 +622,16 @@ mi_on_signal_exited (enum gdb_signal siggnal) static void mi_on_exited (int exitstatus) { - struct mi_interp *mi = mi_interp_data (); + SWITCH_THRU_ALL_UIS () + { + struct mi_interp *mi = find_mi_interp (); - if (mi == NULL) - return; + if (mi == NULL) + continue; - print_exited_reason (mi->mi_uiout, exitstatus); - print_exited_reason (mi->cli_uiout, exitstatus); + print_exited_reason (mi->mi_uiout, exitstatus); + print_exited_reason (mi->cli_uiout, exitstatus); + } } /* Observer for the no_history notification. */ @@ -578,103 +639,57 @@ mi_on_exited (int exitstatus) static void mi_on_no_history (void) { - struct mi_interp *mi = mi_interp_data (); + SWITCH_THRU_ALL_UIS () + { + struct mi_interp *mi = find_mi_interp (); - if (mi == NULL) - return; + if (mi == NULL) + continue; - print_no_history_reason (mi->mi_uiout); - print_no_history_reason (mi->cli_uiout); + print_no_history_reason (mi->mi_uiout); + print_no_history_reason (mi->cli_uiout); + } } static void -mi_on_normal_stop (struct bpstats *bs, int print_frame) +mi_on_normal_stop_1 (struct bpstats *bs, int print_frame) { /* Since this can be called when CLI command is executing, using cli interpreter, be sure to use MI uiout for output, not the current one. */ struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ()); + struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data (); if (print_frame) { + struct thread_info *tp; int core; + struct interp *console_interp; - if (current_uiout != mi_uiout) - { - /* The normal_stop function has printed frame information - into CLI uiout, or some other non-MI uiout. There's no - way we can extract proper fields from random uiout - object, so we print the frame again. In practice, this - can only happen when running a CLI command in MI. */ - struct ui_out *saved_uiout = current_uiout; - struct target_waitstatus last; - ptid_t last_ptid; - - current_uiout = mi_uiout; - - get_last_target_status (&last_ptid, &last); - print_stop_event (&last); + tp = inferior_thread (); - current_uiout = saved_uiout; - } - /* Otherwise, frame information has already been printed by - normal_stop. */ - else + if (tp->thread_fsm != NULL + && thread_fsm_finished_p (tp->thread_fsm)) { - /* Breakpoint hits should always be mirrored to the console. - Deciding what to mirror to the console wrt to breakpoints - and random stops gets messy real fast. E.g., say "s" - trips on a breakpoint. We'd clearly want to mirror the - event to the console in this case. But what about more - complicated cases like "s&; thread n; s&", and one of - those steps spawning a new thread, and that thread - hitting a breakpoint? It's impossible in general to - track whether the thread had any relation to the commands - that had been executed. So we just simplify and always - mirror breakpoints and random events to the console. - - Also, CLI execution commands (-interpreter-exec console - "next", for example) in async mode have the opposite - issue as described in the "then" branch above -- - normal_stop has already printed frame information to MI - uiout, but nothing has printed the same information to - the CLI channel. We should print the source line to the - console when stepping or other similar commands, iff the - step was started by a console command (but not if it was - started with -exec-step or similar). */ - struct thread_info *tp = inferior_thread (); - - if ((!tp->control.stop_step - && !tp->control.proceed_to_finish) - || (tp->control.command_interp != NULL - && tp->control.command_interp != top_level_interpreter ())) - { - struct mi_interp *mi = top_level_interpreter_data (); - struct target_waitstatus last; - ptid_t last_ptid; - struct cleanup *old_chain; - - /* Set the current uiout to CLI uiout temporarily. */ - old_chain = make_cleanup (restore_current_uiout_cleanup, - current_uiout); - current_uiout = mi->cli_uiout; + enum async_reply_reason reason; - get_last_target_status (&last_ptid, &last); - print_stop_event (&last); - - do_cleanups (old_chain); - } + reason = thread_fsm_async_reply_reason (tp->thread_fsm); + ui_out_field_string (mi_uiout, "reason", + async_reason_lookup (reason)); } + print_stop_event (mi_uiout); - ui_out_field_int (mi_uiout, "thread-id", - pid_to_thread_id (inferior_ptid)); + console_interp = interp_lookup (current_ui, INTERP_CONSOLE); + if (should_print_stop_to_console (console_interp, tp)) + print_stop_event (mi->cli_uiout); + + ui_out_field_int (mi_uiout, "thread-id", tp->global_num); if (non_stop) { struct cleanup *back_to = make_cleanup_ui_out_list_begin_end (mi_uiout, "stopped-threads"); - ui_out_field_int (mi_uiout, NULL, - pid_to_thread_id (inferior_ptid)); + ui_out_field_int (mi_uiout, NULL, tp->global_num); do_cleanups (back_to); } else @@ -685,12 +700,24 @@ mi_on_normal_stop (struct bpstats *bs, int print_frame) ui_out_field_int (mi_uiout, "core", core); } - fputs_unfiltered ("*stopped", raw_stdout); - mi_out_put (mi_uiout, raw_stdout); + fputs_unfiltered ("*stopped", mi->raw_stdout); + mi_out_put (mi_uiout, mi->raw_stdout); mi_out_rewind (mi_uiout); - mi_print_timing_maybe (); - fputs_unfiltered ("\n", raw_stdout); - gdb_flush (raw_stdout); + mi_print_timing_maybe (mi->raw_stdout); + fputs_unfiltered ("\n", mi->raw_stdout); + gdb_flush (mi->raw_stdout); +} + +static void +mi_on_normal_stop (struct bpstats *bs, int print_frame) +{ + SWITCH_THRU_ALL_UIS () + { + if (as_mi_interp (top_level_interpreter ()) == NULL) + continue; + + mi_on_normal_stop_1 (bs, print_frame); + } } static void @@ -717,6 +744,7 @@ struct mi_suppress_notification mi_suppress_notification = 0, 0, 0, + 0, }; /* Emit notification on changing a traceframe. */ @@ -724,21 +752,31 @@ struct mi_suppress_notification mi_suppress_notification = static void mi_traceframe_changed (int tfnum, int tpnum) { - struct mi_interp *mi = top_level_interpreter_data (); - if (mi_suppress_notification.traceframe) return; - target_terminal_ours (); + SWITCH_THRU_ALL_UIS () + { + struct mi_interp *mi = as_mi_interp (top_level_interpreter ()); + struct cleanup *old_chain; - if (tfnum >= 0) - fprintf_unfiltered (mi->event_channel, "traceframe-changed," - "num=\"%d\",tracepoint=\"%d\"\n", - tfnum, tpnum); - else - fprintf_unfiltered (mi->event_channel, "traceframe-changed,end"); + if (mi == NULL) + continue; - gdb_flush (mi->event_channel); + old_chain = make_cleanup_restore_target_terminal (); + target_terminal_ours_for_output (); + + if (tfnum >= 0) + fprintf_unfiltered (mi->event_channel, "traceframe-changed," + "num=\"%d\",tracepoint=\"%d\"\n", + tfnum, tpnum); + else + fprintf_unfiltered (mi->event_channel, "traceframe-changed,end"); + + gdb_flush (mi->event_channel); + + do_cleanups (old_chain); + } } /* Emit notification on creating a trace state variable. */ @@ -746,15 +784,25 @@ mi_traceframe_changed (int tfnum, int tpnum) static void mi_tsv_created (const struct trace_state_variable *tsv) { - struct mi_interp *mi = top_level_interpreter_data (); + SWITCH_THRU_ALL_UIS () + { + struct mi_interp *mi = as_mi_interp (top_level_interpreter ()); + struct cleanup *old_chain; - target_terminal_ours (); + if (mi == NULL) + continue; - fprintf_unfiltered (mi->event_channel, "tsv-created," - "name=\"%s\",initial=\"%s\"\n", - tsv->name, plongest (tsv->initial_value)); + old_chain = make_cleanup_restore_target_terminal (); + target_terminal_ours_for_output (); - gdb_flush (mi->event_channel); + fprintf_unfiltered (mi->event_channel, "tsv-created," + "name=\"%s\",initial=\"%s\"\n", + tsv->name, plongest (tsv->initial_value)); + + gdb_flush (mi->event_channel); + + do_cleanups (old_chain); + } } /* Emit notification on deleting a trace state variable. */ @@ -762,17 +810,27 @@ mi_tsv_created (const struct trace_state_variable *tsv) static void mi_tsv_deleted (const struct trace_state_variable *tsv) { - struct mi_interp *mi = top_level_interpreter_data (); + SWITCH_THRU_ALL_UIS () + { + struct mi_interp *mi = as_mi_interp (top_level_interpreter ()); + struct cleanup *old_chain; - target_terminal_ours (); + if (mi == NULL) + continue; - if (tsv != NULL) - fprintf_unfiltered (mi->event_channel, "tsv-deleted," - "name=\"%s\"\n", tsv->name); - else - fprintf_unfiltered (mi->event_channel, "tsv-deleted\n"); + old_chain = make_cleanup_restore_target_terminal (); + target_terminal_ours_for_output (); - gdb_flush (mi->event_channel); + if (tsv != NULL) + fprintf_unfiltered (mi->event_channel, "tsv-deleted," + "name=\"%s\"\n", tsv->name); + else + fprintf_unfiltered (mi->event_channel, "tsv-deleted\n"); + + gdb_flush (mi->event_channel); + + do_cleanups (old_chain); + } } /* Emit notification on modifying a trace state variable. */ @@ -780,25 +838,37 @@ mi_tsv_deleted (const struct trace_state_variable *tsv) static void mi_tsv_modified (const struct trace_state_variable *tsv) { - struct mi_interp *mi = top_level_interpreter_data (); - struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ()); + SWITCH_THRU_ALL_UIS () + { + struct mi_interp *mi = as_mi_interp (top_level_interpreter ()); + struct ui_out *mi_uiout; + struct cleanup *old_chain; - target_terminal_ours (); + if (mi == NULL) + continue; - fprintf_unfiltered (mi->event_channel, - "tsv-modified"); + mi_uiout = interp_ui_out (top_level_interpreter ()); - ui_out_redirect (mi_uiout, mi->event_channel); + old_chain = make_cleanup_restore_target_terminal (); + target_terminal_ours_for_output (); - ui_out_field_string (mi_uiout, "name", tsv->name); - ui_out_field_string (mi_uiout, "initial", - plongest (tsv->initial_value)); - if (tsv->value_known) - ui_out_field_string (mi_uiout, "current", plongest (tsv->value)); + fprintf_unfiltered (mi->event_channel, + "tsv-modified"); - ui_out_redirect (mi_uiout, NULL); + ui_out_redirect (mi_uiout, mi->event_channel); - gdb_flush (mi->event_channel); + ui_out_field_string (mi_uiout, "name", tsv->name); + ui_out_field_string (mi_uiout, "initial", + plongest (tsv->initial_value)); + if (tsv->value_known) + ui_out_field_string (mi_uiout, "current", plongest (tsv->value)); + + ui_out_redirect (mi_uiout, NULL); + + gdb_flush (mi->event_channel); + + do_cleanups (old_chain); + } } /* Emit notification about a created breakpoint. */ @@ -806,38 +876,51 @@ mi_tsv_modified (const struct trace_state_variable *tsv) static void mi_breakpoint_created (struct breakpoint *b) { - struct mi_interp *mi = top_level_interpreter_data (); - struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ()); - if (mi_suppress_notification.breakpoint) return; if (b->number <= 0) return; - target_terminal_ours (); - fprintf_unfiltered (mi->event_channel, - "breakpoint-created"); - /* We want the output from gdb_breakpoint_query to go to - mi->event_channel. One approach would be to just call - gdb_breakpoint_query, and then use mi_out_put to send the current - content of mi_outout into mi->event_channel. However, that will - break if anything is output to mi_uiout prior to calling the - breakpoint_created notifications. So, we use - ui_out_redirect. */ - ui_out_redirect (mi_uiout, mi->event_channel); - TRY + SWITCH_THRU_ALL_UIS () { - gdb_breakpoint_query (mi_uiout, b->number, NULL); - } - CATCH (e, RETURN_MASK_ERROR) - { - } - END_CATCH + struct mi_interp *mi = as_mi_interp (top_level_interpreter ()); + struct ui_out *mi_uiout; + struct cleanup *old_chain; + + if (mi == NULL) + continue; + + mi_uiout = interp_ui_out (top_level_interpreter ()); + + old_chain = make_cleanup_restore_target_terminal (); + target_terminal_ours_for_output (); + + fprintf_unfiltered (mi->event_channel, + "breakpoint-created"); + /* We want the output from gdb_breakpoint_query to go to + mi->event_channel. One approach would be to just call + gdb_breakpoint_query, and then use mi_out_put to send the current + content of mi_outout into mi->event_channel. However, that will + break if anything is output to mi_uiout prior to calling the + breakpoint_created notifications. So, we use + ui_out_redirect. */ + ui_out_redirect (mi_uiout, mi->event_channel); + TRY + { + gdb_breakpoint_query (mi_uiout, b->number, NULL); + } + CATCH (e, RETURN_MASK_ERROR) + { + } + END_CATCH - ui_out_redirect (mi_uiout, NULL); + ui_out_redirect (mi_uiout, NULL); - gdb_flush (mi->event_channel); + gdb_flush (mi->event_channel); + + do_cleanups (old_chain); + } } /* Emit notification about deleted breakpoint. */ @@ -845,20 +928,30 @@ mi_breakpoint_created (struct breakpoint *b) static void mi_breakpoint_deleted (struct breakpoint *b) { - struct mi_interp *mi = top_level_interpreter_data (); - if (mi_suppress_notification.breakpoint) return; if (b->number <= 0) return; - target_terminal_ours (); + SWITCH_THRU_ALL_UIS () + { + struct mi_interp *mi = as_mi_interp (top_level_interpreter ()); + struct cleanup *old_chain; - fprintf_unfiltered (mi->event_channel, "breakpoint-deleted,id=\"%d\"", - b->number); + if (mi == NULL) + continue; - gdb_flush (mi->event_channel); + old_chain = make_cleanup_restore_target_terminal (); + target_terminal_ours_for_output (); + + fprintf_unfiltered (mi->event_channel, "breakpoint-deleted,id=\"%d\"", + b->number); + + gdb_flush (mi->event_channel); + + do_cleanups (old_chain); + } } /* Emit notification about modified breakpoint. */ @@ -866,49 +959,66 @@ mi_breakpoint_deleted (struct breakpoint *b) static void mi_breakpoint_modified (struct breakpoint *b) { - struct mi_interp *mi = top_level_interpreter_data (); - struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ()); - if (mi_suppress_notification.breakpoint) return; if (b->number <= 0) return; - target_terminal_ours (); - fprintf_unfiltered (mi->event_channel, - "breakpoint-modified"); - /* We want the output from gdb_breakpoint_query to go to - mi->event_channel. One approach would be to just call - gdb_breakpoint_query, and then use mi_out_put to send the current - content of mi_outout into mi->event_channel. However, that will - break if anything is output to mi_uiout prior to calling the - breakpoint_created notifications. So, we use - ui_out_redirect. */ - ui_out_redirect (mi_uiout, mi->event_channel); - TRY - { - gdb_breakpoint_query (mi_uiout, b->number, NULL); - } - CATCH (e, RETURN_MASK_ERROR) + SWITCH_THRU_ALL_UIS () { - } - END_CATCH + struct mi_interp *mi = as_mi_interp (top_level_interpreter ()); + struct cleanup *old_chain; + + if (mi == NULL) + continue; + + old_chain = make_cleanup_restore_target_terminal (); + target_terminal_ours_for_output (); + fprintf_unfiltered (mi->event_channel, + "breakpoint-modified"); + /* We want the output from gdb_breakpoint_query to go to + mi->event_channel. One approach would be to just call + gdb_breakpoint_query, and then use mi_out_put to send the current + content of mi_outout into mi->event_channel. However, that will + break if anything is output to mi_uiout prior to calling the + breakpoint_created notifications. So, we use + ui_out_redirect. */ + ui_out_redirect (mi->mi_uiout, mi->event_channel); + TRY + { + gdb_breakpoint_query (mi->mi_uiout, b->number, NULL); + } + CATCH (e, RETURN_MASK_ERROR) + { + } + END_CATCH - ui_out_redirect (mi_uiout, NULL); + ui_out_redirect (mi->mi_uiout, NULL); - gdb_flush (mi->event_channel); + gdb_flush (mi->event_channel); + + do_cleanups (old_chain); + } } static int mi_output_running_pid (struct thread_info *info, void *arg) { - ptid_t *ptid = arg; + ptid_t *ptid = (ptid_t *) arg; + + SWITCH_THRU_ALL_UIS () + { + struct mi_interp *mi = as_mi_interp (top_level_interpreter ()); - if (ptid_get_pid (*ptid) == ptid_get_pid (info->ptid)) - fprintf_unfiltered (raw_stdout, - "*running,thread-id=\"%d\"\n", - info->num); + if (mi == NULL) + continue; + + if (ptid_get_pid (*ptid) == ptid_get_pid (info->ptid)) + fprintf_unfiltered (mi->raw_stdout, + "*running,thread-id=\"%d\"\n", + info->global_num); + } return 0; } @@ -918,7 +1028,7 @@ mi_inferior_count (struct inferior *inf, void *arg) { if (inf->pid != 0) { - int *count_p = arg; + int *count_p = (int *) arg; (*count_p)++; } @@ -926,19 +1036,8 @@ mi_inferior_count (struct inferior *inf, void *arg) } static void -mi_on_resume (ptid_t ptid) +mi_on_resume_1 (struct mi_interp *mi, ptid_t ptid) { - struct thread_info *tp = NULL; - - if (ptid_equal (ptid, minus_one_ptid) || ptid_is_pid (ptid)) - tp = inferior_thread (); - else - tp = find_thread_ptid (ptid); - - /* Suppress output while calling an inferior function. */ - if (tp->control.in_infcall) - return; - /* To cater for older frontends, emit ^running, but do it only once per each command. We do it here, since at this point we know that the target was successfully resumed, and in non-async mode, @@ -949,12 +1048,12 @@ mi_on_resume (ptid_t ptid) In future (MI3), we'll be outputting "^done" here. */ if (!running_result_record_printed && mi_proceeded) { - fprintf_unfiltered (raw_stdout, "%s^running\n", + fprintf_unfiltered (mi->raw_stdout, "%s^running\n", current_token ? current_token : ""); } if (ptid_get_pid (ptid) == -1) - fprintf_unfiltered (raw_stdout, "*running,thread-id=\"all\"\n"); + fprintf_unfiltered (mi->raw_stdout, "*running,thread-id=\"all\"\n"); else if (ptid_is_pid (ptid)) { int count = 0; @@ -965,7 +1064,7 @@ mi_on_resume (ptid_t ptid) iterate_over_inferiors (mi_inferior_count, &count); if (count == 1) - fprintf_unfiltered (raw_stdout, "*running,thread-id=\"all\"\n"); + fprintf_unfiltered (mi->raw_stdout, "*running,thread-id=\"all\"\n"); else iterate_over_threads (mi_output_running_pid, &ptid); } @@ -974,72 +1073,128 @@ mi_on_resume (ptid_t ptid) struct thread_info *ti = find_thread_ptid (ptid); gdb_assert (ti); - fprintf_unfiltered (raw_stdout, "*running,thread-id=\"%d\"\n", ti->num); + fprintf_unfiltered (mi->raw_stdout, "*running,thread-id=\"%d\"\n", + ti->global_num); } if (!running_result_record_printed && mi_proceeded) { running_result_record_printed = 1; - /* This is what gdb used to do historically -- printing prompt even if - it cannot actually accept any input. This will be surely removed - for MI3, and may be removed even earlier. SYNC_EXECUTION is - checked here because we only need to emit a prompt if a - synchronous command was issued when the target is async. */ - if (!target_is_async_p () || sync_execution) - fputs_unfiltered ("(gdb) \n", raw_stdout); + /* This is what gdb used to do historically -- printing prompt + even if it cannot actually accept any input. This will be + surely removed for MI3, and may be removed even earlier. */ + if (current_ui->prompt_state == PROMPT_BLOCKED) + fputs_unfiltered ("(gdb) \n", mi->raw_stdout); } - gdb_flush (raw_stdout); + gdb_flush (mi->raw_stdout); } static void -mi_solib_loaded (struct so_list *solib) +mi_on_resume (ptid_t ptid) { - struct mi_interp *mi = top_level_interpreter_data (); - struct ui_out *uiout = interp_ui_out (top_level_interpreter ()); - - target_terminal_ours (); + struct thread_info *tp = NULL; - fprintf_unfiltered (mi->event_channel, "library-loaded"); + if (ptid_equal (ptid, minus_one_ptid) || ptid_is_pid (ptid)) + tp = inferior_thread (); + else + tp = find_thread_ptid (ptid); - ui_out_redirect (uiout, mi->event_channel); + /* Suppress output while calling an inferior function. */ + if (tp->control.in_infcall) + return; - ui_out_field_string (uiout, "id", solib->so_original_name); - ui_out_field_string (uiout, "target-name", solib->so_original_name); - ui_out_field_string (uiout, "host-name", solib->so_name); - ui_out_field_int (uiout, "symbols-loaded", solib->symbols_loaded); - if (!gdbarch_has_global_solist (target_gdbarch ())) + SWITCH_THRU_ALL_UIS () { - ui_out_field_fmt (uiout, "thread-group", "i%d", current_inferior ()->num); + struct mi_interp *mi = as_mi_interp (top_level_interpreter ()); + struct cleanup *old_chain; + + if (mi == NULL) + continue; + + old_chain = make_cleanup_restore_target_terminal (); + target_terminal_ours_for_output (); + + mi_on_resume_1 (mi, ptid); + + do_cleanups (old_chain); } +} - ui_out_redirect (uiout, NULL); +static void +mi_solib_loaded (struct so_list *solib) +{ + SWITCH_THRU_ALL_UIS () + { + struct mi_interp *mi = as_mi_interp (top_level_interpreter ()); + struct ui_out *uiout; + struct cleanup *old_chain; - gdb_flush (mi->event_channel); + if (mi == NULL) + continue; + + uiout = interp_ui_out (top_level_interpreter ()); + + old_chain = make_cleanup_restore_target_terminal (); + target_terminal_ours_for_output (); + + fprintf_unfiltered (mi->event_channel, "library-loaded"); + + ui_out_redirect (uiout, mi->event_channel); + + ui_out_field_string (uiout, "id", solib->so_original_name); + ui_out_field_string (uiout, "target-name", solib->so_original_name); + ui_out_field_string (uiout, "host-name", solib->so_name); + ui_out_field_int (uiout, "symbols-loaded", solib->symbols_loaded); + if (!gdbarch_has_global_solist (target_gdbarch ())) + { + ui_out_field_fmt (uiout, "thread-group", "i%d", + current_inferior ()->num); + } + + ui_out_redirect (uiout, NULL); + + gdb_flush (mi->event_channel); + + do_cleanups (old_chain); + } } static void mi_solib_unloaded (struct so_list *solib) { - struct mi_interp *mi = top_level_interpreter_data (); - struct ui_out *uiout = interp_ui_out (top_level_interpreter ()); + SWITCH_THRU_ALL_UIS () + { + struct mi_interp *mi = as_mi_interp (top_level_interpreter ()); + struct ui_out *uiout; + struct cleanup *old_chain; - target_terminal_ours (); + if (mi == NULL) + continue; - fprintf_unfiltered (mi->event_channel, "library-unloaded"); + uiout = interp_ui_out (top_level_interpreter ()); - ui_out_redirect (uiout, mi->event_channel); + old_chain = make_cleanup_restore_target_terminal (); + target_terminal_ours_for_output (); - ui_out_field_string (uiout, "id", solib->so_original_name); - ui_out_field_string (uiout, "target-name", solib->so_original_name); - ui_out_field_string (uiout, "host-name", solib->so_name); - if (!gdbarch_has_global_solist (target_gdbarch ())) - { - ui_out_field_fmt (uiout, "thread-group", "i%d", current_inferior ()->num); - } + fprintf_unfiltered (mi->event_channel, "library-unloaded"); - ui_out_redirect (uiout, NULL); + ui_out_redirect (uiout, mi->event_channel); - gdb_flush (mi->event_channel); + ui_out_field_string (uiout, "id", solib->so_original_name); + ui_out_field_string (uiout, "target-name", solib->so_original_name); + ui_out_field_string (uiout, "host-name", solib->so_name); + if (!gdbarch_has_global_solist (target_gdbarch ())) + { + ui_out_field_fmt (uiout, "thread-group", "i%d", + current_inferior ()->num); + } + + ui_out_redirect (uiout, NULL); + + gdb_flush (mi->event_channel); + + do_cleanups (old_chain); + } } /* Emit notification about the command parameter change. */ @@ -1047,25 +1202,36 @@ mi_solib_unloaded (struct so_list *solib) static void mi_command_param_changed (const char *param, const char *value) { - struct mi_interp *mi = top_level_interpreter_data (); - struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ()); - if (mi_suppress_notification.cmd_param_changed) return; - target_terminal_ours (); + SWITCH_THRU_ALL_UIS () + { + struct mi_interp *mi = as_mi_interp (top_level_interpreter ()); + struct ui_out *mi_uiout; + struct cleanup *old_chain; - fprintf_unfiltered (mi->event_channel, - "cmd-param-changed"); + if (mi == NULL) + continue; - ui_out_redirect (mi_uiout, mi->event_channel); + mi_uiout = interp_ui_out (top_level_interpreter ()); - ui_out_field_string (mi_uiout, "param", param); - ui_out_field_string (mi_uiout, "value", value); + old_chain = make_cleanup_restore_target_terminal (); + target_terminal_ours_for_output (); - ui_out_redirect (mi_uiout, NULL); + fprintf_unfiltered (mi->event_channel, "cmd-param-changed"); - gdb_flush (mi->event_channel); + ui_out_redirect (mi_uiout, mi->event_channel); + + ui_out_field_string (mi_uiout, "param", param); + ui_out_field_string (mi_uiout, "value", value); + + ui_out_redirect (mi_uiout, NULL); + + gdb_flush (mi->event_channel); + + do_cleanups (old_chain); + } } /* Emit notification about the target memory change. */ @@ -1074,71 +1240,139 @@ static void mi_memory_changed (struct inferior *inferior, CORE_ADDR memaddr, ssize_t len, const bfd_byte *myaddr) { - struct mi_interp *mi = top_level_interpreter_data (); - struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ()); - struct obj_section *sec; - if (mi_suppress_notification.memory) return; - target_terminal_ours (); + SWITCH_THRU_ALL_UIS () + { + struct mi_interp *mi = as_mi_interp (top_level_interpreter ()); + struct ui_out *mi_uiout; + struct obj_section *sec; + struct cleanup *old_chain; - fprintf_unfiltered (mi->event_channel, - "memory-changed"); + if (mi == NULL) + continue; - ui_out_redirect (mi_uiout, mi->event_channel); + mi_uiout = interp_ui_out (top_level_interpreter ()); - ui_out_field_fmt (mi_uiout, "thread-group", "i%d", inferior->num); - ui_out_field_core_addr (mi_uiout, "addr", target_gdbarch (), memaddr); - ui_out_field_fmt (mi_uiout, "len", "%s", hex_string (len)); + old_chain = make_cleanup_restore_target_terminal (); + target_terminal_ours_for_output (); - /* Append 'type=code' into notification if MEMADDR falls in the range of - sections contain code. */ - sec = find_pc_section (memaddr); - if (sec != NULL && sec->objfile != NULL) - { - flagword flags = bfd_get_section_flags (sec->objfile->obfd, - sec->the_bfd_section); + fprintf_unfiltered (mi->event_channel, "memory-changed"); + + ui_out_redirect (mi_uiout, mi->event_channel); - if (flags & SEC_CODE) - ui_out_field_string (mi_uiout, "type", "code"); + ui_out_field_fmt (mi_uiout, "thread-group", "i%d", inferior->num); + ui_out_field_core_addr (mi_uiout, "addr", target_gdbarch (), memaddr); + ui_out_field_fmt (mi_uiout, "len", "%s", hex_string (len)); + + /* Append 'type=code' into notification if MEMADDR falls in the range of + sections contain code. */ + sec = find_pc_section (memaddr); + if (sec != NULL && sec->objfile != NULL) + { + flagword flags = bfd_get_section_flags (sec->objfile->obfd, + sec->the_bfd_section); + + if (flags & SEC_CODE) + ui_out_field_string (mi_uiout, "type", "code"); + } + + ui_out_redirect (mi_uiout, NULL); + + gdb_flush (mi->event_channel); + + do_cleanups (old_chain); } +} - ui_out_redirect (mi_uiout, NULL); +/* Emit an event when the selection context (inferior, thread, frame) + changed. */ - gdb_flush (mi->event_channel); +static void +mi_user_selected_context_changed (user_selected_what selection) +{ + struct thread_info *tp; + + /* Don't send an event if we're responding to an MI command. */ + if (mi_suppress_notification.user_selected_context) + return; + + tp = find_thread_ptid (inferior_ptid); + + SWITCH_THRU_ALL_UIS () + { + struct mi_interp *mi = as_mi_interp (top_level_interpreter ()); + struct ui_out *mi_uiout; + struct cleanup *old_chain; + + if (mi == NULL) + continue; + + mi_uiout = interp_ui_out (top_level_interpreter ()); + + ui_out_redirect (mi_uiout, mi->event_channel); + + old_chain = make_cleanup_ui_out_redirect_pop (mi_uiout); + + make_cleanup_restore_target_terminal (); + target_terminal_ours_for_output (); + + if (selection & USER_SELECTED_INFERIOR) + print_selected_inferior (mi->cli_uiout); + + if (tp != NULL + && (selection & (USER_SELECTED_THREAD | USER_SELECTED_FRAME))) + { + print_selected_thread_frame (mi->cli_uiout, selection); + + fprintf_unfiltered (mi->event_channel, + "thread-selected,id=\"%d\"", + tp->global_num); + + if (tp->state != THREAD_RUNNING) + { + if (has_stack_frames ()) + print_stack_frame_to_uiout (mi_uiout, get_selected_frame (NULL), + 1, SRC_AND_LOC, 1); + } + } + + gdb_flush (mi->event_channel); + do_cleanups (old_chain); + } } static int report_initial_inferior (struct inferior *inf, void *closure) { - /* This function is called from mi_intepreter_init, and since + /* This function is called from mi_interpreter_init, and since mi_inferior_added assumes that inferior is fully initialized and top_level_interpreter_data is set, we cannot call it here. */ - struct mi_interp *mi = closure; + struct mi_interp *mi = (struct mi_interp *) closure; + struct cleanup *old_chain; + + old_chain = make_cleanup_restore_target_terminal (); + target_terminal_ours_for_output (); - target_terminal_ours (); fprintf_unfiltered (mi->event_channel, "thread-group-added,id=\"i%d\"", inf->num); gdb_flush (mi->event_channel); + + do_cleanups (old_chain); return 0; } static struct ui_out * mi_ui_out (struct interp *interp) { - struct mi_interp *mi = interp_data (interp); + struct mi_interp *mi = (struct mi_interp *) interp_data (interp); return mi->mi_uiout; } -/* Save the original value of raw_stdout here when logging, so we can - restore correctly when done. */ - -static struct ui_file *saved_raw_stdout; - /* Do MI-specific logging actions; save raw_stdout, and change all the consoles to use the supplied ui-file(s). */ @@ -1146,7 +1380,7 @@ static int mi_set_logging (struct interp *interp, int start_log, struct ui_file *out, struct ui_file *logfile) { - struct mi_interp *mi = interp_data (interp); + struct mi_interp *mi = (struct mi_interp *) interp_data (interp); if (!mi) return 0; @@ -1161,46 +1395,86 @@ mi_set_logging (struct interp *interp, int start_log, if (logfile) { ui_file_delete (out); - out = tee_file_new (raw_stdout, 0, logfile, 0); + out = tee_file_new (mi->raw_stdout, 0, logfile, 0); } - saved_raw_stdout = raw_stdout; - raw_stdout = out; + mi->saved_raw_stdout = mi->raw_stdout; + mi->raw_stdout = out; } else { - raw_stdout = saved_raw_stdout; - saved_raw_stdout = NULL; + mi->raw_stdout = mi->saved_raw_stdout; + mi->saved_raw_stdout = NULL; } - mi_console_set_raw (mi->out, raw_stdout); - mi_console_set_raw (mi->err, raw_stdout); - mi_console_set_raw (mi->log, raw_stdout); - mi_console_set_raw (mi->targ, raw_stdout); - mi_console_set_raw (mi->event_channel, raw_stdout); + mi_console_set_raw (mi->out, mi->raw_stdout); + mi_console_set_raw (mi->err, mi->raw_stdout); + mi_console_set_raw (mi->log, mi->raw_stdout); + mi_console_set_raw (mi->targ, mi->raw_stdout); + mi_console_set_raw (mi->event_channel, mi->raw_stdout); return 1; } +/* The MI interpreter's vtable. */ + +static const struct interp_procs mi_interp_procs = +{ + mi_interpreter_init, /* init_proc */ + mi_interpreter_resume, /* resume_proc */ + mi_interpreter_suspend, /* suspend_proc */ + mi_interpreter_exec, /* exec_proc */ + mi_ui_out, /* ui_out_proc */ + mi_set_logging, /* set_logging_proc */ + mi_interpreter_pre_command_loop /* pre_command_loop_proc */ +}; + +/* Factory for MI interpreters. */ + +static struct interp * +mi_interp_factory (const char *name) +{ + return interp_new (name, &mi_interp_procs, NULL); +} + extern initialize_file_ftype _initialize_mi_interp; /* -Wmissing-prototypes */ void _initialize_mi_interp (void) { - static const struct interp_procs procs = - { - mi_interpreter_init, /* init_proc */ - mi_interpreter_resume, /* resume_proc */ - mi_interpreter_suspend, /* suspend_proc */ - mi_interpreter_exec, /* exec_proc */ - mi_ui_out, /* ui_out_proc */ - mi_set_logging, /* set_logging_proc */ - mi_command_loop /* command_loop_proc */ - }; - /* The various interpreter levels. */ - interp_add (interp_new (INTERP_MI1, &procs)); - interp_add (interp_new (INTERP_MI2, &procs)); - interp_add (interp_new (INTERP_MI3, &procs)); - interp_add (interp_new (INTERP_MI, &procs)); + interp_factory_register (INTERP_MI1, mi_interp_factory); + interp_factory_register (INTERP_MI2, mi_interp_factory); + interp_factory_register (INTERP_MI3, mi_interp_factory); + interp_factory_register (INTERP_MI, mi_interp_factory); + + observer_attach_signal_received (mi_on_signal_received); + observer_attach_end_stepping_range (mi_on_end_stepping_range); + observer_attach_signal_exited (mi_on_signal_exited); + observer_attach_exited (mi_on_exited); + observer_attach_no_history (mi_on_no_history); + observer_attach_new_thread (mi_new_thread); + observer_attach_thread_exit (mi_thread_exit); + observer_attach_inferior_added (mi_inferior_added); + observer_attach_inferior_appeared (mi_inferior_appeared); + observer_attach_inferior_exit (mi_inferior_exit); + observer_attach_inferior_removed (mi_inferior_removed); + observer_attach_record_changed (mi_record_changed); + observer_attach_normal_stop (mi_on_normal_stop); + observer_attach_target_resumed (mi_on_resume); + observer_attach_solib_loaded (mi_solib_loaded); + observer_attach_solib_unloaded (mi_solib_unloaded); + observer_attach_about_to_proceed (mi_about_to_proceed); + observer_attach_traceframe_changed (mi_traceframe_changed); + observer_attach_tsv_created (mi_tsv_created); + observer_attach_tsv_deleted (mi_tsv_deleted); + observer_attach_tsv_modified (mi_tsv_modified); + observer_attach_breakpoint_created (mi_breakpoint_created); + observer_attach_breakpoint_deleted (mi_breakpoint_deleted); + observer_attach_breakpoint_modified (mi_breakpoint_modified); + observer_attach_command_param_changed (mi_command_param_changed); + observer_attach_memory_changed (mi_memory_changed); + observer_attach_sync_execution_done (mi_on_sync_execution_done); + observer_attach_user_selected_context_changed + (mi_user_selected_context_changed); }