[binutils-gdb] gdb/dwarf: fix spurious error when encountering dummy CU

Simon Marchi simark@sourceware.org
Tue Mar 18 13:40:07 GMT 2025


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=aab6de1613df693059a6a2b505cc8f20d479d109

commit aab6de1613df693059a6a2b505cc8f20d479d109
Author: Simon Marchi <simon.marchi@polymtl.ca>
Date:   Mon Mar 17 10:34:29 2025 -0400

    gdb/dwarf: fix spurious error when encountering dummy CU
    
    I built an application with -gsplit-dwarf (i.e. dwo), and some CUs are
    considered "dummy" by the DWARF reader.  That is, the top-level DIE
    (DW_TAG_compile_unit) does not have any children.  Here's the skeleton:
    
        0x0000c0cb: Compile Unit: length = 0x0000001d, format = DWARF32, version = 0x0005, unit_type = DW_UT_skeleton, abbr_offset = 0x529b, addr_size = 0x08, DWO_id = 0x0ed2693dd2a756dc (next unit at 0x0000c0ec)
    
        0x0000c0df: DW_TAG_skeleton_unit
                      DW_AT_stmt_list [DW_FORM_sec_offset]      (0x09dee00f)
                      DW_AT_dwo_name [DW_FORM_strp]     ("CMakeFiles/lib_crl.dir/crl/dispatch/crl_dispatch_queue.cpp.dwo")
                      DW_AT_comp_dir [DW_FORM_strp]     ("/home/simark/src/tdesktop/build-relwithdebuginfo-split-nogz/Telegram/lib_crl")
                      DW_AT_GNU_pubnames [DW_FORM_flag_present] (true)
    
    And here's the entire debug info in the .dwo file:
    
        .debug_info.dwo contents:
        0x00000000: Compile Unit: length = 0x0000001a, format = DWARF32, version = 0x0005, unit_type = DW_UT_split_compile, abbr_offset = 0x0000, addr_size = 0x08, DWO_id = 0x0ed2693dd2a756dc (next unit at 0x0000001e)
    
        0x00000014: DW_TAG_compile_unit
                      DW_AT_producer [DW_FORM_strx]     ("GNU C++20 14.2.1 20250207 -mno-direct-extern-access -mtune=generic -march=x86-64 -gsplit-dwarf -g3 -gz=none -O2 -std=gnu++20 -fPIC -fno-strict-aliasing")
                      DW_AT_language [DW_FORM_data1]    (DW_LANG_C_plus_plus_14)
                      DW_AT_name [DW_FORM_strx] ("/home/simark/src/tdesktop/Telegram/lib_crl/crl/dispatch/crl_dispatch_queue.cpp")
                      DW_AT_comp_dir [DW_FORM_strx]     ("/home/simark/src/tdesktop/build-relwithdebuginfo-split-nogz/Telegram/lib_crl")
    
    When loading the binary in GDB, I see some warnings:
    
        $ ./gdb -q -nx --data-directory=data-directory -ex 'maint set dwarf sync on' -ex  "file /home/simark/src/tdesktop/build-relwithdebuginfo-split-nogz/telegram-desktop"
        Reading symbols from /home/simark/src/tdesktop/build-relwithdebuginfo-split-nogz/telegram-desktop...
        DWARF Error: unexpected tag 'DW_TAG_skeleton_unit' at offset 0xc0cb
        DWARF Error: unexpected tag 'DW_TAG_skeleton_unit' at offset 0xc152
        DWARF Error: unexpected tag 'DW_TAG_skeleton_unit' at offset 0xc194
        DWARF Error: unexpected tag 'DW_TAG_skeleton_unit' at offset 0xc1b5
        (gdb)
    
    It turns out that these errors are not really justified.  What happens
    is:
    
     - cutu_reader::read_cutu_die_from_dwo return 0, indicating that the CU
       is "dummy"
     - back in cutu_reader::cutu_reader, we omit setting m_top_level_die to
       the DIE from the dwo file, meaning that m_top_level_die keeps
       pointing to the DIE from the main file (DW_TAG_skeleton_unit)
     - later, in cutu_reader::prepare_one_comp_unit, there is a check that
       m_top_level_die->tag is one of DW_TAG_{compile,partial,type}_unit,
       which triggers
    
    My proposal to fix this is to set m_top_level_die even if the CU is
    dummy.  Even if the top-level DIE does not have any children, I don't
    see any reason to leave cutu_reader::m_top_level_die in a different
    state than when the CU is not dummy.
    
    While at it, set m_dummy_p directly in read_cutu_die_from_dwo, instead
    of returning a value and having the caller do it.  This is all inside
    cutu_reader anyway.
    
    Change-Id: I483a68a369bb461a8dfa5bf2106ab1d6a0067198
    Approved-By: Tom Tromey <tom@tromey.com>

Diff:
---
 gdb/dwarf2/read.c | 37 ++++++++++---------------------------
 gdb/dwarf2/read.h | 10 +++++-----
 2 files changed, 15 insertions(+), 32 deletions(-)

diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 01dfff2b250..60cd2d5e008 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -2775,11 +2775,9 @@ cutu_reader::init_cu_die_reader (dwarf2_cu *cu, dwarf2_section_info *section,
 
    *RESULT_DWO_ABBREV_TABLE will be filled in with the abbrev table allocated
    from the dwo.  Since *RESULT_READER references this abbrev table, it must be
-   kept around for at least as long as *RESULT_READER.
+   kept around for at least as long as *RESULT_READER.  */
 
-   The result is non-zero if a valid (non-dummy) DIE was found.  */
-
-int
+void
 cutu_reader::read_cutu_die_from_dwo (dwarf2_cu *cu, dwo_unit *dwo_unit,
 				     die_info *stub_comp_unit_die,
 				     const char *stub_comp_dir,
@@ -2918,9 +2916,7 @@ cutu_reader::read_cutu_die_from_dwo (dwarf2_cu *cu, dwo_unit *dwo_unit,
   /* Skip dummy compilation units.  */
   if (m_info_ptr >= begin_info_ptr + dwo_unit->length
       || peek_abbrev_code (abfd, m_info_ptr) == 0)
-    return 0;
-
-  return 1;
+    m_dummy_p = true;
 }
 
 /* Return the signature of the compile unit, if found. In DWARF 4 and before,
@@ -3020,16 +3016,9 @@ cutu_reader::init_tu_and_read_dwo_dies (dwarf2_per_cu *this_cu,
      abbrev table.  When reading DWOs with skeletonless TUs, all the TUs
      could share abbrev tables.  */
 
-  if (read_cutu_die_from_dwo (cu, sig_type->dwo_unit,
-			      NULL /* stub_comp_unit_die */,
-			      sig_type->dwo_unit->dwo_file->comp_dir,
-			      &m_top_level_die, &m_dwo_abbrev_table)
-      == 0)
-    {
-      /* Dummy die.  */
-      m_dummy_p = true;
-    }
-
+  read_cutu_die_from_dwo (cu, sig_type->dwo_unit, NULL /* stub_comp_unit_die */,
+			  sig_type->dwo_unit->dwo_file->comp_dir,
+			  &m_top_level_die, &m_dwo_abbrev_table);
   prepare_one_comp_unit (cu, pretend_language);
 }
 
@@ -3218,16 +3207,10 @@ cutu_reader::cutu_reader (dwarf2_per_cu *this_cu,
 	      dwo_unit = lookup_dwo_unit (cu, m_top_level_die, dwo_name);
 	      if (dwo_unit != NULL)
 		{
-		  if (read_cutu_die_from_dwo (cu, dwo_unit, m_top_level_die,
-					      nullptr, &dwo_comp_unit_die,
-					      &m_dwo_abbrev_table)
-		      == 0)
-		    {
-		      /* Dummy die.  */
-		      m_dummy_p = true;
-		    }
-		  else
-		    m_top_level_die = dwo_comp_unit_die;
+		  read_cutu_die_from_dwo (cu, dwo_unit, m_top_level_die,
+					  nullptr, &dwo_comp_unit_die,
+					  &m_dwo_abbrev_table);
+		  m_top_level_die = dwo_comp_unit_die;
 		}
 	      else
 		{
diff --git a/gdb/dwarf2/read.h b/gdb/dwarf2/read.h
index d498eeb00e0..0fe51eef5c2 100644
--- a/gdb/dwarf2/read.h
+++ b/gdb/dwarf2/read.h
@@ -982,11 +982,11 @@ private:
 				  dwarf2_cu *existing_cu,
 				  enum language pretend_language);
 
-  int read_cutu_die_from_dwo (dwarf2_cu *cu, dwo_unit *dwo_unit,
-			      die_info *stub_comp_unit_die,
-			      const char *stub_comp_dir,
-			      die_info **result_comp_unit_die,
-			      abbrev_table_up *result_dwo_abbrev_table);
+  void read_cutu_die_from_dwo (dwarf2_cu *cu, dwo_unit *dwo_unit,
+			       die_info *stub_comp_unit_die,
+			       const char *stub_comp_dir,
+			       die_info **result_comp_unit_die,
+			       abbrev_table_up *result_dwo_abbrev_table);
 
   void prepare_one_comp_unit (struct dwarf2_cu *cu,
 			      enum language pretend_language);


More information about the Gdb-cvs mailing list