aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Burgess <aburgess@redhat.com>2025-08-13 14:30:09 +0100
committerAndrew Burgess <aburgess@redhat.com>2025-08-15 11:45:51 +0100
commit1321c777e975a280d92e8aa577164f9bf9f81b8e (patch)
tree7bf7a59917a17f71ba047c9a8196a80b5e9a3335
parent16e7aa4aab7b0f8535e603d2a43a38f08011debc (diff)
downloadbinutils-1321c777e975a280d92e8aa577164f9bf9f81b8e.zip
binutils-1321c777e975a280d92e8aa577164f9bf9f81b8e.tar.gz
binutils-1321c777e975a280d92e8aa577164f9bf9f81b8e.tar.bz2
gdb: fix forward and reverse search commands to match documentation
The forward-search and reverse-search commands were broken by this commit: commit a75cd9a2c129dfc086cbe570ef9cff9b84570bbd Date: Thu Nov 14 16:11:15 2019 -0700 Add observable to watch current source symtab while builds on the work in this commit: commit 1dd588507782591478882a891f64945af9e2b86c Date: Thu Aug 1 09:34:40 2019 -0600 Make current_source_* per-program-space both of these commits went into GDB 10. The documentation for these commands is pretty clear: 'forward-search REGEXP' 'search REGEXP' The command 'forward-search REGEXP' checks each line, starting with the one following the last line listed, for a match for REGEXP. It lists the line that is found. You can use the synonym 'search REGEXP' or abbreviate the command name as 'fo'. 'reverse-search REGEXP' The command 'reverse-search REGEXP' checks each line, starting with the one before the last line listed and going backward, for a match for REGEXP. It lists the line that is found. You can abbreviate this command as 'rev'. Both searches should start searching based on the last line listed. But currently: (gdb) list 3 1 int 2 main (void) 3 { 4 /* Line 4 */ 5 /* Line 5 */ 6 /* Line 6 */ 7 /* Line 7 */ 8 /* Line 8 */ 9 /* Line 9 */ 10 /* Line 10 */ (gdb) forward-search Line 4 /* Line 4 */ (gdb) This should have found line 11. And for reverse-search: (gdb) list 3 1 int 2 main (void) 3 { 4 /* Line 4 */ 5 /* Line 5 */ 6 /* Line 6 */ 7 /* Line 7 */ 8 /* Line 8 */ 9 /* Line 9 */ 10 /* Line 10 */ (gdb) reverse-search Line Expression not found (gdb) The reverse-search should have returned line 9. This new behaviour started with the above commits in GDB 10. On GDB 9 we see behaviour that matches the documentation. Where the forward and reverse searches start from is controlled by a global, last_line_listed, found in source.c. Before commit 1dd588507782, in print_source_lines_base, the last_line_listed variable was updated as each source line was printed, and it was updated with the current line being printed. After commit 1dd588507782, the current symtab and line are moved into a current_source_location object, but the symtab and line member variables are public. The last_line_listed is still set based on the value held in the current_source_location object, and this object is updated each time around the source printing loop. So despite the restructure, the logic, and behaviour, is unchanged. After commit a75cd9a2c129, the member variables of current_source_location are now private. The source printing loop in print_source_lines_base uses a local variable, new_lineno, to track the current source line number, and updates the current_source_location at the end of print_source_lines_base. However, last_line_listed is still updated inside the loop, using the original line value within current_source_location, which is no longer being updated each time around the loop. As a result, last_line_listed is now just the first line listed! This didn't show up in testing because, as far as I can tell, the last_line_listed is _only_ used for forward and reverse searching, and the testing for these commands is minimal. In this commit I move the setting of last_line_listed outside of the source printing loop, this only needs to be updated once, when we have finished printing the source lines. I've also done a couple of other cleanups in the same area, I moved 'buf' a local variable into the most inner scope where it is required, and I converted the 'while' loop into a 'for' loop, moving the increment out of the loop body. There's now a test which does some more detailed checks of the forward and reverse search commands. Approved-By: Tom Tromey <tom@tromey.com>
-rw-r--r--gdb/source.c11
-rw-r--r--gdb/testsuite/gdb.base/source-search.c127
-rw-r--r--gdb/testsuite/gdb.base/source-search.exp81
3 files changed, 214 insertions, 5 deletions
diff --git a/gdb/source.c b/gdb/source.c
index 0fd370b..b207e0d 100644
--- a/gdb/source.c
+++ b/gdb/source.c
@@ -1400,11 +1400,8 @@ print_source_lines_base (struct symtab *s, int line, int stopline,
const char *iter = lines.c_str ();
int new_lineno = loc->line ();
- while (nlines-- > 0 && *iter != '\0')
+ for (; nlines-- > 0 && *iter != '\0'; ++new_lineno)
{
- char buf[20];
-
- last_line_listed = loc->line ();
if (flags & PRINT_SOURCE_LINES_FILENAME)
{
uiout->message ("%ps",
@@ -1415,7 +1412,6 @@ print_source_lines_base (struct symtab *s, int line, int stopline,
uiout->message ("%ps\t", styled_string (line_number_style.style (),
pulongest (new_lineno)));
- ++new_lineno;
while (*iter != '\0')
{
@@ -1457,6 +1453,8 @@ print_source_lines_base (struct symtab *s, int line, int stopline,
}
else if (*iter > 0 && *iter < 040)
{
+ char buf[20];
+
xsnprintf (buf, sizeof (buf), "^%c", *iter + 0100);
uiout->text (buf);
++iter;
@@ -1470,6 +1468,9 @@ print_source_lines_base (struct symtab *s, int line, int stopline,
uiout->text ("\n");
}
+ /* As NEW_LINENO was incremented after displaying the last source line,
+ the last line shown was the one before NEW_LINENO. */
+ last_line_listed = new_lineno - 1;
loc->set (loc->symtab (), new_lineno);
}
diff --git a/gdb/testsuite/gdb.base/source-search.c b/gdb/testsuite/gdb.base/source-search.c
new file mode 100644
index 0000000..2320c5c
--- /dev/null
+++ b/gdb/testsuite/gdb.base/source-search.c
@@ -0,0 +1,127 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2025 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/>. */
+
+int
+main (void)
+{
+ /* Line 21 */
+ /* Line 22 */
+ /* Line 23 */
+ /* Line 24 */
+ /* Line 25 */
+ /* Line 26 */
+ /* Line 27 */
+ /* Line 28 */
+ /* Line 29 */
+ /* Line 30 */
+ /* Line 31 */
+ /* Line 32 */
+ /* Line 33 */
+ /* Line 34 */
+ /* Line 35 */
+ /* Line 36 */
+ /* Line 37 */
+ /* Line 38 */
+ /* Line 39 */
+ /* Line 40 */
+ /* Line 41 */
+ /* Line 42 */
+ /* Line 43 */
+ /* Line 44 */
+ /* Line 45 */
+ /* Line 46 */
+ /* Line 47 */
+ /* Line 48 */
+ /* Line 49 */
+ /* Line 50 */
+ /* Line 51 */
+ /* Line 52 */
+ /* Line 53 */
+ /* Line 54 */
+ /* Line 55 */
+ /* Line 56 */
+ /* Line 57 */
+ /* Line 58 */
+ /* Line 59 */
+ /* Line 60 */
+ /* Line 61 */
+ /* Line 62 */
+ /* Line 63 */
+ /* Line 64 */
+ /* Line 65 */
+ /* Line 66 */
+ /* Line 67 */
+ /* Line 68 */
+ /* Line 69 */
+ /* Line 70 */
+ /* Line 71 */
+ /* Line 72 */
+ /* Line 73 */
+ /* Line 74 */
+ /* Line 75 */
+ /* Line 76 */
+ /* Line 77 */
+ /* Line 78 */
+ /* Line 79 */
+ /* Line 80 */
+ /* Line 81 */
+ /* Line 82 */
+ /* Line 83 */
+ /* Line 84 */
+ /* Line 85 */
+ /* Line 86 */
+ /* Line 87 */
+ /* Line 88 */
+ /* Line 89 */
+ /* Line 90 */
+ /* Line 91 */
+ /* Line 92 */
+ /* Line 93 */
+ /* Line 94 */
+ /* Line 95 */
+ /* Line 96 */
+ /* Line 97 */
+ /* Line 98 */
+ /* Line 99 */
+ /* Line 100 */
+ /* Line 101 */
+ /* Line 102 */
+ /* Line 103 */
+ /* Line 104 */
+ /* Line 105 */
+ /* Line 106 */
+ /* Line 107 */
+ /* Line 108 */
+ /* Line 109 */
+ /* Line 110 */
+ /* Line 111 */
+ /* Line 112 */
+ /* Line 113 */
+ /* Line 114 */
+ /* Line 115 */
+ /* Line 116 */
+ /* Line 117 */
+ /* Line 118 */
+ /* Line 119 */
+ /* Line 120 */
+ /* Line 121 */
+ /* Line 122 */
+ /* Line 123 */
+ /* Line 124 */
+ /* Line 125 */
+ return 0;
+} /* Last line. */
diff --git a/gdb/testsuite/gdb.base/source-search.exp b/gdb/testsuite/gdb.base/source-search.exp
new file mode 100644
index 0000000..474d429
--- /dev/null
+++ b/gdb/testsuite/gdb.base/source-search.exp
@@ -0,0 +1,81 @@
+# Copyright 2025 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 'forward-search' and 'reverse-search' commands. This test
+# relies on some hard-coded line numbers relating to the source file.
+# We could switch to using gdb_get_line_number, but it doesn't feel
+# like that would add much value; just don't change the source file.
+
+standard_testfile
+
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile] } {
+ return
+}
+
+gdb_test "forward-search This testcase is part" \
+ "1\\s+/\\* This testcase is part of GDB, the GNU debugger\\." \
+ "search for first line of the file"
+
+gdb_test "forward-search This testcase is part" \
+ "Expression not found" \
+ "repeated search doesn't find the same first line"
+
+# The 'reverse-search' command starts searching from the line before
+# the last line displayed. So in this case, the reverse search starts
+# from line 0, i.e. nothing is searched.
+gdb_test "reverse-search This testcase is part" \
+ "Expression not found" \
+ "reverse search doesn't find the first line either"
+
+# List some source lines, and then perform some forward-searches. The
+# searches start from the first line after the last line displayed.
+gdb_test "list 20" ".*" \
+ "list source code ahead of a forward-search"
+gdb_test "forward-search Line 2" \
+ "25\\s+/\\* Line 25 \\*/" \
+ "first forward-search after a list"
+gdb_test "forward-search Line 2" \
+ "26\\s+/\\* Line 26 \\*/" \
+ "second forward-search after a list"
+gdb_test "forward-search Line 2" \
+ "27\\s+/\\* Line 27 \\*/" \
+ "third forward-search after a list"
+
+# Now reverse-search from where we got too.
+gdb_test "reverse-search Line 2" \
+ "26\\s+/\\* Line 26 \\*/" \
+ "first reverse-search for 'Line 2'"
+gdb_test "reverse-search Line 2" \
+ "25\\s+/\\* Line 25 \\*/" \
+ "second reverse-search for 'Line 2'"
+gdb_test "reverse-search Line 2" \
+ "24\\s+/\\* Line 24 \\*/" \
+ "third reverse-search for 'Line 2'"
+
+# List some source lines, and then perform a reverse-search. The
+# search starts frm the first line before the last line displayed.
+gdb_test "list 20" ".*" \
+ "list source code ahead of a reverse-search"
+gdb_test "reverse-search Line 2" \
+ "23\\s+/\\* Line 23 \\*/" \
+ "reverse-search after a list"
+
+# List the last lines of the file, then reverse search for the last
+# line. As reverse-search starts on the line before the last line
+# displayed, this will fail to find the last line.
+gdb_test "list 127"
+gdb_test "reverse-search Last line" \
+ "Expression not found" \
+ "reverse search for the last line fails"