diff options
Diffstat (limited to 'gdb/mi')
-rw-r--r-- | gdb/mi/mi-cmds.c | 6 | ||||
-rw-r--r-- | gdb/mi/mi-interp.c | 61 | ||||
-rw-r--r-- | gdb/mi/mi-main.c | 77 | ||||
-rw-r--r-- | gdb/mi/mi-main.h | 2 |
4 files changed, 122 insertions, 24 deletions
diff --git a/gdb/mi/mi-cmds.c b/gdb/mi/mi-cmds.c index 4779832..85c19c1 100644 --- a/gdb/mi/mi-cmds.c +++ b/gdb/mi/mi-cmds.c @@ -137,7 +137,8 @@ static struct mi_cmd mi_cmds[] = DEF_MI_CMD_MI ("stack-list-frames", mi_cmd_stack_list_frames), DEF_MI_CMD_MI ("stack-list-locals", mi_cmd_stack_list_locals), DEF_MI_CMD_MI ("stack-list-variables", mi_cmd_stack_list_variables), - DEF_MI_CMD_MI ("stack-select-frame", mi_cmd_stack_select_frame), + DEF_MI_CMD_MI_1 ("stack-select-frame", mi_cmd_stack_select_frame, + &mi_suppress_notification.user_selected_context), DEF_MI_CMD_MI ("symbol-list-lines", mi_cmd_symbol_list_lines), DEF_MI_CMD_CLI ("target-attach", "attach", 1), DEF_MI_CMD_MI ("target-detach", mi_cmd_target_detach), @@ -149,7 +150,8 @@ static struct mi_cmd mi_cmds[] = DEF_MI_CMD_CLI ("target-select", "target", 1), DEF_MI_CMD_MI ("thread-info", mi_cmd_thread_info), DEF_MI_CMD_MI ("thread-list-ids", mi_cmd_thread_list_ids), - DEF_MI_CMD_MI ("thread-select", mi_cmd_thread_select), + DEF_MI_CMD_MI_1 ("thread-select", mi_cmd_thread_select, + &mi_suppress_notification.user_selected_context), DEF_MI_CMD_MI ("trace-define-variable", mi_cmd_trace_define_variable), DEF_MI_CMD_MI_1 ("trace-find", mi_cmd_trace_find, &mi_suppress_notification.traceframe), diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c index e3c7dbd..d7db499 100644 --- a/gdb/mi/mi-interp.c +++ b/gdb/mi/mi-interp.c @@ -769,6 +769,7 @@ struct mi_suppress_notification mi_suppress_notification = 0, 0, 0, + 0, }; /* Emit notification on changing a traceframe. */ @@ -1334,6 +1335,64 @@ mi_memory_changed (struct inferior *inferior, CORE_ADDR memaddr, } } +/* Emit an event when the selection context (inferior, thread, frame) + changed. */ + +static void +mi_user_selected_context_changed (user_selected_what selection) +{ + struct switch_thru_all_uis state; + 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 (state) + { + 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) { @@ -1466,4 +1525,6 @@ _initialize_mi_interp (void) 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); } diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c index 1913157..7cd9706 100644 --- a/gdb/mi/mi-main.c +++ b/gdb/mi/mi-main.c @@ -53,6 +53,7 @@ #include "linespec.h" #include "extension.h" #include "gdbcmd.h" +#include "observer.h" #include <ctype.h> #include "gdb_sys_time.h" @@ -564,17 +565,29 @@ mi_cmd_thread_select (char *command, char **argv, int argc) { enum gdb_rc rc; char *mi_error_message; + ptid_t previous_ptid = inferior_ptid; if (argc != 1) error (_("-thread-select: USAGE: threadnum.")); rc = gdb_thread_select (current_uiout, argv[0], &mi_error_message); + /* If thread switch did not succeed don't notify or print. */ if (rc == GDB_RC_FAIL) { make_cleanup (xfree, mi_error_message); error ("%s", mi_error_message); } + + print_selected_thread_frame (current_uiout, + USER_SELECTED_THREAD | USER_SELECTED_FRAME); + + /* Notify if the thread has effectively changed. */ + if (!ptid_equal (inferior_ptid, previous_ptid)) + { + observer_notify_user_selected_context_changed (USER_SELECTED_THREAD + | USER_SELECTED_FRAME); + } } void @@ -2097,6 +2110,34 @@ mi_print_exception (const char *token, struct gdb_exception exception) fputs_unfiltered ("\n", mi->raw_stdout); } +/* Determine whether the parsed command already notifies the + user_selected_context_changed observer. */ + +static int +command_notifies_uscc_observer (struct mi_parse *command) +{ + if (command->op == CLI_COMMAND) + { + /* CLI commands "thread" and "inferior" already send it. */ + return (strncmp (command->command, "thread ", 7) == 0 + || strncmp (command->command, "inferior ", 9) == 0); + } + else /* MI_COMMAND */ + { + if (strcmp (command->command, "interpreter-exec") == 0 + && command->argc > 1) + { + /* "thread" and "inferior" again, but through -interpreter-exec. */ + return (strncmp (command->argv[1], "thread ", 7) == 0 + || strncmp (command->argv[1], "inferior ", 9) == 0); + } + + else + /* -thread-select already sends it. */ + return strcmp (command->command, "thread-select") == 0; + } +} + void mi_execute_command (const char *cmd, int from_tty) { @@ -2124,9 +2165,16 @@ mi_execute_command (const char *cmd, int from_tty) if (command != NULL) { ptid_t previous_ptid = inferior_ptid; + struct cleanup *cleanup = make_cleanup (null_cleanup, NULL); command->token = token; + if (command->cmd != NULL && command->cmd->suppress_notification != NULL) + { + make_cleanup_restore_integer (command->cmd->suppress_notification); + *command->cmd->suppress_notification = 1; + } + if (do_timings) { command->cmd_start = XNEW (struct mi_timestamp); @@ -2161,10 +2209,9 @@ mi_execute_command (const char *cmd, int from_tty) /* Don't try report anything if there are no threads -- the program is dead. */ && thread_count () != 0 - /* -thread-select explicitly changes thread. If frontend uses that - internally, we don't want to emit =thread-selected, since - =thread-selected is supposed to indicate user's intentions. */ - && strcmp (command->command, "thread-select") != 0) + /* If the command already reports the thread change, no need to do it + again. */ + && !command_notifies_uscc_observer (command)) { struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data (); @@ -2185,22 +2232,14 @@ mi_execute_command (const char *cmd, int from_tty) if (report_change) { - struct thread_info *ti = inferior_thread (); - struct cleanup *old_chain; - - old_chain = make_cleanup_restore_target_terminal (); - target_terminal_ours_for_output (); - - fprintf_unfiltered (mi->event_channel, - "thread-selected,id=\"%d\"", - ti->global_num); - gdb_flush (mi->event_channel); - - do_cleanups (old_chain); + observer_notify_user_selected_context_changed + (USER_SELECTED_THREAD | USER_SELECTED_FRAME); } } mi_parse_free (command); + + do_cleanups (cleanup); } } @@ -2277,12 +2316,6 @@ mi_cmd_execute (struct mi_parse *parse) current_context = parse; - if (parse->cmd->suppress_notification != NULL) - { - make_cleanup_restore_integer (parse->cmd->suppress_notification); - *parse->cmd->suppress_notification = 1; - } - if (parse->cmd->argv_func != NULL) { parse->cmd->argv_func (parse->command, parse->argv, parse->argc); diff --git a/gdb/mi/mi-main.h b/gdb/mi/mi-main.h index 18000cf..bf4d1b6 100644 --- a/gdb/mi/mi-main.h +++ b/gdb/mi/mi-main.h @@ -49,6 +49,8 @@ struct mi_suppress_notification int traceframe; /* Memory changed notification suppressed? */ int memory; + /* User selected context changed notification suppressed? */ + int user_selected_context; }; extern struct mi_suppress_notification mi_suppress_notification; |