diff options
author | Pedro Alves <pedro@palves.net> | 2020-08-27 21:03:53 +0100 |
---|---|---|
committer | Pedro Alves <pedro@palves.net> | 2020-08-27 21:03:53 +0100 |
commit | df63178325a5705a609bff94a349162bbb839895 (patch) | |
tree | df44a2706a8aa07bc3523f6c2948576905387e87 /gdb/testsuite | |
parent | b2b38aa45ba2eb2e7e4c70689d679c4c467eda73 (diff) | |
download | gdb-df63178325a5705a609bff94a349162bbb839895.zip gdb-df63178325a5705a609bff94a349162bbb839895.tar.gz gdb-df63178325a5705a609bff94a349162bbb839895.tar.bz2 |
Fix advance/until and multiple locations (PR gdb/26524)
If you do "advance LINESPEC", and LINESPEC expands to more than one
location, GDB just errors out:
if (sals.size () != 1)
error (_("Couldn't get information on specified line."));
For example, advancing to a line in an inlined function, inlined three
times:
(gdb) b 21
Breakpoint 1 at 0x55555555516f: advance.cc:21. (3 locations)
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y <MULTIPLE>
1.1 y 0x000055555555516f in inline_func at advance.cc:21
1.2 y 0x000055555555517e in inline_func at advance.cc:21
1.3 y 0x000055555555518d in inline_func at advance.cc:21
(gdb) advance 21
Couldn't get information on specified line.
(gdb)
Similar issue with the "until" command, as it shares the
implementation with "advance".
Since, as the comment in gdb.base/advance.exp says, "advance <location>"
is really just syntactic sugar for "tbreak <location>;continue",
fix this by making GDB insert a breakpoint at all the resolved
locations.
A new testcase is included, which exercises both "advance" and
"until", in two different cases expanding to multiple locations:
- inlined functions
- C++ overloads
This also exercises the inline frames issue fixed by the previous
patch.
gdb/ChangeLog:
PR gdb/26524
* breakpoint.c (until_break_fsm) <location_breakpoint,
caller_breakpoint>: Delete fields.
<breakpoints>: New field.
<until_break_fsm>: Adjust to save a breakpoint vector instead of
two individual breakpoints.
(until_break_fsm::should_stop): Loop over breakpoints in the
breakpoint vector.
(until_break_fsm::clean_up): Adjust to clear the breakpoints
vector.
(until_break_command): Handle location expanding into multiple
sals.
gdb/testsuite/ChangeLog:
PR gdb/26523
PR gdb/26524
* gdb.base/advance-until-multiple-locations.cc: New.
* gdb.base/advance-until-multiple-locations.exp: New.
Diffstat (limited to 'gdb/testsuite')
-rw-r--r-- | gdb/testsuite/ChangeLog | 7 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/advance-until-multiple-locations.cc | 61 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/advance-until-multiple-locations.exp | 142 |
3 files changed, 210 insertions, 0 deletions
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 2583513..6ce2b71 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2020-08-27 Pedro Alves <pedro@palves.net> + + PR gdb/26523 + PR gdb/26524 + * gdb.base/advance-until-multiple-locations.cc: New. + * gdb.base/advance-until-multiple-locations.exp: New. + 2020-08-27 Simon Marchi <simon.marchi@polymtl.ca> * gdb.dwarf2/dw2-reg-undefined.exp: Use multi_line. diff --git a/gdb/testsuite/gdb.base/advance-until-multiple-locations.cc b/gdb/testsuite/gdb.base/advance-until-multiple-locations.cc new file mode 100644 index 0000000..a904938 --- /dev/null +++ b/gdb/testsuite/gdb.base/advance-until-multiple-locations.cc @@ -0,0 +1,61 @@ +/* This testcase is part of GDB, the GNU debugger. + + 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/>. */ + +static inline int __attribute__ ((always_inline)) +inline_func (int i) +{ + i++; /* multiple locations here */ + return i; +} + +int global = 0; + +void +ovld_func () +{ + global = 1; +} + +void +ovld_func (int) +{ + global = 2; +} + +/* This is a separate function so that we can test that "until" stops + at the caller. */ + +int +test () +{ + int i = 0; + + i = inline_func (i); + i = inline_func (i); + i = inline_func (i); + + ovld_func (); + ovld_func (0); + + return 0; +} + +int +main () +{ + return test (); +} diff --git a/gdb/testsuite/gdb.base/advance-until-multiple-locations.exp b/gdb/testsuite/gdb.base/advance-until-multiple-locations.exp new file mode 100644 index 0000000..a6a1de6 --- /dev/null +++ b/gdb/testsuite/gdb.base/advance-until-multiple-locations.exp @@ -0,0 +1,142 @@ +# 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 'advance/until LINESPEC' where LINESPEC expands to multiple +# locations. + +standard_testfile .cc + +if { [skip_cplus_tests] } { continue } + +if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \ + {debug c++}] } { + return -1 +} + +set lineno [gdb_get_line_number "multiple locations here"] + +# advance/until to an inlined line number, which has been inlined +# multiple times, when the program is stopped at the same inlined +# function. +proc_with_prefix until_advance_lineno_from_inlined {cmd} { + global lineno + + if ![runto test] { + fail "can't run to test" + return + } + + gdb_breakpoint $lineno + gdb_continue_to_breakpoint "break here" + + set lineno2 [expr $lineno + 1] + + gdb_test "$cmd $lineno2" \ + "inline_func .* at .*:$lineno2.*return i.*" \ + "$cmd line number" +} + +# advance/until to a line number, which has been inlined multiple +# times, when the program is stopped at a non-inlined function. + +proc_with_prefix until_advance_lineno_from_non_inlined {cmd} { + global lineno + + if ![runto test] { + fail "can't run to test" + return + } + + gdb_test "$cmd $lineno" \ + "inline_func .* at .*:$lineno.*multiple locations here.*" \ + "$cmd line number" +} + +# Test advancing to an inlined function, which has been inlined +# multiple times. + +proc_with_prefix until_advance_inline_func {cmd} { + global lineno + + if ![runto test] { + fail "can't run to test" + return + } + + gdb_test "$cmd inline_func" \ + "inline_func .* at .*:$lineno.*multiple locations here.*" +} + +# Test advancing to an overloaded function, which is another form of a +# linespec expanding to multiple locations. GDB will stop at the +# first overload called. + +proc_with_prefix advance_overload {} { + global lineno + + if ![runto test] { + fail "can't run to test" + return + } + + # Test that advance stops at the first overload called by the + # program. + + gdb_test "advance ovld_func" \ + "ovld_func .* at .*global = 1.*" \ + "first advance stops at ovld_func()" + + # Now test that advance also stops at the other overload called by + # the program. + + # Need to issue the advance twice, because advance also stops upon + # exit from the current stack frame. + gdb_test "advance ovld_func" \ + "ovld_func \\(0\\);.*" \ + "second advance stops at caller" + + gdb_test "advance ovld_func" \ + "ovld_func .* at .*global = 2.*" \ + "third advance stops at ovld_func(int)" +} + +# Test "until" to an overloaded function, which is another form of a +# linespec expanding to multiple locations. Unlike "advance", "until" +# only stops if still in the same frame. Since the overloaded +# function is a different frame, the program should stop at the caller +# frame instead. + +proc_with_prefix until_overload {} { + global lineno + + if ![runto test] { + fail "can't run to test" + return + } + + # ovld_func is a different frame, so it shouldn't cause a stop. + # Instead, the program should stop at the caller frame. + gdb_test "until ovld_func" \ + "main .* at .*return test \\(\\);.*" +} + +foreach_with_prefix cmd {"until" "advance"} { + until_advance_lineno_from_inlined $cmd + until_advance_lineno_from_non_inlined $cmd + until_advance_inline_func $cmd +} + +advance_overload +until_overload |