dwo_unit->length = cu->header.get_length_with_initial ();
}
+ /* Record some information found in the header. This will be needed when
+ evaluating DWARF expressions in the context of this unit, for instance. */
+ per_cu->set_addr_size (cu->header.addr_size);
+ per_cu->set_offset_size (cu->header.offset_size);
+ per_cu->set_ref_addr_size (cu->header.version == 2
+ ? cu->header.addr_size
+ : cu->header.offset_size);
+
dwo_abbrev_section->read (objfile);
m_dwo_abbrev_table
= abbrev_table::read (dwo_abbrev_section, cu->header.abbrev_sect_off);
gdb_assert (this_cu.sect_off () == cu->header.sect_off);
this_cu.set_length (cu->header.get_length_with_initial ());
}
+
+ /* Record some information found in the header. This will be needed
+ when evaluating DWARF expressions in the context of this unit, for
+ instance. */
+ this_cu.set_addr_size (cu->header.addr_size);
+ this_cu.set_offset_size (cu->header.offset_size);
+ this_cu.set_ref_addr_size (cu->header.version == 2
+ ? cu->header.addr_size
+ : cu->header.offset_size);
}
/* Skip dummy compilation units. */
/* See read.h. */
-const unit_head *
-dwarf2_per_cu::get_header () const
-{
- if (!m_header_read_in)
- {
- const gdb_byte *info_ptr
- = this->section ()->buffer + to_underlying (this->sect_off ());
-
- read_unit_head (&m_header, info_ptr, this->section (), ruh_kind::COMPILE);
-
- m_header_read_in = true;
- }
-
- return &m_header;
-}
-
-/* See read.h. */
-
-int
-dwarf2_per_cu::addr_size () const
-{
- return this->get_header ()->addr_size;
-}
-
-/* See read.h. */
-
-int
-dwarf2_per_cu::offset_size () const
-{
- return this->get_header ()->offset_size;
-}
-
-/* See read.h. */
-
-int
-dwarf2_per_cu::ref_addr_size () const
-{
- const unit_head *header = this->get_header ();
-
- if (header->version == 2)
- return header->addr_size;
- else
- return header->offset_size;
-}
-
-/* See read.h. */
-
void
dwarf2_per_cu::set_lang (enum language lang, dwarf_source_language dw_lang)
{
tu_read (false),
lto_artificial (false),
queued (false),
- m_header_read_in (false),
files_read (false),
scanned (false),
m_section (section),
any of the current compilation units are processed. */
packed<bool, 1> queued;
-private:
- /* True if HEADER has been read in. */
- mutable packed<bool, 1> m_header_read_in;
-
-public:
/* True if we've tried to read the file table. There will be no
point in trying to read it again next time. */
packed<bool, 1> files_read;
not. */
std::atomic<bool> scanned;
+private:
+ /* Sizes for an address, an offset, and a section offset. These fields are
+ set by cutu_reader when the unit is read. */
+ std::uint8_t m_addr_size = 0;
+ std::uint8_t m_offset_size = 0;
+ std::uint8_t m_ref_addr_size = 0;
+
+public:
/* Our index in the unshared "symtabs" vector. */
unsigned index = 0;
/* Backlink to the owner of this. */
dwarf2_per_bfd *m_per_bfd;
- /* DWARF header of this unit. Note that dwarf2_cu reads its own version of
- the header, which may differ from this one, since it may pass
- rch_kind::TYPE to read_unit_head, whereas for dwarf2_per_cu we always pass
- ruh_kind::COMPILE. */
- mutable unit_head m_header;
-
public:
/* The file and directory for this CU. This is cached so that we
don't need to re-examine the DWO in some situations. This may be
bool is_dwz () const
{ return m_is_dwz; }
- /* Get the header of this per_cu, reading it if necessary. */
- const unit_head *get_header () const;
-
/* Return the address size given in the compilation unit header for
this CU. */
- int addr_size () const;
+ std::uint8_t addr_size () const
+ {
+ gdb_assert (m_addr_size != 0);
+ return m_addr_size;
+ }
+
+ /* Set the address size given in the compilation unit header for
+ this CU. */
+ void set_addr_size (std::uint8_t addr_size)
+ { m_addr_size = addr_size; }
/* Return the offset size given in the compilation unit header for
this CU. */
- int offset_size () const;
+ std::uint8_t offset_size () const
+ {
+ gdb_assert (m_offset_size != 0);
+ return m_offset_size;
+ }
+
+ /* Set the offset size given in the compilation unit header for
+ this CU. */
+ void set_offset_size (std::uint8_t offset_size)
+ { m_offset_size = offset_size; }
+
+ /* Return the DW_FORM_ref_addr size given in the compilation unit
+ header for this CU. */
+ std::uint8_t ref_addr_size () const
+ {
+ gdb_assert (m_ref_addr_size != 0);
+ return m_ref_addr_size;
+ }
/* Return the DW_FORM_ref_addr size given in the compilation unit
header for this CU. */
- int ref_addr_size () const;
+ void set_ref_addr_size (std::uint8_t ref_addr_size)
+ { m_ref_addr_size = ref_addr_size; }
/* Return length of this CU. */
unsigned int length () const
--- /dev/null
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2025 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
+ <http://www.gnu.org/licenses/>. */
+
+unsigned char buf[] = { 0x11, 0x22, 0x22, 0x11, };
+
+int
+main (void)
+{
+ return 0;
+}
--- /dev/null
+# Copyright 2025 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 <http://www.gnu.org/licenses/>.
+
+# This test is meant to reproduce a bug occurring in those specific
+# circumstances:
+#
+# - Split DWARF (debug info in a .dwo file)
+# - A type unit in the .dwo file, with a corresponding stub in the main file
+# - A GDB index
+# - We evaluate a DWARF expression in the context of that type unit
+#
+# The test doesn't create a GDB index, but that can be done by running it
+# with the cc-with-gdb-index board.
+
+load_lib dwarf.exp
+
+require dwarf2_support
+
+standard_testfile .c -dw.S
+
+set asm_file [standard_output_file $srcfile2]
+
+Dwarf::assemble $asm_file {
+ set outdir [standard_output_file ""]
+ set cu_debug_addr_label "invalid"
+
+ # Debug info in the DWO file.
+
+ # Definition of "int".
+ tu {
+ fission 1
+ version 4
+ } 0xCAFE1 the_type_1 {
+ type_unit {} {
+ the_type_1: base_type {
+ DW_AT_byte_size 4 DW_FORM_sdata
+ DW_AT_encoding @DW_ATE_signed
+ DW_AT_name int
+ }
+ }
+ }
+
+ # Definition of structure type "struct_type".
+ tu {
+ fission 1
+ version 4
+ } 0xCAFE2 the_type_2 {
+ type_unit {} {
+ the_type_2: DW_TAG_structure_type {
+ DW_AT_name struct_type
+ DW_AT_byte_size 4 DW_FORM_data1
+ } {
+ DW_TAG_member {
+ DW_AT_name field
+ DW_AT_type 0xCAFE1 DW_FORM_ref_sig8
+
+ # This is the expression that is going to be evaluated
+ # by printing the variable.
+ DW_AT_data_member_location {
+ # In order to coax GDB to actually run this
+ # expression in the evaluator, it needs to contain
+ # something that will make decode_locdesc unable
+ # to reduce it to a constant. That's what these 3
+ # operations (which are ultimately a no-op) are for.
+ # Note that there is an implicit
+ # DW_OP_push_object_address done before the
+ # expression is evaluated.
+ DW_OP_dup
+ DW_OP_deref_size 1
+ DW_OP_drop
+ } SPECIAL_expr
+ }
+ }
+ }
+ }
+
+ # Definition of the CU.
+ cu {
+ fission 1
+ version 4
+ } {
+ set cu_debug_addr_label [debug_addr_label]
+
+ compile_unit {
+ DW_AT_GNU_dwo_id 0xF00D DW_FORM_data8
+ } {
+ DW_TAG_variable {
+ DW_AT_name global_var
+ DW_AT_type 0xCAFE2 DW_FORM_ref_sig8
+ DW_AT_location {
+ DW_OP_GNU_addr_index [gdb_target_symbol buf]
+ } SPECIAL_expr
+ }
+ }
+ }
+
+ # Debug info in the main file.
+
+ # Stub for "int" type unit.
+ tu {
+ version 4
+ } 0xCAFE1 "" {
+ type_unit {
+ DW_AT_GNU_dwo_name ${::gdb_test_file_name}.dwo DW_FORM_strp
+ DW_AT_comp_dir ${outdir}
+ } {
+ }
+ }
+
+ # Stub for "struct_type" type unit.
+ tu {
+ version 4
+ } 0xCAFE2 "" {
+ type_unit {
+ DW_AT_GNU_dwo_name ${::gdb_test_file_name}.dwo DW_FORM_strp
+ DW_AT_comp_dir ${outdir}
+ } {
+ }
+ }
+
+ # Stub for the CU.
+ cu {
+ version 4
+ } {
+ compile_unit {
+ DW_AT_GNU_dwo_name ${::gdb_test_file_name}.dwo DW_FORM_strp
+ DW_AT_comp_dir ${outdir}
+ DW_AT_GNU_dwo_id 0xF00D DW_FORM_data8
+ DW_AT_GNU_addr_base $cu_debug_addr_label
+ } {}
+ }
+}
+
+set object_file [standard_output_file ${testfile}.o]
+if { [build_executable_and_dwo_files "${testfile}.exp" ${binfile} {nodebug} \
+ [list $asm_file {nodebug split-dwo} ${object_file}] \
+ [list $srcfile {nodebug}]] } {
+ return -1
+}
+
+proc run_test { testfile } {
+ clean_restart ${testfile}
+
+ # This print would cause the DW_AT_data_member_location expression to be
+ # evaluated and cause the crash.
+ gdb_test "print/x global_var" " = {field = 0x11222211}"
+}
+
+run_test $testfile
+
+# Try adding a gdb-index and dwarf-5 style index, and then rerun the test.
+foreach_with_prefix index_type { gdb dwarf5 } {
+ set binfile_with_index ${binfile}-idx-${index_type}
+ set testfile_with_index ${testfile}-idx-${index_type}
+
+ remote_exec build "cp $binfile $binfile_with_index"
+
+ if { $index_type eq "gdb" } {
+ set style ""
+ } else {
+ set style "-dwarf-5"
+ }
+
+ # This is expected to fail if the binary already has an index.
+ if {[ensure_gdb_index $binfile_with_index $style] != 1} {
+ unsupported "couldn't add $index_type index"
+ return
+ }
+
+ run_test $testfile_with_index
+}