Don't show "display"s twice in MI

If you run "gdb -i=mi2" and set a "display", then when "next"ing the
displays will be shown twice:

    ~"1: x = 23\n"
    ~"7\t  printf(\"%d\\n\", x);\n"
    ~"1: x = 23\n"
    *stopped,reason="end-stepping-range",frame={addr="0x0000000000400565",func="main",args=[],file="q.c",fullname="/tmp/q.c",line="7"},thread-id="1",stopped-threads="all",core="1"

The immediate cause of this is this code in mi_on_normal_stop_1:

      print_stop_event (mi_uiout);

      console_interp = interp_lookup (current_ui, INTERP_CONSOLE);
      if (should_print_stop_to_console (console_interp, tp))
	print_stop_event (mi->cli_uiout);

... which obviously prints the stop twice.

However, I think the first call to print_stop_event is intended just
to emit the MI *stopped notification, which explains why the source
line does not show up two times.

This patch fixes the bug by changing print_stop_event to only call
do_displays for non-MI-like ui-outs.

Tested on x86-64 Fedora 29.

gdb/ChangeLog
2019-03-19  Tom Tromey  <tromey@adacore.com>

	* mi/mi-interp.c (mi_on_normal_stop_1): Only show displays once.
	* infrun.h (print_stop_event): Add "displays" parameter.
	* infrun.c (print_stop_event): Add "displays" parameter.

gdb/testsuite/ChangeLog
2019-03-19  Tom Tromey  <tromey@adacore.com>

	* gdb.mi/mi2-cli-display.c: New file.
	* gdb.mi/mi2-cli-display.exp: New file.
This commit is contained in:
Tom Tromey 2019-03-12 12:56:01 -06:00
parent cb24623460
commit 4c7d57e72e
7 changed files with 142 additions and 6 deletions

View File

@ -1,3 +1,9 @@
2019-03-19 Tom Tromey <tromey@adacore.com>
* mi/mi-interp.c (mi_on_normal_stop_1): Only show displays once.
* infrun.h (print_stop_event): Add "displays" parameter.
* infrun.c (print_stop_event): Add "displays" parameter.
2019-03-19 Pedro Alves <palves@redhat.com>
* tui/tui-out.c (tui_ui_out::do_field_string): Simplify.

View File

@ -7856,7 +7856,7 @@ print_stop_location (struct target_waitstatus *ws)
/* See infrun.h. */
void
print_stop_event (struct ui_out *uiout)
print_stop_event (struct ui_out *uiout, bool displays)
{
struct target_waitstatus last;
ptid_t last_ptid;
@ -7870,7 +7870,8 @@ print_stop_event (struct ui_out *uiout)
print_stop_location (&last);
/* Display the auto-display expressions. */
do_displays ();
if (displays)
do_displays ();
}
tp = inferior_thread ();

View File

@ -167,9 +167,10 @@ extern void print_return_value (struct ui_out *uiout,
/* Print current location without a level number, if we have changed
functions or hit a breakpoint. Print source line if we have one.
If the execution command captured a return value, print it. */
If the execution command captured a return value, print it. If
DISPLAYS is false, do not call 'do_displays'. */
extern void print_stop_event (struct ui_out *uiout);
extern void print_stop_event (struct ui_out *uiout, bool displays = true);
/* Pretty print the results of target_wait, for debugging purposes. */

View File

@ -625,10 +625,15 @@ mi_on_normal_stop_1 (struct bpstats *bs, int print_frame)
reason = tp->thread_fsm->async_reply_reason ();
mi_uiout->field_string ("reason", async_reason_lookup (reason));
}
print_stop_event (mi_uiout);
console_interp = interp_lookup (current_ui, INTERP_CONSOLE);
if (should_print_stop_to_console (console_interp, tp))
/* We only want to print the displays once, and we want it to
look just how it would on the console, so we use this to
decide whether the MI stop should include them. */
bool console_print = should_print_stop_to_console (console_interp, tp);
print_stop_event (mi_uiout, !console_print);
if (console_print)
print_stop_event (mi->cli_uiout);
mi_uiout->field_int ("thread-id", tp->global_num);

View File

@ -1,3 +1,8 @@
2019-03-19 Tom Tromey <tromey@adacore.com>
* gdb.mi/mi2-cli-display.c: New file.
* gdb.mi/mi2-cli-display.exp: New file.
2019-03-18 Joel Brobecker <brobecker@adacore.com>
Tom Tromey <tromey@adacore.com>

View File

@ -0,0 +1,32 @@
/* Copyright 2019 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
int
do_tests (int x)
{
++x;
++x;
++x;
++x;
return x;
}
int
main (void)
{
return do_tests (23);
}

View File

@ -0,0 +1,86 @@
# Copyright 2019 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Ensure that CLI "display"s aren't double-emitted in MI mode.
load_lib mi-support.exp
set MIFLAGS "-i=mi2"
if {[mi_gdb_start]} {
continue
}
standard_testfile
if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
untested "failed to compile"
return -1
}
mi_delete_breakpoints
mi_gdb_reinitialize_dir $srcdir/$subdir
mi_gdb_load ${binfile}
mi_runto do_tests
# A helper procedure that checks for the display and the line number,
# and the following *stopped. X is the expected value of "x" and is
# also used in test names.
proc check_cli_display {x show_source} {
global mi_gdb_prompt
# Now check for the display and the source line. We don't check
# the source line too closely, since it's not really important
# here, but we do check that the stop happened.
set stop "\\*stopped,reason=.*\r\n$mi_gdb_prompt$"
if {$show_source} {
set src "~\"\[0-9\]+\[^\"\]*\\\\n\"\r\n"
} else {
set src ""
}
set display "~\"1: x = $x\\\\n\"\r\n"
gdb_expect {
-re "^${display}${src}${display}${stop}" {
# This case is the bug: the display is shown twice.
fail "check display and source line x=$x"
}
-re "^${src}${display}${stop}" {
verbose -log "got <<<$expect_out(buffer)>>>"
pass "check display and source line x=$x"
}
-re ".*\r\n$mi_gdb_prompt$" {
verbose -log "got <<<$expect_out(buffer)>>>"
fail "check display and source line x=$x (unexpected output)"
}
timeout {
fail "check display and source line x=$x (timeout)"
}
}
}
mi_gdb_test "display x" \
"&\"display x\\\\n\"\r\n~\"1: x = 23\\\\n\"\r\n\\^done" \
"display x"
if {![mi_send_resuming_command "interpreter-exec console next" next]} {
pass "next"
}
check_cli_display 24 1
# Also check that displays are shown for -exec-next.
if {![mi_send_resuming_command exec-next exec-next]} {
pass "-exec-next"
}
check_cli_display 25 0