From aab6de1613df693059a6a2b505cc8f20d479d109 Mon Sep 17 00:00:00 2001 From: Simon Marchi Date: Mon, 17 Mar 2025 10:34:29 -0400 Subject: [PATCH] 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 --- 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); -- 2.39.5