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>
*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,
/* 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,
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);
}
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
{
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);