[PATCH 5/6] gdb: prepend comp_dir to symtab name in buildsym_compunit

Simon Marchi simon.marchi@polymtl.ca
Thu Apr 7 01:51:58 GMT 2022


Printing macros defined in the main source file doesn't work reliably using
various toolchains, especially when DWARF 5 is used.  For example, using either
of these binaries:

    $ gcc --version
    gcc (GCC) 11.2.0
    $ ld --version
    GNU ld (GNU Binutils) 2.38
    $ gcc test.c -g3 -gdwarf-5

    $ clang --version
    clang version 13.0.1
    $ clang test.c -gdwarf-5 -fdebug-macro

I get:

    $ ./gdb -nx -q --data-directory=data-directory a.out
    (gdb) start
    Temporary breakpoint 1 at 0x111d: file test.c, line 6.
    Starting program: /home/simark/build/binutils-gdb-one-target/gdb/a.out

    Temporary breakpoint 1, main () at test.c:6
    6         return ZERO;
    (gdb) p ZERO
    No symbol "ZERO" in current context.

When starting to investigate this (taking the gcc-compiled binary as an
example), we see that GDB fails to look up the appropriate macro scope
when evaluating the expression.  While stopped in
macro_lookup_inclusion:

    (top-gdb) p name
    $1 = 0x62100011a980 "test.c"
    (top-gdb) p source.filename
    $2 = 0x62100011a9a0 "/home/simark/build/binutils-gdb-one-target/gdb/test.c"

`source` is the macro_source_file that we would expect GDB to find.  But
it doesn't find it because the filename it is looking for isn't exactly
like the filename as written in the macro_source_file object.

The `name` parameter comes from the symtab::filename field of the symtab
we are stopped at.  The symtab's filename comes from the compilation
unit's DW_AT_name, passed to the buildsym_compunit's constructor:

  https://gitlab.com/gnutools/binutils-gdb/-/blob/4815d6125ec580cc02a1094d61b8c9d1cc83c0a1/gdb/dwarf2/read.c#L10627-10630

The name is used as is to create the main subfile of the compunit, which
eventually becomes a symtab.  In this case it is just the filename,
"test.c".

The name of the macro_source_file comes from the line number program
header's file table, from the call to the line_header::file_file_name
method:

  https://gitlab.com/gnutools/binutils-gdb/-/blob/4815d6125ec580cc02a1094d61b8c9d1cc83c0a1/gdb/dwarf2/macro.c#L54-65

line_header::file_file_name prepends the directory path the file is
relative to, if the file name is not absolute.  In this case, the file
name is "test.c", appended to the directory
"/home/simark/build/binutils-gdb-one-target/gdb".

Because the symtab's name is not created the same way as the
macro_source_file's name is created, we get this mismatch.

This patch fixes things locally in a rather naive way by making
buildsym_compunit format the main subfile's name the same way as the
DWARF reader formats the main name, that is by prepending the directory
part.  Since this changes some symtab names, there is some user-visible
changes when those names are output, as can be seen from the few tests I
needed to update.  The difference is that some symtab names that
previously didn't include a directory portion will now include one.

Finally, change the comment above the line_header::file_file_name
declaration.  The part about it returning a name relative the
compilation directory is just not true, it thought it was very
misleading.  There isn't much we can guarantee about how the returned
file name will look like, because it depends on what the compiler
decided to put in the file and directory tables.

Change-Id: I0372906dafc01d6b3774b2ab72f9d28d7069b6cc
---
 gdb/buildsym.c                                    | 15 +++++++++++++++
 gdb/dwarf2/line-header.h                          |  5 +----
 gdb/testsuite/gdb.dwarf2/dw2-objfile-overlap.exp  |  2 +-
 gdb/testsuite/gdb.dwarf2/imported-unit-bp.exp.tcl |  2 +-
 4 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/gdb/buildsym.c b/gdb/buildsym.c
index 4718b201f036..c1c588a869dc 100644
--- a/gdb/buildsym.c
+++ b/gdb/buildsym.c
@@ -71,6 +71,21 @@ buildsym_compunit::buildsym_compunit (struct objfile *objfile_,
      non-primary symtabs.  It is also needed by get_macro_table.  */
   m_compunit_symtab = allocate_compunit_symtab (m_objfile, name);
 
+  std::string name_copy;
+
+  /* In order not to lose the line information directory,
+     we concatenate it to the filename when it makes sense.
+     Note that the Dwarf3 standard says (speaking of filenames in line
+     information): ``The directory index is ignored for file names
+     that represent full path names''.  Thus ignoring dirname in the
+     `else' branch below isn't an issue.  */
+
+  if (!IS_ABSOLUTE_PATH (name) && m_comp_dir != nullptr)
+    {
+      name_copy = string_printf ("%s/%s", m_comp_dir.get (), name);
+      name = name_copy.c_str ();
+    }
+
   /* Build the subfile for NAME (the main source file) so that we can record
      a pointer to it for later.
      IMPORTANT: Do not allocate a struct symtab for NAME here.
diff --git a/gdb/dwarf2/line-header.h b/gdb/dwarf2/line-header.h
index 8fb44be56b2e..845fbebfa8d3 100644
--- a/gdb/dwarf2/line-header.h
+++ b/gdb/dwarf2/line-header.h
@@ -162,10 +162,7 @@ struct line_header
      header.  These point into dwarf2_per_objfile->line_buffer.  */
   const gdb_byte *statement_program_start {}, *statement_program_end {};
 
-  /* Return file name relative to the compilation directory of file
-     number I in this object's file name table.  The result is
-     allocated using xmalloc; the caller is responsible for freeing
-     it.  */
+  /* Return file name of file number FILE in this object's file name table.  */
   gdb::unique_xmalloc_ptr<char> file_file_name (int file) const;
 
  private:
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-objfile-overlap.exp b/gdb/testsuite/gdb.dwarf2/dw2-objfile-overlap.exp
index 2257dd228191..6ea68e1f997f 100644
--- a/gdb/testsuite/gdb.dwarf2/dw2-objfile-overlap.exp
+++ b/gdb/testsuite/gdb.dwarf2/dw2-objfile-overlap.exp
@@ -45,4 +45,4 @@ gdb_breakpoint "*outer_before"
 
 # FAIL was:
 # No line number information available for address 0x4 <outer_inner>
-gdb_test "info line inner" {Line 2 of "inner\.c" starts at address .*}
+gdb_test "info line inner" {Line 2 of "/tmp/inner\.c" starts at address .*}
diff --git a/gdb/testsuite/gdb.dwarf2/imported-unit-bp.exp.tcl b/gdb/testsuite/gdb.dwarf2/imported-unit-bp.exp.tcl
index fe92c530888d..d2a74c5031b1 100644
--- a/gdb/testsuite/gdb.dwarf2/imported-unit-bp.exp.tcl
+++ b/gdb/testsuite/gdb.dwarf2/imported-unit-bp.exp.tcl
@@ -126,4 +126,4 @@ if { [prepare_for_testing "failed to prepare" ${testfile} \
 gdb_reinitialize_dir /tmp
 
 # Using an absolute path is important to see the bug.
-gdb_test "break /tmp/${srcfile}:19" "Breakpoint .* file $srcfile, line .*"
+gdb_test "break /tmp/${srcfile}:19" "Breakpoint .* file /tmp/$srcfile, line .*"
-- 
2.35.1



More information about the Gdb-patches mailing list