aboutsummaryrefslogtreecommitdiff
path: root/gdb/mi
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/mi')
-rw-r--r--gdb/mi/mi-cmds.c6
-rw-r--r--gdb/mi/mi-interp.c61
-rw-r--r--gdb/mi/mi-main.c77
-rw-r--r--gdb/mi/mi-main.h2
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;