+2014-05-29 Pedro Alves <palves@redhat.com>
+
+ PR gdb/13860
+ * cli/cli-interp.c: Include infrun.h and observer.h.
+ (cli_uiout, cli_interp): New globals.
+ (cli_on_signal_received, cli_on_end_stepping_range)
+ (cli_on_signal_exited, cli_on_exited, cli_on_no_history): New
+ functions.
+ (cli_interpreter_init): Install them as 'end_stepping_range',
+ 'signal_received' 'signal_exited', 'exited' and 'no_history'
+ observers.
+ (_initialize_cli_interp): Remove cli_interp local.
+ * infrun.c (handle_inferior_event): Call the several stop reason
+ observers instead of printing the stop reason directly.
+ (end_stepping_range): New function.
+ (print_end_stepping_range_reason, print_signal_exited_reason)
+ (print_exited_reason, print_signal_received_reason)
+ (print_no_history_reason): Make static, and add an uiout
+ parameter. Print to that instead of to CURRENT_UIOUT.
+ * infrun.h (print_end_stepping_range_reason)
+ (print_signal_exited_reason, print_exited_reason)
+ (print_signal_received_reason print_no_history_reason): New
+ declarations.
+ * mi/mi-common.h (struct mi_interp): Rename 'uiout' field to
+ 'mi_uiout'.
+ <cli_uiout>: New field.
+ * mi/mi-interp.c (mi_interpreter_init): Adjust. Create the new
+ uiout for CLI output. Install 'signal_received',
+ 'end_stepping_range', 'signal_exited', 'exited' and 'no_history'
+ observers.
+ (find_mi_interpreter, mi_interp_data, mi_on_signal_received)
+ (mi_on_end_stepping_range, mi_on_signal_exited, mi_on_exited)
+ (mi_on_no_history): New functions.
+ (ui_out_free_cleanup): Delete function.
+ (mi_on_normal_stop): Don't allocate a new uiout for CLI output,
+ instead use the one already stored in the MI interpreter data.
+ (mi_ui_out): Adjust.
+ * tui/tui-interp.c: Include infrun.h and observer.h.
+ (tui_interp): New global.
+ (tui_on_signal_received, tui_on_end_stepping_range)
+ (tui_on_signal_exited, tui_on_exited)
+ (tui_on_no_history): New functions.
+ (tui_init): Install them as 'end_stepping_range',
+ 'signal_received' 'signal_exited', 'exited' and 'no_history'
+ observers.
+ (_initialize_tui_interp): Delete tui_interp local.
+
2014-05-29 Pedro Alves <palves@redhat.com>
PR gdb/15713
#include "top.h" /* for "execute_command" */
#include <string.h>
#include "exceptions.h"
-
-struct ui_out *cli_uiout;
+#include "infrun.h"
+#include "observer.h"
/* These are the ui_out and the interpreter for the console
interpreter. */
+struct ui_out *cli_uiout;
+static struct interp *cli_interp;
/* Longjmp-safe wrapper for "execute_command". */
static struct gdb_exception safe_execute_command (struct ui_out *uiout,
char *command,
int from_tty);
+
+/* Observers for several run control events. If the interpreter is
+ quiet (i.e., another interpreter is being run with
+ interpreter-exec), print nothing. */
+
+/* Observer for the signal_received notification. */
+
+static void
+cli_on_signal_received (enum gdb_signal siggnal)
+{
+ if (!interp_quiet_p (cli_interp))
+ print_signal_received_reason (cli_uiout, siggnal);
+}
+
+/* Observer for the end_stepping_range notification. */
+
+static void
+cli_on_end_stepping_range (void)
+{
+ if (!interp_quiet_p (cli_interp))
+ print_end_stepping_range_reason (cli_uiout);
+}
+
+/* Observer for the signalled notification. */
+
+static void
+cli_on_signal_exited (enum gdb_signal siggnal)
+{
+ if (!interp_quiet_p (cli_interp))
+ print_signal_exited_reason (cli_uiout, siggnal);
+}
+
+/* Observer for the exited notification. */
+
+static void
+cli_on_exited (int exitstatus)
+{
+ if (!interp_quiet_p (cli_interp))
+ print_exited_reason (cli_uiout, exitstatus);
+}
+
+/* Observer for the no_history notification. */
+
+static void
+cli_on_no_history (void)
+{
+ if (!interp_quiet_p (cli_interp))
+ print_no_history_reason (cli_uiout);
+}
+
/* These implement the cli out interpreter: */
static void *
cli_interpreter_init (struct interp *self, int top_level)
{
+ /* If changing this, remember to update tui-interp.c as well. */
+ observer_attach_end_stepping_range (cli_on_end_stepping_range);
+ observer_attach_signal_received (cli_on_signal_received);
+ observer_attach_signal_exited (cli_on_signal_exited);
+ observer_attach_exited (cli_on_exited);
+ observer_attach_no_history (cli_on_no_history);
+
return NULL;
}
NULL, /* set_logging_proc */
cli_command_loop /* command_loop_proc */
};
- struct interp *cli_interp;
/* Create a default uiout builder for the CLI. */
cli_uiout = cli_out_new (gdb_stdout);
+2014-05-29 Pedro Alves <palves@redhat.com>
+
+ PR gdb/13860
+ * observer.texi (signal_received, end_stepping_range)
+ (signal_exited, exited, no_history): New observer subjects.
+
2014-05-26 Andy Wingo <wingo@igalia.com>
* guile.texi (GDB Scheme Data Types): Remove documentation for
inferior has stopped.
@end deftypefun
+@deftypefun void signal_received (enum gdb_signal @var{siggnal})
+The inferior was stopped by a signal.
+@end deftypefun
+
+@deftypefun void end_stepping_range (void)
+We are done with a step/next/si/ni command.
+@end deftypefun
+
+@deftypefun void signal_exited (enum gdb_signal @var{siggnal})
+The inferior was terminated by a signal.
+@end deftypefun
+
+@deftypefun void exited (int @var{exitstatus})
+The inferior program is finished.
+@end deftypefun
+
+@deftypefun void no_history (void)
+Reverse execution: target ran out of history info.
+@end deftypefun
+
@deftypefun void target_changed (struct target_ops *@var{target})
The target's register contents have changed.
@end deftypefun
static void xdb_handle_command (char *args, int from_tty);
-static void print_exited_reason (int exitstatus);
-
-static void print_signal_exited_reason (enum gdb_signal siggnal);
-
-static void print_no_history_reason (void);
-
-static void print_signal_received_reason (enum gdb_signal siggnal);
-
-static void print_end_stepping_range_reason (void);
+static void end_stepping_range (void);
void _initialize_infrun (void);
/* Support the --return-child-result option. */
return_child_result_value = ecs->ws.value.integer;
- print_exited_reason (ecs->ws.value.integer);
+ observer_notify_exited (ecs->ws.value.integer);
}
else
{
Cannot fill $_exitsignal with the correct signal number.\n"));
}
- print_signal_exited_reason (ecs->ws.value.sig);
+ observer_notify_signal_exited (ecs->ws.value.sig);
}
gdb_flush (gdb_stdout);
singlestep_breakpoints_inserted_p = 0;
}
stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));
- print_no_history_reason ();
+ observer_notify_no_history ();
stop_stepping (ecs);
return;
}
if (signal_print[ecs->event_thread->suspend.stop_signal])
{
+ /* The signal table tells us to print about this signal. */
printed = 1;
target_terminal_ours_for_output ();
- print_signal_received_reason
- (ecs->event_thread->suspend.stop_signal);
+ observer_notify_signal_received (ecs->event_thread->suspend.stop_signal);
}
/* Always stop on signals if we're either just gaining control
of the program, or the user explicitly requested this thread
delete_step_resume_breakpoint (ecs->event_thread);
ecs->event_thread->control.stop_step = 1;
- print_end_stepping_range_reason ();
+ end_stepping_range ();
stop_stepping (ecs);
}
return;
&& execution_direction == EXEC_REVERSE)
{
ecs->event_thread->control.stop_step = 1;
- print_end_stepping_range_reason ();
+ end_stepping_range ();
stop_stepping (ecs);
}
else
well. FENN */
/* And this works the same backward as frontward. MVS */
ecs->event_thread->control.stop_step = 1;
- print_end_stepping_range_reason ();
+ end_stepping_range ();
stop_stepping (ecs);
return;
}
&& step_stop_if_no_debug)
{
ecs->event_thread->control.stop_step = 1;
- print_end_stepping_range_reason ();
+ end_stepping_range ();
stop_stepping (ecs);
return;
}
is set, we stop the step so that the user has a chance to
switch in assembly mode. */
ecs->event_thread->control.stop_step = 1;
- print_end_stepping_range_reason ();
+ end_stepping_range ();
stop_stepping (ecs);
return;
}
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: stepi/nexti\n");
ecs->event_thread->control.stop_step = 1;
- print_end_stepping_range_reason ();
+ end_stepping_range ();
stop_stepping (ecs);
return;
}
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: no line number info\n");
ecs->event_thread->control.stop_step = 1;
- print_end_stepping_range_reason ();
+ end_stepping_range ();
stop_stepping (ecs);
return;
}
step_into_inline_frame (ecs->ptid);
ecs->event_thread->control.stop_step = 1;
- print_end_stepping_range_reason ();
+ end_stepping_range ();
stop_stepping (ecs);
return;
}
else
{
ecs->event_thread->control.stop_step = 1;
- print_end_stepping_range_reason ();
+ end_stepping_range ();
stop_stepping (ecs);
}
return;
else
{
ecs->event_thread->control.stop_step = 1;
- print_end_stepping_range_reason ();
+ end_stepping_range ();
stop_stepping (ecs);
}
return;
fprintf_unfiltered (gdb_stdlog,
"infrun: stepped to a different line\n");
ecs->event_thread->control.stop_step = 1;
- print_end_stepping_range_reason ();
+ end_stepping_range ();
stop_stepping (ecs);
return;
}
{
/* We are already there: stop now. */
ecs->event_thread->control.stop_step = 1;
- print_end_stepping_range_reason ();
+ end_stepping_range ();
stop_stepping (ecs);
return;
}
{
/* We're there already. Just stop stepping now. */
ecs->event_thread->control.stop_step = 1;
- print_end_stepping_range_reason ();
+ end_stepping_range ();
stop_stepping (ecs);
}
else
ecs->wait_some_more = 1;
}
+/* We are done with the step range of a step/next/si/ni command.
+ Called once for each n of a "step n" operation. Notify observers
+ if not in the middle of doing a "step N" operation for N > 1. */
+
+static void
+end_stepping_range (void)
+{
+ if (inferior_thread ()->step_multi
+ && inferior_thread ()->control.stop_step)
+ return;
+
+ observer_notify_end_stepping_range ();
+}
+
/* Several print_*_reason functions to print why the inferior has stopped.
We always print something when the inferior exits, or receives a signal.
The rest of the cases are dealt with later on in normal_stop and
print_it_typical. Ideally there should be a call to one of these
print_*_reason functions functions from handle_inferior_event each time
- stop_stepping is called. */
+ stop_stepping is called.
-/* Print why the inferior has stopped.
- We are done with a step/next/si/ni command, print why the inferior has
- stopped. For now print nothing. Print a message only if not in the middle
- of doing a "step n" operation for n > 1. */
+ Note that we don't call these directly, instead we delegate that to
+ the interpreters, through observers. Interpreters then call these
+ with whatever uiout is right. */
-static void
-print_end_stepping_range_reason (void)
+void
+print_end_stepping_range_reason (struct ui_out *uiout)
{
- if ((!inferior_thread ()->step_multi
- || !inferior_thread ()->control.stop_step)
- && ui_out_is_mi_like_p (current_uiout))
- ui_out_field_string (current_uiout, "reason",
- async_reason_lookup (EXEC_ASYNC_END_STEPPING_RANGE));
-}
+ /* For CLI-like interpreters, print nothing. */
-/* The inferior was terminated by a signal, print why it stopped. */
+ if (ui_out_is_mi_like_p (uiout))
+ {
+ ui_out_field_string (uiout, "reason",
+ async_reason_lookup (EXEC_ASYNC_END_STEPPING_RANGE));
+ }
+}
-static void
-print_signal_exited_reason (enum gdb_signal siggnal)
+void
+print_signal_exited_reason (struct ui_out *uiout, enum gdb_signal siggnal)
{
- struct ui_out *uiout = current_uiout;
-
annotate_signalled ();
if (ui_out_is_mi_like_p (uiout))
ui_out_field_string
ui_out_text (uiout, "The program no longer exists.\n");
}
-/* The inferior program is finished, print why it stopped. */
-
-static void
-print_exited_reason (int exitstatus)
+void
+print_exited_reason (struct ui_out *uiout, int exitstatus)
{
struct inferior *inf = current_inferior ();
const char *pidstr = target_pid_to_str (pid_to_ptid (inf->pid));
- struct ui_out *uiout = current_uiout;
annotate_exited (exitstatus);
if (exitstatus)
}
}
-/* Signal received, print why the inferior has stopped. The signal table
- tells us to print about it. */
-
-static void
-print_signal_received_reason (enum gdb_signal siggnal)
+void
+print_signal_received_reason (struct ui_out *uiout, enum gdb_signal siggnal)
{
- struct ui_out *uiout = current_uiout;
-
annotate_signal ();
if (siggnal == GDB_SIGNAL_0 && !ui_out_is_mi_like_p (uiout))
ui_out_text (uiout, ".\n");
}
-/* Reverse execution: target ran out of history info, print why the inferior
- has stopped. */
-
-static void
-print_no_history_reason (void)
+void
+print_no_history_reason (struct ui_out *uiout)
{
- ui_out_text (current_uiout, "\nNo more reverse-execution history.\n");
+ ui_out_text (uiout, "\nNo more reverse-execution history.\n");
}
/* Print current location without a level number, if we have changed
extern void set_step_info (struct frame_info *frame,
struct symtab_and_line sal);
+/* Several print_*_reason helper functions to print why the inferior
+ has stopped to the passed in UIOUT. */
+
+/* Signal received, print why the inferior has stopped. */
+extern void print_signal_received_reason (struct ui_out *uiout,
+ enum gdb_signal siggnal);
+
+/* Print why the inferior has stopped. We are done with a
+ step/next/si/ni command, print why the inferior has stopped. */
+extern void print_end_stepping_range_reason (struct ui_out *uiout);
+
+/* The inferior was terminated by a signal, print why it stopped. */
+extern void print_signal_exited_reason (struct ui_out *uiout,
+ enum gdb_signal siggnal);
+
+/* The inferior program is finished, print why it stopped. */
+extern void print_exited_reason (struct ui_out *uiout, int exitstatus);
+
+/* Reverse execution: target ran out of history info, print why the
+ inferior has stopped. */
+extern void print_no_history_reason (struct ui_out *uiout);
+
extern void print_stop_event (struct target_waitstatus *ws);
extern int signal_stop_state (int);
struct ui_file *event_channel;
/* MI's builder. */
- struct ui_out *uiout;
+ struct ui_out *mi_uiout;
+
+ /* MI's CLI builder (wraps OUT). */
+ struct ui_out *cli_uiout;
/* This is the interpreter for the mi... */
struct interp *mi2_interp;
static void mi_insert_notify_hooks (void);
static void mi_remove_notify_hooks (void);
+
+static void mi_on_signal_received (enum gdb_signal siggnal);
+static void mi_on_end_stepping_range (void);
+static void mi_on_signal_exited (enum gdb_signal siggnal);
+static void mi_on_exited (int exitstatus);
static void mi_on_normal_stop (struct bpstats *bs, int print_frame);
+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);
else
gdb_assert_not_reached ("unhandled MI version");
- mi->uiout = mi_out_new (mi_version);
+ 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)
{
current_uiout = saved_uiout;
}
-/* Cleanup that destroys the a ui_out object. */
+/* 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)
+{
+ 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;
+}
+
+/* Return the MI_INTERP structure of the active MI interpreter.
+ Returns NULL if MI is not active. */
+
+static struct mi_interp *
+mi_interp_data (void)
+{
+ struct interp *interp = find_mi_interpreter ();
+
+ if (interp != NULL)
+ return interp_data (interp);
+ return NULL;
+}
+
+/* Observers for several run control events that print why the
+ inferior has stopped to both the the MI event channel and to the MI
+ console. If the MI interpreter is not active, print nothing. */
+
+/* Observer for the signal_received notification. */
+
+static void
+mi_on_signal_received (enum gdb_signal siggnal)
+{
+ struct mi_interp *mi = mi_interp_data ();
+
+ if (mi == NULL)
+ return;
+
+ print_signal_received_reason (mi->mi_uiout, siggnal);
+ print_signal_received_reason (mi->cli_uiout, siggnal);
+}
+
+/* Observer for the end_stepping_range notification. */
+
+static void
+mi_on_end_stepping_range (void)
+{
+ struct mi_interp *mi = mi_interp_data ();
+
+ if (mi == NULL)
+ return;
+
+ print_end_stepping_range_reason (mi->mi_uiout);
+ print_end_stepping_range_reason (mi->cli_uiout);
+}
+
+/* Observer for the signal_exited notification. */
static void
-ui_out_free_cleanup (void *arg)
+mi_on_signal_exited (enum gdb_signal siggnal)
{
- struct ui_out *uiout = arg;
+ struct mi_interp *mi = mi_interp_data ();
- ui_out_destroy (uiout);
+ if (mi == NULL)
+ return;
+
+ print_signal_exited_reason (mi->mi_uiout, siggnal);
+ print_signal_exited_reason (mi->cli_uiout, siggnal);
+}
+
+/* Observer for the exited notification. */
+
+static void
+mi_on_exited (int exitstatus)
+{
+ struct mi_interp *mi = mi_interp_data ();
+
+ if (mi == NULL)
+ return;
+
+ print_exited_reason (mi->mi_uiout, exitstatus);
+ print_exited_reason (mi->cli_uiout, exitstatus);
+}
+
+/* Observer for the no_history notification. */
+
+static void
+mi_on_no_history (void)
+{
+ struct mi_interp *mi = mi_interp_data ();
+
+ if (mi == NULL)
+ return;
+
+ print_no_history_reason (mi->mi_uiout);
+ print_no_history_reason (mi->cli_uiout);
}
static void
struct mi_interp *mi = top_level_interpreter_data ();
struct target_waitstatus last;
ptid_t last_ptid;
- struct ui_out *cli_uiout;
struct cleanup *old_chain;
- /* Sets the current uiout to a new temporary CLI uiout
- assigned to STREAM. */
- cli_uiout = cli_out_new (mi->out);
- old_chain = make_cleanup (ui_out_free_cleanup, cli_uiout);
-
- make_cleanup (restore_current_uiout_cleanup, current_uiout);
- current_uiout = cli_uiout;
+ /* Set the current uiout to CLI uiout temporarily. */
+ old_chain = make_cleanup (restore_current_uiout_cleanup,
+ current_uiout);
+ current_uiout = mi->cli_uiout;
get_last_target_status (&last_ptid, &last);
print_stop_event (&last);
{
struct mi_interp *mi = interp_data (interp);
- return mi->uiout;
+ return mi->mi_uiout;
}
/* Save the original value of raw_stdout here when logging, so we can
+2014-05-29 Pedro Alves <palves@redhat.com>
+
+ PR gdb/13860
+ * gdb.mi/mi-cli.exp: Always expect "end-stepping-range" stop
+ reason, even in sync mode.
+
2014-05-29 Pedro Alves <palves@redhat.com>
Hui Zhu <hui@codesourcery.com>
{500\^done} \
"-stack-select-frame 0"
-# When a CLI command is entered in MI session, the respose is different in
-# sync and async modes. In sync mode normal_stop is called when current
-# interpreter is CLI. So:
-# - print_stop_reason prints stop reason in CLI uiout, and we don't show it
-# in MI
-# - The stop position is printed, and appears in MI 'console' channel.
-#
-# In async mode the stop event is processed when we're back to MI interpreter,
-# so the stop reason is printed into MI uiout an.
-if {$async} {
- set reason "end-stepping-range"
-} else {
- set reason ""
-}
-
-mi_execute_to "interpreter-exec console step" $reason "callee4" "" ".*basics.c" $line_callee4_next \
+mi_execute_to "interpreter-exec console step" "end-stepping-range" "callee4" "" ".*basics.c" $line_callee4_next \
"" "check *stopped from CLI command"
mi_send_resuming_command "exec-step" "-exec-step to line \$line_callee4_next_step"
}
}
-# Note that the output does not include stop reason. This is fine.
-# The purpose of *stopped notification for CLI command is to make
-# sure that frontend knows that inferior is stopped, and knows where.
-# Supplementary information is not necessary.
-mi_expect_stop "$reason" "main" "" ".*basics.c" $line_main_return "" \
+mi_expect_stop "end-stepping-range" "main" "" ".*basics.c" $line_main_return "" \
"34 next: stop"
mi_gdb_test "-interpreter-exec console \"list\"" \
#include "tui/tui.h"
#include "tui/tui-io.h"
#include "exceptions.h"
+#include "infrun.h"
+#include "observer.h"
+
+static struct ui_out *tui_ui_out (struct interp *self);
/* Set to 1 when the TUI mode must be activated when we first start
gdb. */
static int tui_start_enabled = 0;
+/* The TUI interpreter. */
+static struct interp *tui_interp;
+
/* Cleanup the tui before exiting. */
static void
/* True if TUI is the top-level interpreter. */
static int tui_is_toplevel = 0;
+/* Observers for several run control events. If the interpreter is
+ quiet (i.e., another interpreter is being run with
+ interpreter-exec), print nothing. */
+
+/* Observer for the signal_received notification. */
+
+static void
+tui_on_signal_received (enum gdb_signal siggnal)
+{
+ if (!interp_quiet_p (tui_interp))
+ print_signal_received_reason (tui_ui_out (tui_interp), siggnal);
+}
+
+/* Observer for the end_stepping_range notification. */
+
+static void
+tui_on_end_stepping_range (void)
+{
+ if (!interp_quiet_p (tui_interp))
+ print_end_stepping_range_reason (tui_ui_out (tui_interp));
+}
+
+/* Observer for the signal_exited notification. */
+
+static void
+tui_on_signal_exited (enum gdb_signal siggnal)
+{
+ if (!interp_quiet_p (tui_interp))
+ print_signal_exited_reason (tui_ui_out (tui_interp), siggnal);
+}
+
+/* Observer for the exited notification. */
+
+static void
+tui_on_exited (int exitstatus)
+{
+ if (!interp_quiet_p (tui_interp))
+ print_exited_reason (tui_ui_out (tui_interp), exitstatus);
+}
+
+/* Observer for the no_history notification. */
+
+static void
+tui_on_no_history (void)
+{
+ if (!interp_quiet_p (tui_interp))
+ print_no_history_reason (tui_ui_out (tui_interp));
+}
+
/* These implement the TUI interpreter. */
static void *
if (ui_file_isatty (gdb_stdout))
tui_initialize_readline ();
+ /* If changing this, remember to update cli-interp.c as well. */
+ observer_attach_signal_received (tui_on_signal_received);
+ observer_attach_end_stepping_range (tui_on_end_stepping_range);
+ observer_attach_signal_exited (tui_on_signal_exited);
+ observer_attach_exited (tui_on_exited);
+ observer_attach_no_history (tui_on_no_history);
+
return NULL;
}
NULL,
cli_command_loop
};
- struct interp *tui_interp;
/* Create a default uiout builder for the TUI. */
tui_interp = interp_new (INTERP_TUI, &procs);