diff options
-rw-r--r-- | gdb/ChangeLog | 58 | ||||
-rw-r--r-- | gdb/NEWS | 4 | ||||
-rw-r--r-- | gdb/cli/cli-decode.c | 32 | ||||
-rw-r--r-- | gdb/cli/cli-decode.h | 6 | ||||
-rw-r--r-- | gdb/cli/cli-interp.c | 38 | ||||
-rw-r--r-- | gdb/command.h | 16 | ||||
-rw-r--r-- | gdb/defs.h | 16 | ||||
-rw-r--r-- | gdb/doc/ChangeLog | 11 | ||||
-rw-r--r-- | gdb/doc/gdb.texinfo | 33 | ||||
-rw-r--r-- | gdb/doc/observer.texi | 4 | ||||
-rw-r--r-- | gdb/frame.h | 8 | ||||
-rw-r--r-- | gdb/gdbthread.h | 4 | ||||
-rw-r--r-- | gdb/inferior.c | 40 | ||||
-rw-r--r-- | gdb/inferior.h | 3 | ||||
-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 | ||||
-rw-r--r-- | gdb/stack.c | 42 | ||||
-rw-r--r-- | gdb/testsuite/ChangeLog | 7 | ||||
-rw-r--r-- | gdb/testsuite/gdb.mi/mi-pthreads.exp | 4 | ||||
-rw-r--r-- | gdb/thread.c | 86 | ||||
-rw-r--r-- | gdb/tui/tui-interp.c | 33 |
23 files changed, 503 insertions, 88 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index ffbdc3d..2b5232c 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,61 @@ +2016-10-03 Antoine Tremblay <antoine.tremblay@ericsson.com> +2016-10-03 Simon Marchi <simon.marchi@ericsson.com> + + PR gdb/20487 + * NEWS: Mention new frame field of =thread-selected event. + * cli/cli-decode.c (add_cmd): Initialize c->suppress_notification. + (add_com_suppress_notification): New function definition. + (cmd_func): Set and restore the suppress_notification flag. + * cli/cli-deicode.h (struct cmd_list_element) + <suppress_notification>: New field. + * cli/cli-interp.c (cli_suppress_notification): New global variable. + (cli_on_user_selected_context_changed): New function. + (_initialize_cli_interp): Attach to user_selected_context_changed + observer. + * command.h (struct cli_suppress_notification): New structure. + (cli_suppress_notification): New global variable declaration. + (add_com_suppress_notification): New function declaration. + * defs.h (enum user_selected_what_flag): New enum. + (user_selected_what): New enum flag type. + * frame.h (print_stack_frame_to_uiout): New function declaration. + * gdbthread.h (print_selected_thread_frame): New function declaration. + * inferior.c (print_selected_inferior): New function definition. + (inferior_command): Remove printing of inferior/thread/frame switch + notifications, notify user_selected_context_changed observer. + * inferior.h (print_selected_inferior): New function declaration. + * mi/mi-cmds.c (struct mi_cmd): Add user_selected_context + suppression to stack-select-frame and thread-select commands. + * mi/mi-interp.c (struct mi_suppress_notification) + <user_selected_context>: Initialize. + (mi_user_selected_context_changed): New function definition. + (_initialize_mi_interp): Attach to user_selected_context_changed. + * mi/mi-main.c (mi_cmd_thread_select): Print thread selection reply. + (mi_execute_command): Handle notification suppression. Notify + user_selected_context_changed observer on thread change instead of printing + event directly. Don't send it if command already sends the notification. + (command_notifies_uscc_observer): New function. + (mi_cmd_execute): Don't handle notification suppression. + * mi/mi-main.h (struct mi_suppress_notification) + <user_selected_context>: New field. + * stack.c (print_stack_frame_to_uiout): New function definition. + (select_frame_command): Notify user_selected_context_changed + observer. + (frame_command): Call print_selected_thread_frame if there's no frame + change or notify user_selected_context_changed observer if there is. + (up_command): Notify user_selected_context_changed observer. + (down_command): Likewise. + (_initialize_stack): Suppress user_selected_context notification for + command select-frame. + * thread.c (thread_command): Notify + user_selected_context_changed if the thread has changed, print + thread info directly if it hasn't. + (do_captured_thread_select): Do not print thread switch event. + (print_selected_thread_frame): New function definition. + * tui/tui-interp.c (tui_on_user_selected_context_changed): + New function definition. + (_initialize_tui_interp): Attach to user_selected_context_changed + observer. + 2016-09-29 Jan Kratochvil <jan.kratochvil@redhat.com> PR gdb/20609 - attach of JIT-debug-enabled inf 7.11.1 regression @@ -152,6 +152,10 @@ signal-event EVENTID =record-started,thread-group="i1",method="btrace",format="bts" +* MI async record =thread-selected now includes the frame field. For example: + + =thread-selected,id="3",frame={level="0",addr="0x00000000004007c0"} + * New targets Andes NDS32 nds32*-*-elf diff --git a/gdb/cli/cli-decode.c b/gdb/cli/cli-decode.c index 0d2b137..acc9c42 100644 --- a/gdb/cli/cli-decode.c +++ b/gdb/cli/cli-decode.c @@ -253,6 +253,7 @@ add_cmd (const char *name, enum command_class theclass, cmd_cfunc_ftype *fun, c->user_commands = NULL; c->cmd_pointer = NULL; c->alias_chain = NULL; + c->suppress_notification = NULL; return c; } @@ -883,7 +884,22 @@ add_com_alias (const char *name, const char *oldname, enum command_class theclas { return add_alias_cmd (name, oldname, theclass, abbrev_flag, &cmdlist); } - + +/* Add an element with a suppress notification to the list of commands. */ + +struct cmd_list_element * +add_com_suppress_notification (const char *name, enum command_class theclass, + cmd_cfunc_ftype *fun, const char *doc, + int *suppress_notification) +{ + struct cmd_list_element *element; + + element = add_cmd (name, theclass, fun, doc, &cmdlist); + element->suppress_notification = suppress_notification; + + return element; +} + /* Recursively walk the commandlist structures, and print out the documentation of commands that match our regex in either their name, or their documentation. @@ -1885,7 +1901,19 @@ void cmd_func (struct cmd_list_element *cmd, char *args, int from_tty) { if (cmd_func_p (cmd)) - (*cmd->func) (cmd, args, from_tty); + { + struct cleanup *cleanups = make_cleanup (null_cleanup, NULL); + + if (cmd->suppress_notification != NULL) + { + make_cleanup_restore_integer (cmd->suppress_notification); + *cmd->suppress_notification = 1; + } + + (*cmd->func) (cmd, args, from_tty); + + do_cleanups (cleanups); + } else error (_("Invalid command")); } diff --git a/gdb/cli/cli-decode.h b/gdb/cli/cli-decode.h index 4ea8063..4ef2e1b 100644 --- a/gdb/cli/cli-decode.h +++ b/gdb/cli/cli-decode.h @@ -218,6 +218,12 @@ struct cmd_list_element /* Link pointer for aliases on an alias list. */ struct cmd_list_element *alias_chain; + + /* If non-null, the pointer to a field in 'struct + cli_suppress_notification', which will be set to true in cmd_func + when this command is being executed. It will be set back to false + when the command has been executed. */ + int *suppress_notification; }; extern void help_cmd_list (struct cmd_list_element *, enum command_class, diff --git a/gdb/cli/cli-interp.c b/gdb/cli/cli-interp.c index 5d67ba4..cc556a4 100644 --- a/gdb/cli/cli-interp.c +++ b/gdb/cli/cli-interp.c @@ -37,6 +37,12 @@ struct cli_interp struct ui_out *cli_uiout; }; +/* Suppress notification struct. */ +struct cli_suppress_notification cli_suppress_notification = + { + 0 /* user_selected_context_changed */ + }; + /* Returns the INTERP's data cast as cli_interp if INTERP is a CLI, and returns NULL otherwise. */ @@ -229,6 +235,36 @@ cli_on_command_error (void) display_gdb_prompt (NULL); } +/* Observer for the user_selected_context_changed notification. */ + +static void +cli_on_user_selected_context_changed (user_selected_what selection) +{ + struct switch_thru_all_uis state; + struct thread_info *tp; + + /* This event is suppressed. */ + if (cli_suppress_notification.user_selected_context) + return; + + tp = find_thread_ptid (inferior_ptid); + + SWITCH_THRU_ALL_UIS (state) + { + struct cli_interp *cli = as_cli_interp (top_level_interpreter ()); + + if (cli == NULL) + continue; + + if (selection & USER_SELECTED_INFERIOR) + print_selected_inferior (cli->cli_uiout); + + if (tp != NULL + && ((selection & (USER_SELECTED_THREAD | USER_SELECTED_FRAME)))) + print_selected_thread_frame (cli->cli_uiout, selection); + } +} + /* pre_command_loop implementation. */ void @@ -393,4 +429,6 @@ _initialize_cli_interp (void) observer_attach_no_history (cli_on_no_history); observer_attach_sync_execution_done (cli_on_sync_execution_done); observer_attach_command_error (cli_on_command_error); + observer_attach_user_selected_context_changed + (cli_on_user_selected_context_changed); } diff --git a/gdb/command.h b/gdb/command.h index ab62601..965d91f 100644 --- a/gdb/command.h +++ b/gdb/command.h @@ -115,6 +115,17 @@ struct cmd_list_element; typedef void cmd_cfunc_ftype (char *args, int from_tty); +/* This structure specifies notifications to be suppressed by a cli + command interpreter. */ + +struct cli_suppress_notification +{ + /* Inferior, thread, frame selected notification suppressed? */ + int user_selected_context; +}; + +extern struct cli_suppress_notification cli_suppress_notification; + /* Forward-declarations of the entry-points of cli/cli-decode.c. */ /* API to the manipulation of command lists. */ @@ -218,6 +229,11 @@ extern struct cmd_list_element *add_com (const char *, enum command_class, extern struct cmd_list_element *add_com_alias (const char *, const char *, enum command_class, int); +extern struct cmd_list_element *add_com_suppress_notification + (const char *name, enum command_class theclass, + cmd_cfunc_ftype *fun, const char *doc, + int *supress_notification); + extern struct cmd_list_element *add_info (const char *, cmd_cfunc_ftype *fun, const char *); @@ -53,6 +53,7 @@ #include "ui-file.h" #include "host-defs.h" +#include "common/enum-flags.h" /* Scope types enumerator. List the types of scopes the compiler will accept. */ @@ -743,6 +744,21 @@ enum block_enum FIRST_LOCAL_BLOCK = 2 }; +/* User selection used in observer.h and multiple print functions. */ + +enum user_selected_what_flag + { + /* Inferior selected. */ + USER_SELECTED_INFERIOR = 1 << 1, + + /* Thread selected. */ + USER_SELECTED_THREAD = 1 << 2, + + /* Frame selected. */ + USER_SELECTED_FRAME = 1 << 3 + }; +DEF_ENUM_FLAGS_TYPE (enum user_selected_what_flag, user_selected_what); + #include "utils.h" #endif /* #ifndef DEFS_H */ diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index d0b071a..85b55e2 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,14 @@ +2016-10-03 Antoine Tremblay <antoine.tremblay@ericsson.com> +2016-10-03 Simon Marchi <simon.marchi@ericsson.com> + + PR gdb/20487 + * gdb.texinfo (Context management): Update mention of frame + change notifications. + (gdb/mi Async Records): Document frame field in + =thread-select event. + * observer.texi (GDB Observers): New user_selected_context_changed + observer. + 2016-09-28 Tom Tromey <tom@tromey.com> * gdb.texinfo (Packets) <z0>: Use "software breakpoint" rather diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 099680d..344c186 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -25832,13 +25832,13 @@ identifier for thread and frame to operate on. Usually, each top-level window in a frontend allows the user to select a thread and a frame, and remembers the user selection for further operations. However, in some cases @value{GDBN} may suggest that the -current thread be changed. For example, when stopping on a breakpoint -it is reasonable to switch to the thread where breakpoint is hit. For -another example, if the user issues the CLI @samp{thread} command via -the frontend, it is desirable to change the frontend's selected thread to the -one specified by user. @value{GDBN} communicates the suggestion to -change current thread using the @samp{=thread-selected} notification. -No such notification is available for the selected frame at the moment. +current thread or frame be changed. For example, when stopping on a +breakpoint it is reasonable to switch to the thread where breakpoint is +hit. For another example, if the user issues the CLI @samp{thread} or +@samp{frame} commands via the frontend, it is desirable to change the +frontend's selection to the one specified by user. @value{GDBN} +communicates the suggestion to change current thread and frame using the +@samp{=thread-selected} notification. Note that historically, MI shares the selected thread with CLI, so frontends used the @code{-thread-select} to execute commands in the @@ -26484,13 +26484,18 @@ A thread either was created, or has exited. The @var{id} field contains the global @value{GDBN} identifier of the thread. The @var{gid} field identifies the thread group this thread belongs to. -@item =thread-selected,id="@var{id}" -Informs that the selected thread was changed as result of the last -command. This notification is not emitted as result of @code{-thread-select} -command but is emitted whenever an MI command that is not documented -to change the selected thread actually changes it. In particular, -invoking, directly or indirectly (via user-defined command), the CLI -@code{thread} command, will generate this notification. +@item =thread-selected,id="@var{id}"[,frame="@var{frame}"] +Informs that the selected thread or frame were changed. This notification +is not emitted as result of the @code{-thread-select} or +@code{-stack-select-frame} commands, but is emitted whenever an MI command +that is not documented to change the selected thread and frame actually +changes them. In particular, invoking, directly or indirectly +(via user-defined command), the CLI @code{thread} or @code{frame} commands, +will generate this notification. Changing the thread or frame from another +user interface (see @ref{Interpreters}) will also generate this notification. + +The @var{frame} field is only present if the newly selected thread is +stopped. See @ref{GDB/MI Frame Information} for the format of its value. We suggest that in response to this notification, front ends highlight the selected thread and cause subsequent commands to apply to diff --git a/gdb/doc/observer.texi b/gdb/doc/observer.texi index fc7aac4..6ef27b7 100644 --- a/gdb/doc/observer.texi +++ b/gdb/doc/observer.texi @@ -307,3 +307,7 @@ This observer is used for internal testing. Do not use. See testsuite/gdb.gdb/observer.exp. @end deftypefun +@deftypefun void user_selected_context_changed (user_selected_what @var{selection}) +The user-selected inferior, thread and/or frame has changed. The user_select_what +flag specifies if the inferior, thread and/or frame has changed. +@end deftypefun diff --git a/gdb/frame.h b/gdb/frame.h index 5f21bb8..de13e7d 100644 --- a/gdb/frame.h +++ b/gdb/frame.h @@ -704,6 +704,14 @@ extern CORE_ADDR get_pc_function_start (CORE_ADDR); extern struct frame_info *find_relative_frame (struct frame_info *, int *); +/* Wrapper over print_stack_frame modifying current_uiout with UIOUT for + the function call. */ + +extern void print_stack_frame_to_uiout (struct ui_out *uiout, + struct frame_info *, int print_level, + enum print_what print_what, + int set_current_sal); + extern void print_stack_frame (struct frame_info *, int print_level, enum print_what print_what, int set_current_sal); diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h index af2dc86..8f37fbb 100644 --- a/gdb/gdbthread.h +++ b/gdb/gdbthread.h @@ -630,6 +630,10 @@ extern void validate_registers_access (void); true iff we ever detected multiple threads. */ extern int show_thread_that_caused_stop (void); +/* Print the message for a thread or/and frame selected. */ +extern void print_selected_thread_frame (struct ui_out *uiout, + user_selected_what selection); + extern struct thread_info *thread_list; #endif /* GDBTHREAD_H */ diff --git a/gdb/inferior.c b/gdb/inferior.c index 47d91c7..277b988 100644 --- a/gdb/inferior.c +++ b/gdb/inferior.c @@ -548,6 +548,24 @@ inferior_pid_to_str (int pid) return _("<null>"); } +/* See inferior.h. */ + +void +print_selected_inferior (struct ui_out *uiout) +{ + char buf[PATH_MAX + 256]; + struct inferior *inf = current_inferior (); + + xsnprintf (buf, sizeof (buf), + _("[Switching to inferior %d [%s] (%s)]\n"), + inf->num, + inferior_pid_to_str (inf->pid), + (inf->pspace->pspace_exec_filename != NULL + ? inf->pspace->pspace_exec_filename + : _("<noexec>"))); + ui_out_text (uiout, buf); +} + /* Prints the list of inferiors and their details on UIOUT. This is a version of 'info_inferior_command' suitable for use from MI. @@ -726,13 +744,6 @@ inferior_command (char *args, int from_tty) if (inf == NULL) error (_("Inferior ID %d not known."), num); - printf_filtered (_("[Switching to inferior %d [%s] (%s)]\n"), - inf->num, - inferior_pid_to_str (inf->pid), - (inf->pspace->pspace_exec_filename != NULL - ? inf->pspace->pspace_exec_filename - : _("<noexec>"))); - if (inf->pid != 0) { if (inf->pid != ptid_get_pid (inferior_ptid)) @@ -746,9 +757,10 @@ inferior_command (char *args, int from_tty) switch_to_thread (tp->ptid); } - printf_filtered (_("[Switching to thread %s (%s)] "), - print_thread_id (inferior_thread ()), - target_pid_to_str (inferior_ptid)); + observer_notify_user_selected_context_changed + (USER_SELECTED_INFERIOR + | USER_SELECTED_THREAD + | USER_SELECTED_FRAME); } else { @@ -758,14 +770,8 @@ inferior_command (char *args, int from_tty) set_current_inferior (inf); switch_to_thread (null_ptid); set_current_program_space (inf->pspace); - } - if (inf->pid != 0 && is_running (inferior_ptid)) - ui_out_text (current_uiout, "(running)\n"); - else if (inf->pid != 0) - { - ui_out_text (current_uiout, "\n"); - print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1); + observer_notify_user_selected_context_changed (USER_SELECTED_INFERIOR); } } diff --git a/gdb/inferior.h b/gdb/inferior.h index 571d26a..54c6f65 100644 --- a/gdb/inferior.h +++ b/gdb/inferior.h @@ -523,4 +523,7 @@ extern int number_of_inferiors (void); extern struct inferior *add_inferior_with_spaces (void); +/* Print the current selected inferior. */ +extern void print_selected_inferior (struct ui_out *uiout); + #endif /* !defined (INFERIOR_H) */ 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; diff --git a/gdb/stack.c b/gdb/stack.c index 417e887..b719fcd 100644 --- a/gdb/stack.c +++ b/gdb/stack.c @@ -51,6 +51,7 @@ #include "safe-ctype.h" #include "symfile.h" #include "extension.h" +#include "observer.h" /* The possible choices of "set print frame-arguments", and the value of this setting. */ @@ -141,6 +142,24 @@ frame_show_address (struct frame_info *frame, return get_frame_pc (frame) != sal.pc; } +/* See frame.h. */ + +void +print_stack_frame_to_uiout (struct ui_out *uiout, struct frame_info *frame, + int print_level, enum print_what print_what, + int set_current_sal) +{ + struct cleanup *old_chain; + + old_chain = make_cleanup_restore_current_uiout (); + + current_uiout = uiout; + + print_stack_frame (frame, print_level, print_what, set_current_sal); + + do_cleanups (old_chain); +} + /* Show or print a stack frame FRAME briefly. The output is formatted according to PRINT_LEVEL and PRINT_WHAT printing the frame's relative level, function name, argument list, and file name and @@ -2302,7 +2321,11 @@ find_relative_frame (struct frame_info *frame, int *level_offset_ptr) void select_frame_command (char *level_exp, int from_tty) { + struct frame_info *prev_frame = get_selected_frame_if_set (); + select_frame (parse_frame_specification (level_exp, NULL)); + if (get_selected_frame_if_set () != prev_frame) + observer_notify_user_selected_context_changed (USER_SELECTED_FRAME); } /* The "frame" command. With no argument, print the selected frame @@ -2312,8 +2335,13 @@ select_frame_command (char *level_exp, int from_tty) static void frame_command (char *level_exp, int from_tty) { - select_frame_command (level_exp, from_tty); - print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1); + struct frame_info *prev_frame = get_selected_frame_if_set (); + + select_frame (parse_frame_specification (level_exp, NULL)); + if (get_selected_frame_if_set () != prev_frame) + observer_notify_user_selected_context_changed (USER_SELECTED_FRAME); + else + print_selected_thread_frame (current_uiout, USER_SELECTED_FRAME); } /* Select the frame up one or COUNT_EXP stack levels from the @@ -2344,7 +2372,7 @@ static void up_command (char *count_exp, int from_tty) { up_silently_base (count_exp); - print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1); + observer_notify_user_selected_context_changed (USER_SELECTED_FRAME); } /* Select the frame down one or COUNT_EXP stack levels from the previously @@ -2383,9 +2411,8 @@ static void down_command (char *count_exp, int from_tty) { down_silently_base (count_exp); - print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1); + observer_notify_user_selected_context_changed (USER_SELECTED_FRAME); } - void return_command (char *retval_exp, int from_tty) @@ -2616,10 +2643,11 @@ a command file or a user-defined command.")); add_com_alias ("f", "frame", class_stack, 1); - add_com ("select-frame", class_stack, select_frame_command, _("\ + add_com_suppress_notification ("select-frame", class_stack, select_frame_command, _("\ Select a stack frame without printing anything.\n\ An argument specifies the frame to select.\n\ -It can be a stack frame number or the address of the frame.\n")); +It can be a stack frame number or the address of the frame.\n"), + &cli_suppress_notification.user_selected_context); add_com ("backtrace", class_stack, backtrace_command, _("\ Print backtrace of all stack frames, or innermost COUNT frames.\n\ diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index d7cdf74..6d93c28 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2016-10-03 Antoine Tremblay <antoine.tremblay@ericsson.com> +2016-10-03 Simon Marchi <simon.marchi@ericsson.com> + + PR gdb/20487 + * gdb.mi/mi-pthreads.exp (check_mi_thread_command_set): Adapt + =thread-select-event check. + 2016-09-29 Peter Bergner <bergner@vnet.ibm.com> * gdb.arch/powerpc-power.exp <cmprb>: Update tests to account for diff --git a/gdb/testsuite/gdb.mi/mi-pthreads.exp b/gdb/testsuite/gdb.mi/mi-pthreads.exp index 88a600a..511f0ca 100644 --- a/gdb/testsuite/gdb.mi/mi-pthreads.exp +++ b/gdb/testsuite/gdb.mi/mi-pthreads.exp @@ -53,8 +53,8 @@ proc check_mi_thread_command_set {} { foreach thread $thread_list { mi_gdb_test "-interpreter-exec console \"thread $thread\"" \ - ".*\\^done\r\n=thread-selected,id=\"$thread\"" \ - "check =thread-selected: thread $thread" + ".*=thread-selected,id=\"$thread\".*\r\n\\^done" \ + "check =thread-selected: thread $thread" } } diff --git a/gdb/thread.c b/gdb/thread.c index a66a2b5..13449a8 100644 --- a/gdb/thread.c +++ b/gdb/thread.c @@ -1923,7 +1923,7 @@ thread_apply_command (char *tidlist, int from_tty) void thread_command (char *tidstr, int from_tty) { - if (!tidstr) + if (tidstr == NULL) { if (ptid_equal (inferior_ptid, null_ptid)) error (_("No thread selected")); @@ -1943,10 +1943,31 @@ thread_command (char *tidstr, int from_tty) } else error (_("No stack.")); - return; } + else + { + ptid_t previous_ptid = inferior_ptid; + enum gdb_rc result; + + result = gdb_thread_select (current_uiout, tidstr, NULL); + + /* If thread switch did not succeed don't notify or print. */ + if (result == GDB_RC_FAIL) + return; - gdb_thread_select (current_uiout, tidstr, NULL); + /* Print if the thread has not changed, otherwise an event will be sent. */ + if (ptid_equal (inferior_ptid, previous_ptid)) + { + print_selected_thread_frame (current_uiout, + USER_SELECTED_THREAD + | USER_SELECTED_FRAME); + } + else + { + observer_notify_user_selected_context_changed (USER_SELECTED_THREAD + | USER_SELECTED_FRAME); + } + } } /* Implementation of `thread name'. */ @@ -2058,32 +2079,53 @@ do_captured_thread_select (struct ui_out *uiout, void *tidstr_v) annotate_thread_changed (); - if (ui_out_is_mi_like_p (uiout)) - ui_out_field_int (uiout, "new-thread-id", inferior_thread ()->global_num); - else + /* Since the current thread may have changed, see if there is any + exited thread we can now delete. */ + prune_threads (); + + return GDB_RC_OK; +} + +/* Print thread and frame switch command response. */ + +void +print_selected_thread_frame (struct ui_out *uiout, + user_selected_what selection) +{ + struct thread_info *tp = inferior_thread (); + struct inferior *inf = current_inferior (); + + if (selection & USER_SELECTED_THREAD) { - ui_out_text (uiout, "[Switching to thread "); - ui_out_field_string (uiout, "new-thread-id", print_thread_id (tp)); - ui_out_text (uiout, " ("); - ui_out_text (uiout, target_pid_to_str (inferior_ptid)); - ui_out_text (uiout, ")]"); + if (ui_out_is_mi_like_p (uiout)) + { + ui_out_field_int (uiout, "new-thread-id", + inferior_thread ()->global_num); + } + else + { + ui_out_text (uiout, "[Switching to thread "); + ui_out_field_string (uiout, "new-thread-id", print_thread_id (tp)); + ui_out_text (uiout, " ("); + ui_out_text (uiout, target_pid_to_str (inferior_ptid)); + ui_out_text (uiout, ")]"); + } } - /* Note that we can't reach this with an exited thread, due to the - thread_alive check above. */ if (tp->state == THREAD_RUNNING) - ui_out_text (uiout, "(running)\n"); - else { - ui_out_text (uiout, "\n"); - print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1); + if (selection & USER_SELECTED_THREAD) + ui_out_text (uiout, "(running)\n"); } + else if (selection & USER_SELECTED_FRAME) + { + if (selection & USER_SELECTED_THREAD) + ui_out_text (uiout, "\n"); - /* Since the current thread may have changed, see if there is any - exited thread we can now delete. */ - prune_threads (); - - return GDB_RC_OK; + if (has_stack_frames ()) + print_stack_frame_to_uiout (uiout, get_selected_frame (NULL), + 1, SRC_AND_LOC, 1); + } } enum gdb_rc diff --git a/gdb/tui/tui-interp.c b/gdb/tui/tui-interp.c index 3856382..e06d679 100644 --- a/gdb/tui/tui-interp.c +++ b/gdb/tui/tui-interp.c @@ -206,6 +206,37 @@ tui_on_command_error (void) display_gdb_prompt (NULL); } +/* Observer for the user_selected_context_changed notification. */ + +static void +tui_on_user_selected_context_changed (user_selected_what selection) +{ + struct switch_thru_all_uis state; + struct thread_info *tp; + + /* This event is suppressed. */ + if (cli_suppress_notification.user_selected_context) + return; + + tp = find_thread_ptid (inferior_ptid); + + SWITCH_THRU_ALL_UIS (state) + { + struct interp *tui = as_tui_interp (top_level_interpreter ()); + + if (tui == NULL) + continue; + + if (selection & USER_SELECTED_INFERIOR) + print_selected_inferior (tui_ui_out (tui)); + + if (tp != NULL + && ((selection & (USER_SELECTED_THREAD | USER_SELECTED_FRAME)))) + print_selected_thread_frame (tui_ui_out (tui), selection); + + } +} + /* These implement the TUI interpreter. */ static void * @@ -323,4 +354,6 @@ _initialize_tui_interp (void) observer_attach_no_history (tui_on_no_history); observer_attach_sync_execution_done (tui_on_sync_execution_done); observer_attach_command_error (tui_on_command_error); + observer_attach_user_selected_context_changed + (tui_on_user_selected_context_changed); } |