Fix MI output for multi-location breakpoints

New in v2:

- Addressed comments about doc, updated the MI version table
- New doc for the Breakpoint information format
- New -fix-multi-location-breakpoint-output command, with associated
  doc, test and NEWS updated accordingly
- Fixed the output, the locations list is now actually in the tuple
  representing the breakpoint.

Various MI commands or events related to breakpoints output invalid MI
records when printing information about a multi-location breakpoint.
For example:

    -break-insert allo
    ^done,bkpt={...,addr="<MULTIPLE>",...},{number="1.1",...},{number="1.2",...}

The problem is that according to the syntax [1], the top-level elements
are of type "result" and should be of the form "variable=value".

This patch changes the output to wrap the locations in a list:

    ^done,bkpt={...,addr="<MULTIPLE>",locations=[{number="1.1",...},{number="1.2",...}]}

The events =breakpoint-created, =breakpoint-modified, as well as the
-break-info command also suffer from this (and maybe others I didn't
find).

Since this is a breaking change for MI, we have to deal somehow with
backwards compatibility.  The approach taken by this patch is to bump
the MI version, use the new syntax in MI3 while retaining the old syntax
in MI2.  Frontends are expected to use a precise MI version (-i=mi2), so
if they do that they should be unaffected.

The patch also adds the command -fix-multi-location-breakpoint-output,
which front ends can use to enable this behavior with MI <= 2.

[1] https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Output-Syntax.html#GDB_002fMI-Output-Syntax

gdb/ChangeLog:

	* NEWS: Mention that the new default MI version is 3.  Mention
	changes to the output of commands and events that deal with
	multi-location breakpoints.
	* breakpoint.c: Include "mi/mi-out.h".
	(print_one_breakpoint): Change output syntax if using MI version
	>= 3.
	* mi/mi-main.h (mi_cmd_fix_multi_location_breakpoint_output):
	New.
	(mi_multi_location_breakpoint_output_fixed): New.
	* mi/mi-main.c (fix_multi_location_breakpoint_output): New.
	(mi_cmd_fix_multi_location_breakpoint_output): New.
	(mi_multi_location_breakpoint_output_fixed): New.
	* mi/mi-cmds.c (mi_cmds): Register command
	-fix-multi-location-breakpoint-output.
	* mi/mi-out.c (mi_out_new): Instantiate version 3 when using
	interpreter "mi".

gdb/testsuite/ChangeLog:

	* mi-breakpoint-location-ena-dis.exp: Rename to ...
	* mi-breakpoint-multiple-locations.exp: ... this.
	(make_breakpoints_pattern): New proc.
	(do_test): Add mi_version parameter, test -break-insert,
	-break-info and	=breakpoint-created.

gdb/doc/ChangeLog:

	* gdb.texinfo (Mode Options): Mention mi3.
	(Interpreters): Likewise.
	(GDB/MI Development and Front Ends): Add entry for MI 3 in
	version table.  Document -fix-multi-location-breakpoint-output.
	(GDB/MI Breakpoint Information): Document format of breakpoint
	location output.
This commit is contained in:
Simon Marchi 2019-03-13 15:13:03 -04:00 committed by Simon Marchi
parent 8e5e5494f8
commit b4be1b0648
13 changed files with 331 additions and 78 deletions

View file

@ -69,6 +69,7 @@
#include "thread-fsm.h"
#include "tid-parse.h"
#include "cli/cli-style.h"
#include "mi/mi-main.h"
/* readline include files */
#include "readline/readline.h"
@ -6361,12 +6362,15 @@ print_one_breakpoint (struct breakpoint *b,
int allflag)
{
struct ui_out *uiout = current_uiout;
bool use_fixed_output = mi_multi_location_breakpoint_output_fixed (uiout);
{
ui_out_emit_tuple tuple_emitter (uiout, "bkpt");
gdb::optional<ui_out_emit_tuple> bkpt_tuple_emitter (gdb::in_place, uiout, "bkpt");
print_one_breakpoint_location (b, NULL, 0, last_loc, allflag);
print_one_breakpoint_location (b, NULL, 0, last_loc, allflag);
}
/* The mi2 broken format: the main breakpoint tuple ends here, the locations
are outside. */
if (!use_fixed_output)
bkpt_tuple_emitter.reset ();
/* If this breakpoint has custom print function,
it's already printed. Otherwise, print individual
@ -6384,12 +6388,18 @@ print_one_breakpoint (struct breakpoint *b,
&& !is_hardware_watchpoint (b)
&& (b->loc->next || !b->loc->enabled))
{
struct bp_location *loc;
int n = 1;
gdb::optional<ui_out_emit_list> locations_list;
for (loc = b->loc; loc; loc = loc->next, ++n)
/* For MI version <= 2, keep the behavior where GDB outputs an invalid
MI record. For later versions, place breakpoint locations in a
list. */
if (uiout->is_mi_like_p () && use_fixed_output)
locations_list.emplace (uiout, "locations");
int n = 1;
for (bp_location *loc = b->loc; loc != NULL; loc = loc->next, ++n)
{
ui_out_emit_tuple tuple_emitter (uiout, NULL);
ui_out_emit_tuple loc_tuple_emitter (uiout, NULL);
print_one_breakpoint_location (b, loc, n, last_loc, allflag);
}
}