aboutsummaryrefslogtreecommitdiff
path: root/gdb/infrun.c
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2014-05-29 13:09:45 +0100
committerPedro Alves <palves@redhat.com>2014-05-29 13:09:45 +0100
commitfd664c91769bf7e31c3b4d64e41d05854eecd94a (patch)
tree1db5da8fcdfd99220446718632b9d1b499b2f38e /gdb/infrun.c
parent8817a6f225766029787b5e2c1300a342b328909e (diff)
downloadgdb-fd664c91769bf7e31c3b4d64e41d05854eecd94a.zip
gdb-fd664c91769bf7e31c3b4d64e41d05854eecd94a.tar.gz
gdb-fd664c91769bf7e31c3b4d64e41d05854eecd94a.tar.bz2
PR gdb/13860 - Make MI sync vs async output (closer to) the same.
Ignoring expected and desired differences like whether the prompt is output after *stoppped records, GDB MI output is still different in sync and async modes. In sync mode, when a CLI execution command is entered, the "reason" field is missing in the *stopped async record. And in async mode, for some events, like program exits, the corresponding CLI output is missing in the CLI channel. Vis, diff between sync vs async modes: run ^running *running,thread-id="1" (gdb) ... - ~"[Inferior 1 (process 15882) exited normally]\n" =thread-exited,id="1",group-id="i1" =thread-group-exited,id="i1",exit-code="0" - *stopped + *stopped,reason="exited-normally" si ... (gdb) ~"0x000000000045e033\t29\t memset (&args, 0, sizeof args);\n" - *stopped,frame=...,thread-id="1",stopped-threads="all",core="0" + *stopped,reason="end-stepping-range",frame=...,thread-id="1",stopped-threads="all",core="0" (gdb) In addition, in both cases, when a MI execution command is entered, and a breakpoint triggers, the event is sent to the console too. But some events like program exits have the CLI output missing in the CLI channel: -exec-run ^running *running,thread-id="1" (gdb) ... =thread-exited,id="1",group-id="i1" =thread-group-exited,id="i1",exit-code="0" - *stopped + *stopped,reason="exited-normally" We'll want to make background commands always possible by default. IOW, make target-async be the default. But, in order to do that, we'll need to emulate MI sync on top of an async target. That means we'll have yet another combination to care for in the testsuite. Rather than making the testsuite cope with all these differences, I thought it better to just fix GDB to always have the complete output, no matter whether it's in sync or async mode. This is all related to interpreter-exec, and the corresponding uiout switching. (Typing a CLI command directly in MI is shorthand for running it through -interpreter-exec console.) In sync mode, when a CLI command is active, normal_stop is called when the current interpreter and uiout are CLI's. So print_XXX_reason prints the stop reason to CLI uiout (only), and we don't show it in MI. In async mode the stop event is processed when we're back in the MI interpreter, so the stop reason is printed directly to the MI uiout. Fix this by making run control event printing roughly independent of whatever is the current interpreter or uiout. That is, move these prints to interpreter observers, that know whether to print or be quiet, and if printing, which uiout to print to. In the case of the console/tui interpreters, only print if the top interpreter. For MI, always print. Breakpoint hits / normal stops are already handled similarly -- MI has a normal_stop observer that prints the event to both MI and the CLI, though that could be cleaned up further in the direction of this patch. This also makes all of: (gdb) foo and (gdb) interpreter-exec MI "-exec-foo" and (gdb) -exec-foo and (gdb) -interpreter-exec console "foo" print as expected. Tested on x86_64 Fedora 20, sync and async modes. gdb/ 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. gdb/doc/ 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. gdb/testsuite/ 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.
Diffstat (limited to 'gdb/infrun.c')
-rw-r--r--gdb/infrun.c118
1 files changed, 55 insertions, 63 deletions
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 2068a2a..0b45c2d 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -88,15 +88,7 @@ static int currently_stepping (struct thread_info *tp);
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);
@@ -3540,7 +3532,7 @@ handle_inferior_event (struct execution_control_state *ecs)
/* 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
{
@@ -3569,7 +3561,7 @@ handle_inferior_event (struct execution_control_state *ecs)
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);
@@ -3837,7 +3829,7 @@ Cannot fill $_exitsignal with the correct signal number.\n"));
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;
}
@@ -4225,10 +4217,10 @@ handle_signal_stop (struct execution_control_state *ecs)
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
@@ -4472,7 +4464,7 @@ process_event_stop_test (struct execution_control_state *ecs)
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;
@@ -4637,7 +4629,7 @@ process_event_stop_test (struct execution_control_state *ecs)
&& execution_direction == EXEC_REVERSE)
{
ecs->event_thread->control.stop_step = 1;
- print_end_stepping_range_reason ();
+ end_stepping_range ();
stop_stepping (ecs);
}
else
@@ -4791,7 +4783,7 @@ process_event_stop_test (struct execution_control_state *ecs)
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;
}
@@ -4907,7 +4899,7 @@ process_event_stop_test (struct execution_control_state *ecs)
&& step_stop_if_no_debug)
{
ecs->event_thread->control.stop_step = 1;
- print_end_stepping_range_reason ();
+ end_stepping_range ();
stop_stepping (ecs);
return;
}
@@ -5003,7 +4995,7 @@ process_event_stop_test (struct execution_control_state *ecs)
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;
}
@@ -5024,7 +5016,7 @@ process_event_stop_test (struct execution_control_state *ecs)
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;
}
@@ -5038,7 +5030,7 @@ process_event_stop_test (struct execution_control_state *ecs)
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;
}
@@ -5071,7 +5063,7 @@ process_event_stop_test (struct execution_control_state *ecs)
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;
}
@@ -5086,7 +5078,7 @@ process_event_stop_test (struct execution_control_state *ecs)
else
{
ecs->event_thread->control.stop_step = 1;
- print_end_stepping_range_reason ();
+ end_stepping_range ();
stop_stepping (ecs);
}
return;
@@ -5113,7 +5105,7 @@ process_event_stop_test (struct execution_control_state *ecs)
else
{
ecs->event_thread->control.stop_step = 1;
- print_end_stepping_range_reason ();
+ end_stepping_range ();
stop_stepping (ecs);
}
return;
@@ -5131,7 +5123,7 @@ process_event_stop_test (struct execution_control_state *ecs)
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;
}
@@ -5457,7 +5449,7 @@ handle_step_into_function (struct gdbarch *gdbarch,
{
/* 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;
}
@@ -5506,7 +5498,7 @@ handle_step_into_function_backward (struct gdbarch *gdbarch,
{
/* 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
@@ -5906,35 +5898,46 @@ prepare_to_wait (struct execution_control_state *ecs)
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
@@ -5953,14 +5956,11 @@ print_signal_exited_reason (enum gdb_signal siggnal)
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)
@@ -5989,14 +5989,9 @@ print_exited_reason (int 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))
@@ -6028,13 +6023,10 @@ print_signal_received_reason (enum gdb_signal siggnal)
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