variants. */
const dwarf2_section_info §ion () const;
+ /* The section offset of the beginning of this unit in its section.
+
+ For a split DWARF unit, this is the offset in the .dwo section. */
+ sect_offset section_offset () const;
+
/* TU version of handle_DW_AT_stmt_list for read_type_unit_scope.
Create the set of symtabs used by this TU, or if this TU is sharing
symtabs with another TU and the symtabs have already been created
return *this->per_cu->section ();
}
+/* See cu.h.
+
+ This function is defined in this file (instead of cu.c) because it needs
+ to see the definition of struct dwo_unit. */
+
+sect_offset
+dwarf2_cu::section_offset () const
+{
+ if (this->dwo_unit != nullptr)
+ return this->dwo_unit->sect_off;
+ else
+ return this->per_cu->sect_off ();
+}
+
void
dwarf2_cu::setup_type_unit_groups (struct die_info *die)
{
dwarf2_per_objfile *per_objfile,
gdb::function_view<CORE_ADDR ()> get_frame_pc)
{
- sect_offset sect_off = per_cu->sect_off () + to_underlying (offset_in_cu);
+ /* For split DWARF, the section offset of PER_CU is the offset of the
+ skeleton CU in the main file, but OFFSET_IN_CU is relative to the start
+ of the CU in the .dwo file. We need to use the section offset of the unit
+ in the .dwo file in that case. */
+ dwarf2_cu *cu = per_objfile->get_cu (per_cu);
+ if (cu == nullptr)
+ cu = load_cu (per_cu, per_objfile, false);
+
+ /* We know this can't be a dummy CU, since we're executing something from
+ it. */
+ gdb_assert (cu != nullptr);
+
+ sect_offset sect_off = cu->section_offset () + to_underlying (offset_in_cu);
return dwarf2_fetch_die_loc_sect_off (sect_off, per_cu, per_objfile,
get_frame_pc);
--- /dev/null
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2026 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/>. */
+
+int
+main (void)
+{
+ return 0;
+}
--- /dev/null
+# Copyright 2026 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/>.
+
+# Test DW_OP_call2 and DW_OP_call4 in a .dwo file (split DWARF), to verify
+# that GDB correctly computes offsets when evaluating these operators.
+# See PR gdb/31772.
+#
+# The CU in the .dwo file is placed after a type unit, so that it is not at
+# offset 0. This is important to test that GDB correctly adds the CU offset
+# within the section when computing the target of DW_OP_call2/call4.
+
+load_lib dwarf.exp
+
+require dwarf2_support
+
+standard_testfile .c -dw.S
+
+set asm_file [standard_output_file $srcfile2]
+
+Dwarf::assemble $asm_file {
+ # Skeleton CU in the main file.
+ cu {
+ version 5
+ dwo_id 0x1234
+ } {
+ compile_unit {
+ DW_AT_dwo_name ${::gdb_test_file_name}-dw.dwo DW_FORM_strp
+ } {}
+ }
+
+ # Type unit in the .dwo file. This is placed before the CU to ensure
+ # it is not at offset 0 in .debug_info.dwo.
+ 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 dummy_type
+ }
+ }
+ }
+
+ # Compilation unit in the .dwo file.
+ cu {
+ fission 1
+ version 5
+ dwo_id 0x1234
+ label cu_start
+ } {
+ compile_unit {} {
+ declare_labels int_type dwarf_proc
+
+ int_type: DW_TAG_base_type {
+ DW_AT_byte_size 4 DW_FORM_sdata
+ DW_AT_encoding @DW_ATE_signed
+ DW_AT_name int
+ }
+
+ # DWARF procedure that multiplies the top of stack by 2.
+ dwarf_proc: DW_TAG_dwarf_procedure {
+ DW_AT_location {
+ DW_OP_lit2
+ DW_OP_mul
+ } SPECIAL_expr
+ }
+
+ # Variable using DW_OP_call2 (2-byte CU-relative offset).
+ # Pushes 5, calls the procedure (5 * 2 = 10).
+ DW_TAG_variable {
+ DW_AT_name var_call2
+ DW_AT_type :$int_type
+ DW_AT_location {
+ DW_OP_lit5
+ DW_OP_call2 "$dwarf_proc - $cu_start"
+ DW_OP_stack_value
+ } SPECIAL_expr
+ }
+
+ # Variable using DW_OP_call4 (4-byte CU-relative offset).
+ # Pushes 6, calls the procedure (6 * 2 = 12).
+ DW_TAG_variable {
+ DW_AT_name var_call4
+ DW_AT_type :$int_type
+ DW_AT_location {
+ DW_OP_lit6
+ DW_OP_call4 "$dwarf_proc - $cu_start"
+ DW_OP_stack_value
+ } SPECIAL_expr
+ }
+ }
+ }
+}
+
+set obj [standard_output_file "${testfile}-dw.o"]
+if {[build_executable_and_dwo_files "$testfile.exp" "${binfile}" {} \
+ [list $asm_file {nodebug split-dwo} $obj] \
+ [list $srcfile {nodebug}]]} {
+ return
+}
+
+clean_restart ${testfile}
+
+gdb_test "print var_call2" " = 10" "DW_OP_call2"
+gdb_test "print var_call4" " = 12" "DW_OP_call4"
_op .sleb128 $reg
}
+ proc _handle_DW_OP_call2 {offset} {
+ _op .2byte $offset
+ }
+
+ proc _handle_DW_OP_call4 {offset} {
+ _op .4byte $offset
+ }
+
proc _handle_default_OP {} {
# Do nothing; if arguments are passed, Tcl will cause an
# error.