[RFA] fix *stopped for CLI commands

Vladimir Prus
2009-02-06T07:44:46Z

[-- Attachment #1: Type: text/plain, Size: 1225 bytes --]

In gdb 6.8, typing CLI commands in MI session does not produce either *running,
or ^running or *stopped messages. I've checked in some patches previous to
improve that, but *stopped turns out to be not finished yet -- when in non-async
mode, CLI commands such as 'continue' result in *stopped, but it has no frame
information.

The reason is that *stopped is printed by normal_stop observer, and the frame
information is printed by normal_stop function, in infrun.c. When a CLI command
is executed, we switch to the CLI interpreter and CLI uiout. In async mode,
the command execution is done, we switch back to MI uiout, and then we handle
stop event, so infrun.c:normal_stop prints frame into MI uiout and then MI observer
puts that data out. In sync mode, however, infrun.c:normal_stop is called when
the uiout is still CLI uiout, and then MI observer does not have any way to
access the fields printed into CLI uiout.

This patch fixes this by making MI observer print frame again, into MI uiout,
if necessary. It passes all MI tests in (sync,async)x(native,gdbserver) combinations.
How does this look, and are non-MI changes OK? If approved, I'll add a test that
CLI commands result in proper *stopped.

Thanks,
Volodya

[-- Attachment #2: stopped.diff --]
[-- Type: text/x-diff, Size: 8473 bytes --]

commit b9adf85d3252a9ed41c76bad645ca13af4efa027
Author: Vladimir Prus <vladimir@codesourcery.com>
Date: Fri Feb 6 10:39:17 2009 +0300

Include frame information for *stopped due to CLI commands.

gdb/doc/
* observer.texi: Add parameter 'print_frame' to normal_stop
observer.

* ada-tasks.c (ada_normal_stop_observer): Adjust prototype.
* infcmd.c (finish_command_continuation): Pass '1' for
'print_frame' parameter to the observer.
* infrun.c (normal_stop): Don't print mi-specific information
here. Pass 'stop_print_frame' to the 'print_frame' parameter
of the observer.
* mi/mi-interp.c (mi_on_normal_stop): Adjust prototype.
If we need to print frame, and current uiout is not the MI one,
print frame again.

gdb/testsuite/
* lib/mi-support.exp (mi_expect_stop): Adjust the order of fields.
(mi_expect_interrupt): Likewise.

diff --git a/gdb/ada-tasks.c b/gdb/ada-tasks.c
index 5176d75..3639472 100644
--- a/gdb/ada-tasks.c
+++ b/gdb/ada-tasks.c
@@ -951,7 +951,7 @@ ada_task_list_changed (void)
/* The 'normal_stop' observer notification callback. */

static void
-ada_normal_stop_observer (struct bpstats *unused_args)
+ada_normal_stop_observer (struct bpstats *unused_args, int unused_args2)
{
/* The inferior has been resumed, and just stopped. This means that
our task_list needs to be recomputed before it can be used again. */
diff --git a/gdb/doc/observer.texi b/gdb/doc/observer.texi
index 636658a..8327fea 100644
--- a/gdb/doc/observer.texi
+++ b/gdb/doc/observer.texi
@@ -88,7 +88,7 @@ Send a notification to all @var{event} observers.

The following observable events are defined:

-@deftypefun void normal_stop (struct bpstats *@var{bs})
+@deftypefun void normal_stop (struct bpstats *@var{bs}, int @var{print_frame})
The inferior has stopped for real.
@end deftypefun

diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 3696f79..188077c 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -1374,7 +1374,7 @@ finish_command_continuation (void *arg)
next stop will be in the same thread that we started doing a
finish on. This suppressing (or some other replacement means)
should be a thread property. */
- observer_notify_normal_stop (bs);
+ observer_notify_normal_stop (bs, 1 /* print frame */);
suppress_stop_observer = 0;
delete_breakpoint (a->breakpoint);
}
diff --git a/gdb/infrun.c b/gdb/infrun.c
index c11c71a..e50ef49 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -4351,22 +4351,6 @@ Further execution is probably impossible.\n"));
internal_error (__FILE__, __LINE__, _("Unknown value."));
}

- if (ui_out_is_mi_like_p (uiout))
- {
-
- ui_out_field_int (uiout, "thread-id",
- pid_to_thread_id (inferior_ptid));
- if (non_stop)
- {
- struct cleanup *back_to = make_cleanup_ui_out_list_begin_end
- (uiout, "stopped-threads");
- ui_out_field_int (uiout, NULL,
- pid_to_thread_id (inferior_ptid));
- do_cleanups (back_to);
- }
- else
- ui_out_field_string (uiout, "stopped-threads", "all");
- }
/* The behavior of this routine with respect to the source
flag is:
SRC_LINE: Print only source line
@@ -4421,9 +4405,10 @@ done:
&& inferior_thread ()->step_multi))
{
if (!ptid_equal (inferior_ptid, null_ptid))
- observer_notify_normal_stop (inferior_thread ()->stop_bpstat);
+ observer_notify_normal_stop (inferior_thread ()->stop_bpstat,
+ stop_print_frame);
else
- observer_notify_normal_stop (NULL);
+ observer_notify_normal_stop (NULL, stop_print_frame);
}

if (target_has_execution)
diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c
index 8e2b230..7f52549 100644
--- a/gdb/mi/mi-interp.c
+++ b/gdb/mi/mi-interp.c
@@ -52,7 +52,7 @@ static void mi1_command_loop (void);

static void mi_insert_notify_hooks (void);
static void mi_remove_notify_hooks (void);
-static void mi_on_normal_stop (struct bpstats *bs);
+static void mi_on_normal_stop (struct bpstats *bs, int print_frame);

static void mi_new_thread (struct thread_info *t);
static void mi_thread_exit (struct thread_info *t);
@@ -322,17 +322,46 @@ mi_inferior_exit (int pid)
}

static void
-mi_on_normal_stop (struct bpstats *bs)
+mi_on_normal_stop (struct bpstats *bs, int print_frame)
{
/* Since this can be called when CLI command is executing,
using cli interpreter, be sure to use MI uiout for output,
not the current one. */
- struct ui_out *uiout = interp_ui_out (top_level_interpreter ());
+ struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ());
struct mi_interp *mi = top_level_interpreter_data ();

+ if (print_frame)
+ {
+ if (uiout != mi_uiout)
+ {
+ /* The normal_stop function has printed frame information into
+ CLI uiout, or some other non-MI uiout. There's no way we
+ can extra proper fields from random uiout object, so we print
+ the frame again. In practice, this can only happen when running
+ a CLI command in MI. */
+ struct ui_out *saved_uiout = uiout;
+ uiout = mi_uiout;
+ print_stack_frame (get_selected_frame (NULL), 0, SRC_AND_LOC);
+ uiout = saved_uiout;
+ }
+
+ ui_out_field_int (mi_uiout, "thread-id",
+ pid_to_thread_id (inferior_ptid));
+ if (non_stop)
+ {
+ struct cleanup *back_to = make_cleanup_ui_out_list_begin_end
+ (mi_uiout, "stopped-threads");
+ ui_out_field_int (mi_uiout, NULL,
+ pid_to_thread_id (inferior_ptid));
+ do_cleanups (back_to);
+ }
+ else
+ ui_out_field_string (mi_uiout, "stopped-threads", "all");
+ }
+
fputs_unfiltered ("*stopped", raw_stdout);
- mi_out_put (uiout, raw_stdout);
- mi_out_rewind (uiout);
+ mi_out_put (mi_uiout, raw_stdout);
+ mi_out_rewind (mi_uiout);
fputs_unfiltered ("\n", raw_stdout);
gdb_flush (raw_stdout);
}
diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp
index be9b530..f62c240 100644
--- a/gdb/testsuite/lib/mi-support.exp
+++ b/gdb/testsuite/lib/mi-support.exp
@@ -1020,13 +1020,13 @@ proc mi_expect_stop { reason func args file line extra test } {

set any "\[^\n\]*"

- verbose -log "mi_expect_stop: expecting: \\*stopped,${r}${a}${bn}thread-id=\"$decimal\",stopped-threads=$any,frame=\{addr=\"$hex\",func=\"$func\",args=$args,file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"$line\"\}$after_stopped\r\n($thread_selected_re)?$prompt_re"
+ verbose -log "mi_expect_stop: expecting: \\*stopped,${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"$line\"\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re)?$prompt_re"
gdb_expect {
- -re "\\*stopped,${r}${a}${bn}thread-id=\"$decimal\",stopped-threads=$any,frame=\{addr=\"$hex\",func=\"$func\",args=$args,file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"($line)\"\}$after_stopped\r\n($thread_selected_re)?$prompt_re" {
+ -re "\\*stopped,${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"($line)\"\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re)?$prompt_re" {
pass "$test"
return $expect_out(2,string)
}
- -re "\\*stopped,${r}${a}${bn}thread-id=\"$decimal\",stopped-threads=$any,frame=\{addr=\"$hex\",func=\"$any\",args=\[\\\[\{\]$any\[\\\]\}\],file=\"$any\",fullname=\"${fullname_syntax}$any\",line=\"\[0-9\]*\"\}$any\r\n$prompt_re" {
+ -re "\\*stopped,${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$any\",args=\[\\\[\{\]$any\[\\\]\}\],file=\"$any\",fullname=\"${fullname_syntax}$any\",line=\"\[0-9\]*\"\}thread-id=\"$decimal\",stopped-threads=$any\r\n$prompt_re" {
verbose -log "got $expect_out(buffer)"
fail "$test (stopped at wrong place)"
return -1
@@ -1061,9 +1061,9 @@ proc mi_expect_interrupt { test } {
set any "\[^\n\]*"

# A signal can land anywhere, just ignore the location
- verbose -log "mi_expect_interrupt: expecting: \\*stopped,${r},thread-id=\"$decimal\",stopped-threads=$any\r\n$prompt_re"
+ verbose -log "mi_expect_interrupt: expecting: \\*stopped,${r}$any\r\n$prompt_re"
gdb_expect {
- -re "\\*stopped,${r},thread-id=\"$decimal\",stopped-threads=$any\r\n$prompt_re" {
+ -re "\\*stopped,${r}$any\r\n$prompt_re" {
pass "$test"
return 0;
}