# Copyright (C) 2026 Free Software Foundation, Inc. # Copyright (C) 2026 Advanced Micro Devices, Inc. All rights reserved. # 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 exercises the case where a DWARF expression leads the dwarf # machinery to try to read past a given register's end. This should be # handled gracefully by GDB. load_lib "dwarf.exp" require dwarf2_support # This test will store a 128 bits variable in a register too small to # contain the entire value. Select a suitable register which is less # than 128 bits in size. if { [is_amd64_regs_target] } { # Use RAX, a 64 bits register. set dwarf_regnum 0 set regname "rax" } else { verbose "Skipping ${gdb_test_file_name} for current architecture." unsupported "$gdb_test_file_name" return } standard_testfile main.c -dw.S set dwarf_file [standard_output_file $srcfile2] Dwarf::assemble $dwarf_file { get_func_info main cu {} { DW_TAG_compile_unit { {DW_AT_language @DW_LANG_C} {DW_AT_name $::srcfile} {DW_AT_comp_dir /tmp} } { declare_labels int_label foo_t_label bitfield_t_label int_label: DW_TAG_base_type { {DW_AT_name int} {DW_AT_byte_size 4 DW_FORM_udata} {DW_AT_encoding @DW_ATE_signed} } foo_t_label: DW_TAG_structure_type { {DW_AT_name foo_t} {DW_AT_byte_size 16 DW_FORM_sdata} } { DW_TAG_member { {DW_AT_name a} {DW_AT_data_member_location 0 DW_FORM_data1} {DW_AT_type :$int_label} } DW_TAG_member { {DW_AT_name b} {DW_AT_data_member_location 4 DW_FORM_data1} {DW_AT_type :$int_label} } DW_TAG_member { {DW_AT_name c} {DW_AT_data_member_location 8 DW_FORM_data1} {DW_AT_type :$int_label} } DW_TAG_member { {DW_AT_name d} {DW_AT_data_member_location 12 DW_FORM_data1} {DW_AT_type :$int_label} } } bitfield_t_label: DW_TAG_structure_type { {DW_AT_name bitfield_t} {DW_AT_byte_size 1 DW_FORM_sdata} } { DW_TAG_member { {DW_AT_name a} {DW_AT_type :$int_label} {DW_AT_bit_size 1 DW_FORM_sdata} {DW_AT_data_bit_offset 0 DW_FORM_sdata} } DW_TAG_member { {DW_AT_name b} {DW_AT_type :$int_label} {DW_AT_bit_size 1 DW_FORM_sdata} {DW_AT_data_bit_offset 1 DW_FORM_sdata} } DW_TAG_member { {DW_AT_name c} {DW_AT_type :$int_label} {DW_AT_bit_size 1 DW_FORM_sdata} {DW_AT_data_bit_offset 2 DW_FORM_sdata} } DW_TAG_member { {DW_AT_name d} {DW_AT_type :$int_label} {DW_AT_bit_size 1 DW_FORM_sdata} {DW_AT_data_bit_offset 3 DW_FORM_sdata} } DW_TAG_member { {DW_AT_name e} {DW_AT_type :$int_label} {DW_AT_bit_size 1 DW_FORM_sdata} {DW_AT_data_bit_offset 4 DW_FORM_sdata} } } DW_TAG_subprogram { {DW_AT_name main} {DW_AT_low_pc $main_start DW_FORM_addr} {DW_AT_high_pc $main_end DW_FORM_addr} {DW_AT_type :$int_label} } { DW_TAG_variable { {DW_AT_name var_piece} {DW_AT_type :$foo_t_label} {DW_AT_location { DW_OP_regx $::dwarf_regnum DW_OP_piece 16 } SPECIAL_expr} } DW_TAG_variable { {DW_AT_name var_reg} {DW_AT_type :$foo_t_label} {DW_AT_location { DW_OP_regx $::dwarf_regnum } SPECIAL_expr} } DW_TAG_variable { {DW_AT_name var_reg_past_the_end} {DW_AT_type :$foo_t_label} {DW_AT_location { DW_OP_regx $::dwarf_regnum DW_OP_constu 8 DW_OP_LLVM_offset } SPECIAL_expr} } DW_TAG_variable { {DW_AT_name var_bitfield} {DW_AT_type :$bitfield_t_label} {DW_AT_location { DW_OP_regx $::dwarf_regnum DW_OP_constu 62 DW_OP_LLVM_bit_offset } SPECIAL_expr} } } } } } if { [prepare_for_testing "failed to prepare" $testfile \ [list $srcfile $dwarf_file] {nodebug}] } { return } if { ![runto_main] } { return } # The test assumes a register size of 64 bits, ensure we have this. set regsize [get_sizeof "\$$regname" ""] gdb_assert {$regsize == 8} "ensure register size" gdb_test "p/x var_piece" "= {a = $::hex, b = $::hex, c = , d = }" # Read a variable larger than the register holding it, with a simple register # location description. gdb_test "p/x var_reg" "= {a = $::hex, b = $::hex, c = , d = }" # Read a value fully past the end of the register. gdb_test "p/x var_reg_past_the_end" "= " # Read a 1-byte value 2 bits away from the end of the register. GDB needs # to be able to read less than one byte (2 bits), bits 2-7 are optimized out. gdb_test "p/x var_bitfield" "= {a = $::hex, b = $::hex, c = , d = , e = }"