[PATCH 1/1] gdb, linespec: filename-qualified explicit line BP missed

Klaus Gerlicher klaus.gerlicher@intel.com
Tue Nov 5 09:55:24 GMT 2024


From: "Gerlicher, Klaus" <klaus.gerlicher@intel.com>

Assume we compile an application with a main source file and two additional
source files of the same basename but different folders.  Each source file
contains a function at the same line location but with a different layout of
code, commented with "Intentionally empty.".  In effect source file one has
executable code on line 21 while source file two has code at line 22.

Source file one:

01 /* This testcase is part of GDB, the GNU debugger.
[...]
17
18 void afunc (void)
19 {
20   /* Intentionally empty.  */
21   while(0); /* Should break here.  */
22 }

Source file two:

01 /* This testcase is part of GDB, the GNU debugger.
[...]
17
18 void bfunc (void)
19 {
20   /* Intentionally no code.  */
21   /* Intentionally no code.  */
22   while(0); /* Should also break here.  */
23 }

The main source file just imports function afunc and bfunc.

Now set a filename-qualified breakpoint on a line for the file, for
example here "break thefile.c:20".  This will only set a breakpoint on source
file one and not on source file two.

The breakpoint propagation algorithm tries to find a best entry line but only
considers a single symbol table match as sufficient.  For our case it propagates
to line 21.
It now tries to set a breakpoint on this line which matches for source file
one.  However, source file two does not have executable code at this line and
therefore the breakpoint set there is unsuccessful, as seen here:

(gdb) b thefile.c:20
Breakpoint 1 at 0x1154: file one/thefile.c, line 21.

This patch updates the breakpoint propagation algorithm to use a best entry per
symbol table which will then yield:

(gdb) b thefile.c:20
Breakpoint 1 at 0x1154: thefile.c:20. (2 locations)

Both breakpoints will now be set and hit as the user would expect.

Line tables for reference:

(gdb) maint info line-table
objfile: explicit-line-propagation ((struct objfile *) 0x55ebdb845650)
compunit_symtab: thefile.c ((struct compunit_symtab *) 0x55ebdb850d50)
symtab: two/thefile.c ((struct symtab *) 0x55ebdb850dd0)
linetable: ((struct linetable *) 0x55ebdb8845b0):
INDEX  LINE   REL-ADDRESS        UNREL-ADDRESS      IS-STMT PROLOGUE-END
0      19     0x0000555555555158 0x0000000000001158 Y
1      22     0x0000555555555160 0x0000000000001160 Y
2      23     0x0000555555555161 0x0000000000001161 Y
3      END    0x0000555555555164 0x0000000000001164 Y

objfile: explicit-line-propagation ((struct objfile *) 0x55ebdb845650)
compunit_symtab: thefile.c ((struct compunit_symtab *) 0x55ebdb8509e0)
symtab: one/thefile.c ((struct symtab *) 0x55ebdb850a60)
linetable: ((struct linetable *) 0x55ebdb850cc0):
INDEX  LINE   REL-ADDRESS        UNREL-ADDRESS      IS-STMT PROLOGUE-END
0      19     0x000055555555514c 0x000000000000114c Y
1      21     0x0000555555555154 0x0000000000001154 Y
2      22     0x0000555555555155 0x0000000000001155 Y
3      END    0x0000555555555158 0x0000000000001158 Y

objfile: explicit-line-propagation ((struct objfile *) 0x55ebdb845650)
compunit_symtab: explicit-line-propagation.c ((struct compunit_symtab *) 0x55ebdb850460)
symtab: explicit-line-propagation.c ((struct symtab *) 0x55ebdb8504f0)
linetable: ((struct linetable *) 0x55ebdb850940):
INDEX  LINE   REL-ADDRESS        UNREL-ADDRESS      IS-STMT PROLOGUE-END
0      22     0x0000555555555129 0x0000000000001129 Y
1      23     0x0000555555555131 0x0000000000001131 Y
2      24     0x000055555555513b 0x000000000000113b Y
3      25     0x000055555555514a 0x000000000000114a Y
4      END    0x000055555555514c 0x000000000000114c Y
---
 gdb/linespec.c                                | 51 +++++++++++++++----
 .../gdb.linespec/explicit-line-propagation.c  | 25 +++++++++
 .../explicit-line-propagation.exp             | 46 +++++++++++++++++
 .../gdb.linespec/explicit/one/thefile.c       | 22 ++++++++
 .../gdb.linespec/explicit/two/thefile.c       | 23 +++++++++
 5 files changed, 157 insertions(+), 10 deletions(-)
 create mode 100644 gdb/testsuite/gdb.linespec/explicit-line-propagation.c
 create mode 100644 gdb/testsuite/gdb.linespec/explicit-line-propagation.exp
 create mode 100644 gdb/testsuite/gdb.linespec/explicit/one/thefile.c
 create mode 100644 gdb/testsuite/gdb.linespec/explicit/two/thefile.c

diff --git a/gdb/linespec.c b/gdb/linespec.c
index 4d8a8c1731e..f99c2e3e331 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -45,6 +45,7 @@
 #include "gdbsupport/def-vector.h"
 #include <algorithm>
 #include "inferior.h"
+#include <map>
 
 /* An enumeration of the various things a user might attempt to
    complete for a linespec location.  */
@@ -386,11 +387,12 @@ static std::vector<symtab *>
   collect_symtabs_from_filename (const char *file,
 				 struct program_space *pspace);
 
+using symtab_best_entry_map = std::map<symtab *, const linetable_entry *>;
 static std::vector<symtab_and_line> decode_digits_ordinary
   (struct linespec_state *self,
    linespec *ls,
    int line,
-   const linetable_entry **best_entry);
+   symtab_best_entry_map &best_entries);
 
 static std::vector<symtab_and_line> decode_digits_list_mode
   (struct linespec_state *self,
@@ -2060,7 +2062,7 @@ create_sals_line_offset (struct linespec_state *self,
     values = decode_digits_list_mode (self, ls, val);
   else
     {
-      const linetable_entry *best_entry = NULL;
+      symtab_best_entry_map entry_per_symtab;
       int i, j;
 
       /* True if the provided line gave an exact match.  False if we had to
@@ -2068,13 +2070,37 @@ create_sals_line_offset (struct linespec_state *self,
       bool was_exact = true;
 
       std::vector<symtab_and_line> intermediate_results
-	= decode_digits_ordinary (self, ls, val.line, &best_entry);
-      if (intermediate_results.empty () && best_entry != NULL)
+	= decode_digits_ordinary (self, ls, val.line, entry_per_symtab);
+      if (intermediate_results.empty () && !entry_per_symtab.empty ())
 	{
 	  was_exact = false;
-	  intermediate_results = decode_digits_ordinary (self, ls,
-							 best_entry->line,
-							 &best_entry);
+
+	  /* We got best entries per symtab and therefore only lookup PCs
+	     in the associated symtab.  */
+	  for (const auto &symtab : ls->file_symtabs)
+	    {
+	      const auto e = entry_per_symtab.find (symtab);
+	      if (e == entry_per_symtab.end ())
+		continue;
+
+	      program_space *pspace
+		= symtab->compunit ()->objfile ()->pspace ();
+	      set_current_program_space (pspace);
+
+	      const linetable_entry *best_entry = nullptr;
+	      std::vector<CORE_ADDR> pcs = find_pcs_for_symtab_line
+		(symtab, e->second->line, &best_entry);
+	      for (const CORE_ADDR pc : pcs)
+		{
+		  symtab_and_line sal;
+		  sal.pspace = pspace;
+		  sal.symtab = symtab;
+		  sal.line = e->second->line;
+		  sal.explicit_line = true;
+		  sal.pc = pc;
+		  intermediate_results.push_back (std::move (sal));
+		}
+	    }
 	}
 
       /* For optimized code, the compiler can scatter one source line
@@ -4046,13 +4072,15 @@ decode_digits_list_mode (struct linespec_state *self,
 
 /* A helper for create_sals_line_offset that iterates over the symtabs
    associated with LS and returns a vector of corresponding symtab_and_line
-   structures.  */
+   structures.  It also fills in BEST_ENTRIES, a map of symtab to line
+   numbers, for best matching lines when propagating a line that is not
+   in the line tables.  */
 
 static std::vector<symtab_and_line>
 decode_digits_ordinary (struct linespec_state *self,
 			linespec *ls,
 			int line,
-			const linetable_entry **best_entry)
+			symtab_best_entry_map &best_entries)
 {
   std::vector<symtab_and_line> sals;
   for (const auto &elt : ls->file_symtabs)
@@ -4065,7 +4093,10 @@ decode_digits_ordinary (struct linespec_state *self,
       program_space *pspace = elt->compunit ()->objfile ()->pspace ();
       set_current_program_space (pspace);
 
-      pcs = find_pcs_for_symtab_line (elt, line, best_entry);
+      const linetable_entry *best_entry = nullptr;
+      pcs = find_pcs_for_symtab_line (elt, line, &best_entry);
+      if (pcs.empty () && best_entry != nullptr)
+	best_entries[elt] = best_entry;
       for (CORE_ADDR pc : pcs)
 	{
 	  symtab_and_line sal;
diff --git a/gdb/testsuite/gdb.linespec/explicit-line-propagation.c b/gdb/testsuite/gdb.linespec/explicit-line-propagation.c
new file mode 100644
index 00000000000..64e9db6e615
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/explicit-line-propagation.c
@@ -0,0 +1,25 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2024 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/>.  */
+
+extern void afunc ();
+extern void bfunc ();
+
+int main ()
+{
+  afunc ();
+  bfunc ();
+}
diff --git a/gdb/testsuite/gdb.linespec/explicit-line-propagation.exp b/gdb/testsuite/gdb.linespec/explicit-line-propagation.exp
new file mode 100644
index 00000000000..285dbeee645
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/explicit-line-propagation.exp
@@ -0,0 +1,46 @@
+# Copyright 2024 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 filename qualified explicit line breakpoint propagation for the case
+# where there are multiple source files of the same name.
+
+require allow_shlib_tests
+
+standard_testfile .c
+
+set exefile $testfile
+
+set base "thefile.c"
+set baseone explicit/one/$base
+set basetwo explicit/two/$base
+
+if {[prepare_for_testing "failed to prepare" $exefile \
+     [list $srcfile $baseone $basetwo]]} {
+    return -1
+}
+
+if {![runto_main]} {
+    return
+}
+
+set propagate_location [gdb_get_line_number "Intentionally empty." $baseone]
+gdb_breakpoint "$base:$propagate_location"
+
+set should_break_location [gdb_get_line_number "Should break here." $baseone]
+set should_also_break_location [gdb_get_line_number "Should also break here." $basetwo]
+
+gdb_continue_to_breakpoint $should_break_location ".*$baseone:$should_break_location.*"
+gdb_continue_to_breakpoint $should_also_break_location ".*$basetwo:$should_also_break_location.*"
+
+gdb_continue_to_end
diff --git a/gdb/testsuite/gdb.linespec/explicit/one/thefile.c b/gdb/testsuite/gdb.linespec/explicit/one/thefile.c
new file mode 100644
index 00000000000..ae332522c69
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/explicit/one/thefile.c
@@ -0,0 +1,22 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2024 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/>.  */
+
+void afunc (void)
+{
+  /* Intentionally empty.  */
+  while (0); /* Should break here.  */
+}
diff --git a/gdb/testsuite/gdb.linespec/explicit/two/thefile.c b/gdb/testsuite/gdb.linespec/explicit/two/thefile.c
new file mode 100644
index 00000000000..c2b65a8f39b
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/explicit/two/thefile.c
@@ -0,0 +1,23 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2024 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/>.  */
+
+void bfunc (void)
+{
+  /* Intentionally no code.  */
+  /* Intentionally no code.  */
+  while (0); /* Should also break here.  */
+}
-- 
2.34.1

Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928



More information about the Gdb-patches mailing list