From: Simon Marchi Date: Mon, 7 Apr 2025 17:52:01 +0000 (-0400) Subject: gdb/dwarf2: pass correct dwarf2_cu to lookup_dwo_id in create_cus_hash_table X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8ad92d35519a14ee31c6494be1c2eb8bdb52053d;p=thirdparty%2Fbinutils-gdb.git gdb/dwarf2: pass correct dwarf2_cu to lookup_dwo_id in create_cus_hash_table Commit 71a48752660b ("gdb/dwarf: remove create_dwo_cu_reader") introduced a regression when handling files compiled with "-gsplit-dwarf -fdebug-types-section" (at least with clang): $ cat test.cpp #include int main() { std::vector v; return v.size (); } $ clang++ -O0 test.cpp -g -gdwarf-5 -gsplit-dwarf -fdebug-types-section -o test $ ./gdb -nx -q --data-directory=data-directory ./test -ex "maint expand-symtabs" Reading symbols from ./test... /home/smarchi/src/binutils-gdb/gdb/dwarf2/read.c:6159: internal-error: setup_type_unit_groups: Assertion `per_cu->is_debug_types' failed. In the main file, we have a skeleton CU with a certain DWO ID: 0x00000000: Compile Unit: ..., unit_type = DW_UT_skeleton, ..., DWO_id = 0x146eaa4daf5deef2, ... In the .dwo file, the first unit is a type unit with a certain type signature: 0x00000000: Type Unit: ..., unit_type = DW_UT_split_type, ..., type_signature = 0xb499dcf29e2928c4, ... and the split compile unit matching the DWO ID from the skeleton from the main file comes later: 0x0000117f: Compile Unit: ..., unit_type = DW_UT_split_compile, ..., DWO_id = 0x146eaa4daf5deef2, ... The problem introduced by the aforementioned commit is that when creating a dwo_unit structure representing the type unit, we use the signature (DWO id) from the skeleton, instead of the signature from the type unit's header. As a result, all dwo_units get created with the same signature (the DWO id) and only the first unit gets inserted in the hash table. When looking up the comp unit by DWO ID later on, we wrongly find the type unit, and try to expand a type unit as a comp unit, hitting the assert. Before that commit, we passed `reader.cu ()` to lookup_dwo_id, which yields a dwarf2_cu built from parsing the type unit's header. This dwarf2_cu contains the comp_unit_header with the correct signature. Fix the code to use `reader.cu ()` again. Another thing that enables this bug is the fact that since DWARF 5, type and compile units are all in .debug_info, and therefore read by create_cus_hash_table, so they both end up in dwo_file::cus. Type units should end up in dwo_file::tus, otherwise they won't be found by lookup_dwo_cutu. This bug hasn't given me trouble so far, so I'm not fixing it right now, but it's on my todo list. The problem can be seen with some tests, when using the dwarf5-fission-debug-types board: $ make check TESTS="gdb.cp/expand-sals.exp" RUNTESTFLAGS="--target_board=dwarf5-fission-debug-types CC_FOR_TARGET=clang CXX_FOR_TARGET=clang++" Running /home/simark/src/binutils-gdb/gdb/testsuite/gdb.cp/expand-sals.exp ... FAIL: gdb.cp/expand-sals.exp: gdb_breakpoint: set breakpoint at main (GDB internal error) But this patch also adds a DWARF assembler-based test that triggers the internal error. Note that the new test does not use the build_executable_and_dwo_files proc, because I found that it is subtly broken and doesn't work to put multiple units in a single .dwo file. The debug abbrev offset field in the second unit's header would be 0, when it should have been something else. The problem is that no linking is ever done to generate the .dwo file, so the relocation that would apply for this field is never applied. Instead, I generate two DWARF debug infos separately and link the .dwo file using gdb_compile, it seems to work fine. Change-Id: I96f809c56f703e25f72b8622c32e6bb91de20d6a Approved-By: Tom Tromey --- diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c index 69e20cb776c..6e96afe65e1 100644 --- a/gdb/dwarf2/read.c +++ b/gdb/dwarf2/read.c @@ -6343,7 +6343,7 @@ create_cus_hash_table (dwarf2_cu *cu, dwo_file &dwo_file) continue; std::optional signature - = lookup_dwo_id (cu, reader.top_level_die ()); + = lookup_dwo_id (reader.cu (), reader.top_level_die ()); if (!signature.has_value ()) { complaint (_(DWARF_ERROR_PREFIX diff --git a/gdb/testsuite/gdb.dwarf2/fission-with-type-unit.c b/gdb/testsuite/gdb.dwarf2/fission-with-type-unit.c new file mode 100644 index 00000000000..a0f1b76175f --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/fission-with-type-unit.c @@ -0,0 +1,23 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2021-2024 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + . */ + +int +main (int argc, char **argv) +{ + return 0; +} diff --git a/gdb/testsuite/gdb.dwarf2/fission-with-type-unit.exp b/gdb/testsuite/gdb.dwarf2/fission-with-type-unit.exp new file mode 100644 index 00000000000..2d582602523 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/fission-with-type-unit.exp @@ -0,0 +1,105 @@ +# Copyright 2021-2024 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# This test is meant to reproduce a bug where having a DWO file with a type unit +# as the first unit would cause an internal error on CU expansion. + +load_lib dwarf.exp + +# This test can only be run on targets which support DWARF-2 and use gas. +require dwarf2_support + +standard_testfile .c -dw.S -dwo.S + +set main_asm_file [standard_output_file $srcfile2] +set dwo_asm_file [standard_output_file $srcfile3] + +# Debug info in the main file. +Dwarf::assemble $main_asm_file { + cu { + version 5 + dwo_id 0xF00D + } { + compile_unit { + {DW_AT_dwo_name ${::gdb_test_file_name}.dwo DW_FORM_strp} + } {} + } +} + +# Debug info in the DWO file. +Dwarf::assemble $dwo_asm_file { + tu { + fission 1 + version 5 + } 0xCAFE "the_type" { + type_unit {} { + the_type: base_type { + {DW_AT_byte_size 4 DW_FORM_sdata} + {DW_AT_encoding @DW_ATE_signed} + {DW_AT_name int} + } + } + } + + cu { + fission 1 + version 5 + dwo_id 0xF00D + } { + compile_unit {} { + declare_labels int4_type + + int4_type: DW_TAG_base_type { + {DW_AT_byte_size 4 DW_FORM_sdata} + {DW_AT_encoding @DW_ATE_signed} + {DW_AT_name int} + } + + DW_TAG_variable { + {DW_AT_name global_var} + {DW_AT_type :$int4_type} + {DW_AT_location { + DW_OP_const1u 12 + DW_OP_stack_value + } SPECIAL_expr} + } + } + } +} + +# Build main file. +if { [build_executable "${testfile}.exp" $binfile \ + [list ${srcfile} ${main_asm_file}] {nodebug}] } { + return +} + +# Build DWO file. +set dwo_file [standard_output_file ${testfile}.dwo] +if { [gdb_compile_shlib $dwo_asm_file $dwo_file nodebug] != "" } { + return +} + +clean_restart ${testfile} + +# This would cause an internal error. +gdb_test_no_output "maint expand-symtabs" + +# Sanity check that the CU was correctly loaded. +gdb_test "print global_var" " = 12" + +# Test again just to see if the symbol can be found without having expanded the +# symtab first. +clean_restart ${testfile} +gdb_test "print global_var" " = 12" "print global_var without symtab expansion"