Add MI "-break-insert --qualified"

Message ID 20200901180703.20045-1-pedro@palves.net
State New
Headers show
Series
  • Add MI "-break-insert --qualified"
Related show

Commit Message

Pedro Alves Sept. 1, 2020, 6:07 p.m.
Currently -break-insert always creates a wildmatching breakpoint, and
there's no way to ask for a fullname match.  To address that, this
patch adds the equivalent of "break -qualified" to MI:

  "-break-insert --qualified".

For the testcase, curiously, it doesn't look like we have _any_
testcase that tests a breakpoint with multiple locations, and, the
existing mi_create_breakpoint / mi_make_breakpoint procedures are only
good for breakpoints with a single location.  This patch thus adds a
few new companion routines to mi-support.exp for breakpoints with
multiple locations: mi_create_breakpoint_multi,
mi_make_breakpoint_loc, mi_make_breakpoint_multi.

gdb/ChangeLog:

	* mi/mi-cmd-break.c (mi_cmd_break_insert_1): Handle "--qualified".

gdb/doc/ChangeLog:

	* gdb.texinfo (GDB/MI Breakpoint Commands): Document
	"-break-insert --qualified" and "-dprintf-insert --qualified".

gdb/testsuite/ChangeLog:

	* NEWS: Document "-break-insert --qualified".
	* gdb.mi/mi-break-qualified.cc: New file.
	* gdb.mi/mi-break-qualified.exp: New file.
	* lib/mi-support.exp (mi_create_breakpoint_multi)
	(mi_make_breakpoint_loc, mi_make_breakpoint_multi): New
	procedures.
	(mi_create_breakpoint_1): New, factored out from
	mi_create_breakpoint.
---
 gdb/NEWS                                    |  10 +++
 gdb/doc/gdb.texinfo                         |  12 ++-
 gdb/mi/mi-cmd-break.c                       |  10 ++-
 gdb/testsuite/gdb.mi/mi-break-qualified.cc  |  53 +++++++++++
 gdb/testsuite/gdb.mi/mi-break-qualified.exp | 106 ++++++++++++++++++++++
 gdb/testsuite/lib/mi-support.exp            | 135 +++++++++++++++++++++++-----
 6 files changed, 300 insertions(+), 26 deletions(-)
 create mode 100644 gdb/testsuite/gdb.mi/mi-break-qualified.cc
 create mode 100644 gdb/testsuite/gdb.mi/mi-break-qualified.exp


base-commit: 4c8584be76a2b95cd4876ac8622cb0f2d0fc1ad4
-- 
2.14.5

Comments

Eli Zaretskii Sept. 1, 2020, 6:13 p.m. | #1
> From: Pedro Alves <pedro@palves.net>

> Date: Tue,  1 Sep 2020 19:07:03 +0100

> 

> gdb/ChangeLog:

> 

> 	* mi/mi-cmd-break.c (mi_cmd_break_insert_1): Handle "--qualified".

> 

> gdb/doc/ChangeLog:

> 

> 	* gdb.texinfo (GDB/MI Breakpoint Commands): Document

> 	"-break-insert --qualified" and "-dprintf-insert --qualified".

> 

> gdb/testsuite/ChangeLog:

> 

> 	* NEWS: Document "-break-insert --qualified".

> 	* gdb.mi/mi-break-qualified.cc: New file.

> 	* gdb.mi/mi-break-qualified.exp: New file.

> 	* lib/mi-support.exp (mi_create_breakpoint_multi)

> 	(mi_make_breakpoint_loc, mi_make_breakpoint_multi): New

> 	procedures.

> 	(mi_create_breakpoint_1): New, factored out from

> 	mi_create_breakpoint.


Thanks, the documentation parts are OK.
Simon Marchi Sept. 2, 2020, 6:35 p.m. | #2
On 2020-09-01 2:07 p.m., Pedro Alves wrote:
> Currently -break-insert always creates a wildmatching breakpoint, and

> there's no way to ask for a fullname match.  To address that, this

> patch adds the equivalent of "break -qualified" to MI:

> 

>   "-break-insert --qualified".

> 

> For the testcase, curiously, it doesn't look like we have _any_

> testcase that tests a breakpoint with multiple locations, and, the

> existing mi_create_breakpoint / mi_make_breakpoint procedures are only

> good for breakpoints with a single location.  This patch thus adds a

> few new companion routines to mi-support.exp for breakpoints with

> multiple locations: mi_create_breakpoint_multi,

> mi_make_breakpoint_loc, mi_make_breakpoint_multi.


The code looks good to me.

Thanks,

Simon
Pedro Alves Sept. 13, 2020, 5:13 p.m. | #3
On 9/2/20 7:35 PM, Simon Marchi wrote:
> On 2020-09-01 2:07 p.m., Pedro Alves wrote:

>> Currently -break-insert always creates a wildmatching breakpoint, and

>> there's no way to ask for a fullname match.  To address that, this

>> patch adds the equivalent of "break -qualified" to MI:

>>

>>   "-break-insert --qualified".

>>

>> For the testcase, curiously, it doesn't look like we have _any_

>> testcase that tests a breakpoint with multiple locations, and, the

>> existing mi_create_breakpoint / mi_make_breakpoint procedures are only

>> good for breakpoints with a single location.  This patch thus adds a

>> few new companion routines to mi-support.exp for breakpoints with

>> multiple locations: mi_create_breakpoint_multi,

>> mi_make_breakpoint_loc, mi_make_breakpoint_multi.

> 

> The code looks good to me.

> 


Thank you both.

I've merged this now, with NEWS entry moved to the new
"Changes since GDB 10" section.

Pedro Alves

Patch

diff --git a/gdb/NEWS b/gdb/NEWS
index 45bd23526d6..edf1a45629a 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -165,6 +165,16 @@  BPF				bpf-unknown-none
      using Guile 2.2 and later, users who need to control the size of
      a memory port's internal buffer can use the 'setvbuf' procedure.
 
+* MI changes
+
+ ** '-break-insert --qualified' and '-dprintf-insert --qualified'
+
+    The MI -break-insert and -dprintf-insert commands now support a
+    new "--qualified" option that makes GDB interpret a specified
+    function name as a complete fully-qualified name.  This is the
+    equivalent of the CLI's "break -qualified" and "dprintf
+    -qualified".
+
 *** Changes in GDB 9
 
 * 'thread-exited' event is now available in the annotations interface.
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 77c5d895053..8bff27c940d 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -30180,7 +30180,7 @@  N.A.
 @subsubheading Synopsis
 
 @smallexample
- -break-insert [ -t ] [ -h ] [ -f ] [ -d ] [ -a ]
+ -break-insert [ -t ] [ -h ] [ -f ] [ -d ] [ -a ] [ --qualified ]
     [ -c @var{condition} ] [ -i @var{ignore-count} ]
     [ -p @var{thread-id} ] [ @var{location} ]
 @end smallexample
@@ -30242,6 +30242,9 @@  Initialize the @var{ignore-count}.
 @item -p @var{thread-id}
 Restrict the breakpoint to the thread with the specified global
 @var{thread-id}.
+@item --qualified
+This option makes @value{GDBN} interpret a function name specified as
+a complete fully-qualified name.
 @end table
 
 @subsubheading Result
@@ -30302,15 +30305,16 @@  times="0"@}]@}
 @subsubheading Synopsis
 
 @smallexample
- -dprintf-insert [ -t ] [ -f ] [ -d ]
+ -dprintf-insert [ -t ] [ -f ] [ -d ] [ --qualified ]
     [ -c @var{condition} ] [ -i @var{ignore-count} ]
     [ -p @var{thread-id} ] [ @var{location} ] [ @var{format} ]
     [ @var{argument} ]
 @end smallexample
 
 @noindent
-If supplied, @var{location} may be specified the same way as for
-the @code{-break-insert} command.  @xref{-break-insert}.
+If supplied, @var{location} and @code{--qualified} may be specified
+the same way as for the @code{-break-insert} command.
+@xref{-break-insert}.
 
 The possible optional parameters of this command are:
 
diff --git a/gdb/mi/mi-cmd-break.c b/gdb/mi/mi-cmd-break.c
index 417f2d82dd3..3835c02650d 100644
--- a/gdb/mi/mi-cmd-break.c
+++ b/gdb/mi/mi-cmd-break.c
@@ -176,6 +176,7 @@  mi_cmd_break_insert_1 (int dprintf, const char *command, char **argv, int argc)
   int pending = 0;
   int enabled = 1;
   int tracepoint = 0;
+  symbol_name_match_type match_type = symbol_name_match_type::WILD;
   enum bptype type_wanted;
   event_location_up location;
   struct breakpoint_ops *ops;
@@ -188,6 +189,7 @@  mi_cmd_break_insert_1 (int dprintf, const char *command, char **argv, int argc)
       HARDWARE_OPT, TEMP_OPT, CONDITION_OPT,
       IGNORE_COUNT_OPT, THREAD_OPT, PENDING_OPT, DISABLE_OPT,
       TRACEPOINT_OPT,
+      QUALIFIED_OPT,
       EXPLICIT_SOURCE_OPT, EXPLICIT_FUNC_OPT,
       EXPLICIT_LABEL_OPT, EXPLICIT_LINE_OPT
     };
@@ -201,6 +203,7 @@  mi_cmd_break_insert_1 (int dprintf, const char *command, char **argv, int argc)
     {"f", PENDING_OPT, 0},
     {"d", DISABLE_OPT, 0},
     {"a", TRACEPOINT_OPT, 0},
+    {"-qualified", QUALIFIED_OPT, 0},
     {"-source" , EXPLICIT_SOURCE_OPT, 1},
     {"-function", EXPLICIT_FUNC_OPT, 1},
     {"-label", EXPLICIT_LABEL_OPT, 1},
@@ -247,6 +250,9 @@  mi_cmd_break_insert_1 (int dprintf, const char *command, char **argv, int argc)
 	case TRACEPOINT_OPT:
 	  tracepoint = 1;
 	  break;
+	case QUALIFIED_OPT:
+	  match_type = symbol_name_match_type::FULL;
+	  break;
 	case EXPLICIT_SOURCE_OPT:
 	  is_explicit = 1;
 	  explicit_loc.source_filename = oarg;
@@ -333,12 +339,14 @@  mi_cmd_break_insert_1 (int dprintf, const char *command, char **argv, int argc)
 	error (_("-%s-insert: --source option requires --function, --label,"
 		 " or --line"), dprintf ? "dprintf" : "break");
 
+      explicit_loc.func_name_match_type = match_type;
+
       location = new_explicit_location (&explicit_loc);
     }
   else
     {
       location = string_to_event_location_basic (&address, current_language,
-						 symbol_name_match_type::WILD);
+						 match_type);
       if (*address)
 	error (_("Garbage '%s' at end of location"), address);
     }
diff --git a/gdb/testsuite/gdb.mi/mi-break-qualified.cc b/gdb/testsuite/gdb.mi/mi-break-qualified.cc
new file mode 100644
index 00000000000..d4e27034faa
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-break-qualified.cc
@@ -0,0 +1,53 @@ 
+/* Copyright 2020 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/>.  */
+
+namespace NS {
+
+int
+func (int i)
+{
+  return i; /* location NS::func here */
+}
+
+} /* namespace NS */
+
+struct foo
+{
+  long func (long l);
+};
+
+long
+foo::func (long l)
+{
+  return l; /* location foo::func here */
+}
+
+char
+func (char c)
+{
+  return c; /* location func here */
+}
+
+int
+main ()
+{
+  foo f;
+  f.func (1);
+  NS::func (2);
+  func (3);
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.mi/mi-break-qualified.exp b/gdb/testsuite/gdb.mi/mi-break-qualified.exp
new file mode 100644
index 00000000000..adbc3b5eb01
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-break-qualified.exp
@@ -0,0 +1,106 @@ 
+# Copyright 2020 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/>.
+
+# Test '-break-insert --qualified' and C++ wildmatching.
+#
+# The goal is not to test GDB functionality, which is done by other
+# tests, but to verify the correct output response to MI operations.
+
+load_lib mi-support.exp
+set MIFLAGS "-i=mi"
+
+standard_testfile .cc
+
+if {[build_executable $testfile.exp $testfile $srcfile {c++ debug}] == -1} {
+     untested "failed to compile"
+     return -1
+}
+
+set loc_ns_func_line [gdb_get_line_number "location NS::func here"]
+set loc_foo_func_line [gdb_get_line_number "location foo::func here"]
+set loc_func_line [gdb_get_line_number "location func here"]
+
+proc test_break_qualified {} {
+    global hex
+    global loc_ns_func_line loc_foo_func_line loc_func_line
+
+    # We have three functions called "func" in the program.  Check
+    # that --qualified only picks the one explicitly specified.
+
+    set bps {}
+    set test "--qualified func"
+    lappend bps [mi_create_breakpoint $test $test \
+		     -func "func\\(char\\)" \
+		     -file ".*mi-break-qualified.cc" \
+		     -line $loc_func_line]
+
+    set test "--qualified NS::func"
+    lappend bps [mi_create_breakpoint $test $test \
+		     -func "NS::func\\(int\\)" \
+		     -file ".*mi-break-qualified.cc" \
+		     -line $loc_ns_func_line]
+
+    set test "--qualified foo::func"
+    lappend bps [mi_create_breakpoint $test $test \
+		     -func "foo::func\\(long\\)" \
+		     -file ".*mi-break-qualified.cc" \
+		     -line $loc_foo_func_line]
+
+    # Also check that without --qualified, we get a breakpoint with a
+    # location for each of the functions called "func" in the program.
+
+    # Small helper wrapper around mi_make_breakpoint_loc.
+    proc make_loc_re {func line_no} {
+	global hex
+
+	return [mi_make_breakpoint_loc \
+		  -enabled "y" \
+		  -func "$func" \
+		  -file ".*mi-break-qualified.cc" \
+		  -line="$line_no"]
+    }
+
+    set loc1 [make_loc_re "NS::func\\(int\\)" $loc_ns_func_line]
+    set loc2 [make_loc_re "foo::func\\(long\\)" $loc_foo_func_line]
+    set loc3 [make_loc_re "func\\(char\\)" $loc_func_line]
+
+    set test "func"
+    set bp [mi_create_breakpoint_multi $test $test \
+		-original-location "func" \
+		-locations "\\\[$loc1,$loc2,$loc3\\\]"]
+
+    lappend bps $bp
+
+    # List the breakpoints.
+    mi_gdb_test "666-break-list" \
+	"666\\\^done,[mi_make_breakpoint_table $bps]" \
+	"list of breakpoints"
+
+    mi_gdb_test "777-break-delete" \
+	    "777\\^done" \
+	    "delete temp breakpoints"
+}
+
+mi_gdb_exit
+
+if [mi_gdb_start ""] {
+    return
+}
+
+mi_delete_breakpoints
+mi_gdb_reinitialize_dir $srcdir/$subdir
+mi_gdb_load ${binfile}
+
+test_break_qualified
diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp
index 1e59919ab47..19e49e8ae71 100644
--- a/gdb/testsuite/lib/mi-support.exp
+++ b/gdb/testsuite/lib/mi-support.exp
@@ -1376,6 +1376,15 @@  proc mi_create_breakpoint {location test args} {
     return $bp
 }
 
+# Like mi_create_breakpoint, but creates a breakpoint with multiple
+# locations using mi_make_breakpoint_multi instead.
+
+proc mi_create_breakpoint_multi {location test args} {
+    set bp [eval mi_make_breakpoint_multi $args]
+    mi_gdb_test "222-break-insert $location" "222\\^done,$bp" $test
+    return $bp
+}
+
 # Creates varobj named NAME for EXPRESSION.
 # Name cannot be "-".
 proc mi_create_varobj { name expression testname } {
@@ -2477,36 +2486,39 @@  proc mi_build_kv_pairs {attr_list {joiner ,}} {
     return "[join $l $joiner]"
 }
 
-# Construct a breakpoint regexp.  This may be used to test the output of
-# -break-insert, -dprintf-insert, or -break-info.
+# Construct a breakpoint location regexp.  This may be used along with
+# mi_make_breakpoint_multi to test the output of -break-insert,
+# -dprintf-insert, or -break-info with breapoints with multiple
+# locations.
 #
-# All arguments for the breakpoint may be specified using the options
-# number, type, disp, enabled, addr, func, file, fullanme, line,
-# thread-groups, cond, evaluated-by, times, ignore, script,
-# and original-location.
+# All arguments for the breakpoint location may be specified using the
+# options number, enabled, addr, func, file, fullname, line and
+# thread-groups.
 #
-# Only if -script and -ignore are given will they appear in the output.
-# Otherwise, this procedure will skip them using ".*".
-#
-# Example: mi_make_breakpoint -number 2 -file ".*/myfile.c" -line 3
-# will return the breakpoint:
-# bkpt={number="2",type=".*",disp=".*",enabled=".*",addr=".*",func=".*",
-#       file=".*/myfile.c",fullname=".*",line="3",thread-groups=\[.*\],
-#       times="0".*original-location=".*"}
+# Example: mi_make_breakpoint_loc -number 2.1 -file ".*/myfile.c" -line 3
+# will return the breakpoint location:
+# {number="2.1",enabled=".*",addr=".*",func=".*",
+#       file=".*/myfile.c",fullname=".*",line="3",thread-groups=\[.*\]}
 
-proc mi_make_breakpoint {args} {
-    parse_args {{number .*} {type .*} {disp .*} {enabled .*} {addr .*}
+proc mi_make_breakpoint_loc {args} {
+    parse_args {{number .*} {enabled .*} {addr .*}
 	{func .*} {file .*} {fullname .*} {line .*}
-	{thread-groups \\\[.*\\\]} {times .*} {ignore 0}
-	{script ""} {original-location .*} {cond ""} {evaluated-by ""}}
+	{thread-groups \\\[.*\\\]}}
 
     set attr_list {}
-    foreach attr [list number type disp enabled addr func file \
+    foreach attr [list number enabled addr func file \
 		      fullname line thread-groups] {
 	lappend attr_list $attr [set $attr]
     }
 
-    set result "bkpt={[mi_build_kv_pairs $attr_list]"
+    return "{[mi_build_kv_pairs $attr_list]}"
+}
+
+# Shared bits between mi_make_breakpoint and mi_make_breakpoint_multi.
+
+proc mi_make_breakpoint_1 {attr_list cond evaluated-by times \
+			   ignore script original-location} {
+    set result "bkpt=\\\{[mi_build_kv_pairs $attr_list]"
 
     # There are always exceptions.
 
@@ -2546,7 +2558,88 @@  proc mi_make_breakpoint {args} {
     }
     append result [mi_build_kv_pairs \
 		       [list "original-location" ${original-location}]]
-    append result "}"
+
+    return $result
+}
+
+
+# Construct a breakpoint regexp, for a breakpoint with multiple
+# locations.  This may be used to test the output of -break-insert,
+# -dprintf-insert, or -break-info with breakpoints with multiple
+# locations.
+#
+# All arguments for the breakpoint may be specified using the options
+# number, type, disp, enabled, func, cond, evaluated-by, times,
+# ignore, script and locations.
+#
+# Only if -script and -ignore are given will they appear in the output.
+# Otherwise, this procedure will skip them using ".*".
+#
+# Example: mi_make_breakpoint_multi -number 2 -locations "$loc"
+# will return the breakpoint:
+# bkpt={number="2",type=".*",disp=".*",enabled=".*",addr="<MULTIPLE>",
+#       times="0".*original-location=".*",locations=$loc}
+#
+# You can construct the list of locations with mi_make_breakpoint_loc.
+
+proc mi_make_breakpoint_multi {args} {
+    parse_args {{number .*} {type .*} {disp .*} {enabled .*}
+	{times .*} {ignore 0}
+	{script ""} {original-location .*} {cond ""} {evaluated-by ""}
+	{locations .*}}
+
+    set attr_list {}
+    foreach attr [list number type disp enabled] {
+	lappend attr_list $attr [set $attr]
+    }
+
+    lappend attr_list "addr" "<MULTIPLE>"
+
+    set result [mi_make_breakpoint_1 \
+		    $attr_list $cond ${evaluated-by} $times \
+		    $ignore $script ${original-location}]
+
+    append result ","
+    append result [mi_build_kv_pairs [list "locations" $locations]]
+
+    append result "\\\}"
+    return $result
+}
+
+# Construct a breakpoint regexp.  This may be used to test the output of
+# -break-insert, -dprintf-insert, or -break-info.
+#
+# All arguments for the breakpoint may be specified using the options
+# number, type, disp, enabled, addr, func, file, fullanme, line,
+# thread-groups, cond, evaluated-by, times, ignore, script,
+# and original-location.
+#
+# Only if -script and -ignore are given will they appear in the output.
+# Otherwise, this procedure will skip them using ".*".
+#
+# Example: mi_make_breakpoint -number 2 -file ".*/myfile.c" -line 3
+# will return the breakpoint:
+# bkpt={number="2",type=".*",disp=".*",enabled=".*",addr=".*",func=".*",
+#       file=".*/myfile.c",fullname=".*",line="3",thread-groups=\[.*\],
+#       times="0".*original-location=".*"}
+
+proc mi_make_breakpoint {args} {
+    parse_args {{number .*} {type .*} {disp .*} {enabled .*} {addr .*}
+	{func .*} {file .*} {fullname .*} {line .*}
+	{thread-groups \\\[.*\\\]} {times .*} {ignore 0}
+	{script ""} {original-location .*} {cond ""} {evaluated-by ""}}
+
+    set attr_list {}
+    foreach attr [list number type disp enabled addr func file \
+		      fullname line thread-groups] {
+	lappend attr_list $attr [set $attr]
+    }
+
+    set result [mi_make_breakpoint_1 \
+		    $attr_list $cond ${evaluated-by} $times \
+		    $ignore $script ${original-location}]
+
+    append result "\\\}"
     return $result
 }