[06/14] libdw: Handle split DWARF in dwarf_macro_getsrcfiles

Message ID 4d46a2bb0eba8e3aff5a33c045cd5a75342d596b.1695837512.git.osandov@fb.com
State Committed
Headers
Series elfutils: DWARF package (.dwp) file support |

Commit Message

Omar Sandoval Sept. 27, 2023, 6:20 p.m. UTC
  From: Omar Sandoval <osandov@fb.com>

Macro information references file names from the line number information
table, which is tricky in split DWARF for a couple of reasons.

First, the line number information for a macro unit comes from the
.debug_line.dwo section in the split file, not the .debug_line section
in the skeleton file.  This was not specified in the GNU DebugFission
design document [1] or the DWARF 5 standard, but it is how GCC and Clang
behave in practice and was clarified in DWARF standard issue
200602.1 [2] for the upcoming DWARF 6 standard.

dwarf_macro_getsrcfiles uses the line number information from whichever
Dwarf handle it was passed.  This is error-prone, since the most natural
thing to do is to pass the skeleton Dwarf handle.  Fix this by storing
the appropriate Dwarf handle in Dwarf_Macro_Op_Table and using that one.

Second, for .debug_macinfo.dwo in GNU DebugFission (generated by gcc
-gdwarf-4 -gstrict-dwarf -gsplit-dwarf), the offset into .debug_line.dwo
is implicitly 0.  Again, this isn't in any specification, but it's how
GCC behaves in practice (Clang never generates macro information for
DWARF 4 split DWARF).  Make get_macinfo_table default to 0 for split
DWARF when it can't find DW_AT_stmt_list.

1: https://gcc.gnu.org/wiki/DebugFission
2: https://dwarfstd.org/issues/200602.1.html

Signed-off-by: Omar Sandoval <osandov@fb.com>
---
 libdw/ChangeLog                 |  8 +++++---
 libdw/dwarf_getmacros.c         | 11 +++++++++--
 libdw/dwarf_macro_getsrcfiles.c |  5 ++++-
 libdw/libdwP.h                  |  2 ++
 4 files changed, 20 insertions(+), 6 deletions(-)
  

Comments

Mark Wielaard Oct. 3, 2023, 9:49 p.m. UTC | #1
Hi Omar,

On Wed, Sep 27, 2023 at 11:20:55AM -0700, Omar Sandoval wrote:
> Macro information references file names from the line number information
> table, which is tricky in split DWARF for a couple of reasons.
> 
> First, the line number information for a macro unit comes from the
> .debug_line.dwo section in the split file, not the .debug_line section
> in the skeleton file.  This was not specified in the GNU DebugFission
> design document [1] or the DWARF 5 standard, but it is how GCC and Clang
> behave in practice and was clarified in DWARF standard issue
> 200602.1 [2] for the upcoming DWARF 6 standard.
> 
> dwarf_macro_getsrcfiles uses the line number information from whichever
> Dwarf handle it was passed.  This is error-prone, since the most natural
> thing to do is to pass the skeleton Dwarf handle.  Fix this by storing
> the appropriate Dwarf handle in Dwarf_Macro_Op_Table and using that one.

Too bad we cannot fix the function signature because that would be an
API break. But this makes sense (thanks again for the references).

> Second, for .debug_macinfo.dwo in GNU DebugFission (generated by gcc
> -gdwarf-4 -gstrict-dwarf -gsplit-dwarf), the offset into .debug_line.dwo
> is implicitly 0.  Again, this isn't in any specification, but it's how
> GCC behaves in practice (Clang never generates macro information for
> DWARF 4 split DWARF).  Make get_macinfo_table default to 0 for split
> DWARF when it can't find DW_AT_stmt_list.

Makes sense, it cannot really be any other offset than zero.

Applied,

Mark
  

Patch

diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index d3f36cc8..be1e40bc 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -9,15 +9,17 @@ 
 	DW_FORM_strx, and DW_FORM_strx[1-4].
 	* dwarf_getmacros.c (get_macinfo_table): Replace assignment of
 	table->is_64bit with assignments of table->address_size and
-	table->offset_size.
+	table->offset_size.  Assume default DW_AT_stmt_list of 0 for split
+	DWARF.  Set table->dbg.
 	(get_table_for_offset): Ditto.
 	(read_macros): Get fake CU offset_size from table->offset_size instead
 	of table->is_64bit.
 	* dwarf_macro_getsrcfiles.c (dwarf_macro_getsrcfiles): Get
 	address_size for __libdw_getsrclines from table->address_size instead
-	of table->is_64bit.
+	of table->is_64bit.  Get dbg for __libdw_getsrclines from table->dbg
+	instead of dbg parameter, which is now unused.
 	* libdwP.h (Dwarf_Macro_Op_Table): Replace is_64bit with address_size
-	and offset_size.
+	and offset_size.  Add dbg.
 
 2023-02-22  Mark Wielaard  <mark@klomp.org>
 
diff --git a/libdw/dwarf_getmacros.c b/libdw/dwarf_getmacros.c
index b7d98af4..a3a78884 100644
--- a/libdw/dwarf_getmacros.c
+++ b/libdw/dwarf_getmacros.c
@@ -124,13 +124,19 @@  get_macinfo_table (Dwarf *dbg, Dwarf_Word macoff, Dwarf_Die *cudie)
     = INTUSE(dwarf_attr) (cudie, DW_AT_stmt_list, &attr_mem);
   Dwarf_Off line_offset = (Dwarf_Off) -1;
   if (attr != NULL)
-    if (unlikely (INTUSE(dwarf_formudata) (attr, &line_offset) != 0))
-      return NULL;
+    {
+      if (unlikely (INTUSE(dwarf_formudata) (attr, &line_offset) != 0))
+	return NULL;
+    }
+  else if (cudie->cu->unit_type == DW_UT_split_compile
+	   && dbg->sectiondata[IDX_debug_line] != NULL)
+    line_offset = 0;
 
   Dwarf_Macro_Op_Table *table = libdw_alloc (dbg, Dwarf_Macro_Op_Table,
 					     macinfo_data_size, 1);
   memcpy (table, macinfo_data, macinfo_data_size);
 
+  table->dbg = dbg;
   table->offset = macoff;
   table->sec_index = IDX_debug_macinfo;
   table->line_offset = line_offset;
@@ -263,6 +269,7 @@  get_table_for_offset (Dwarf *dbg, Dwarf_Word macoff,
 					     macop_table_size, 1);
 
   *table = (Dwarf_Macro_Op_Table) {
+    .dbg = dbg,
     .offset = macoff,
     .sec_index = IDX_debug_macro,
     .line_offset = line_offset,
diff --git a/libdw/dwarf_macro_getsrcfiles.c b/libdw/dwarf_macro_getsrcfiles.c
index 4e8deeeb..11c587af 100644
--- a/libdw/dwarf_macro_getsrcfiles.c
+++ b/libdw/dwarf_macro_getsrcfiles.c
@@ -36,6 +36,9 @@  int
 dwarf_macro_getsrcfiles (Dwarf *dbg, Dwarf_Macro *macro,
 			 Dwarf_Files **files, size_t *nfiles)
 {
+  /* This was needed before Dwarf_Macro_Op_Table stored the Dwarf handle.  */
+  (void)dbg;
+
   /* macro is declared NN */
   Dwarf_Macro_Op_Table *const table = macro->table;
   if (table->files == NULL)
@@ -71,7 +74,7 @@  dwarf_macro_getsrcfiles (Dwarf *dbg, Dwarf_Macro *macro,
 	 the same unit through dwarf_getsrcfiles, and the file names
 	 will be broken.  */
 
-      if (__libdw_getsrclines (dbg, line_offset, table->comp_dir,
+      if (__libdw_getsrclines (table->dbg, line_offset, table->comp_dir,
 			       table->address_size, NULL, &table->files) < 0)
 	table->files = (void *) -1;
     }
diff --git a/libdw/libdwP.h b/libdw/libdwP.h
index c3fe9f93..77959b3b 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -508,6 +508,8 @@  typedef struct
 /* Prototype table.  */
 typedef struct
 {
+  Dwarf *dbg;
+
   /* Offset of .debug_macro section.  */
   Dwarf_Off offset;