From: Tom Tromey Date: Tue, 14 Oct 2025 19:26:30 +0000 (-0600) Subject: Handle dynamic DW_AT_bit_size X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=157da75362cc082f8f8067155d137dfe98ac230c;p=thirdparty%2Fbinutils-gdb.git Handle dynamic DW_AT_bit_size gnat-llvm will sometimes emit a structure that that uses DW_AT_bit_size with an expression to compute the bit size of a record. I believe this is a DWARF extension. This patch implements support for this in gdb. Reviewed-By: Keith Seitz --- diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c index 49c5fd2323a..802a4550322 100644 --- a/gdb/dwarf2/read.c +++ b/gdb/dwarf2/read.c @@ -11193,7 +11193,27 @@ read_structure_type (struct die_info *die, struct dwarf2_cu *cu) } } else - type->set_length (0); + { + attr = dwarf2_attr (die, DW_AT_bit_size, cu); + if (attr != nullptr) + { + if (attr->form_is_constant ()) + { + ULONGEST len = attr->unsigned_constant ().value_or (0); + type->set_length (align_up (len, 8) / 8); + } + else + { + struct dynamic_prop prop; + if (attr_to_dynamic_prop (attr, die, cu, &prop, cu->addr_type ())) + type->add_dyn_prop (DYN_PROP_BIT_SIZE, prop); + + type->set_length (0); + } + } + else + type->set_length (0); + } maybe_set_alignment (cu, die, type); diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c index ac622d54201..63d6f4c0ceb 100644 --- a/gdb/gdbtypes.c +++ b/gdb/gdbtypes.c @@ -2890,10 +2890,21 @@ resolve_dynamic_type_internal (struct type *type, return type; std::optional type_length; + dynamic_prop_node_kind type_kind = DYN_PROP_BYTE_SIZE; prop = type->dyn_prop (DYN_PROP_BYTE_SIZE); - if (prop != NULL + if (prop != nullptr && dwarf2_evaluate_property (prop, frame, addr_stack, &value)) type_length = value; + else + { + prop = type->dyn_prop (DYN_PROP_BIT_SIZE); + if (prop != nullptr + && dwarf2_evaluate_property (prop, frame, addr_stack, &value)) + { + type_kind = DYN_PROP_BIT_SIZE; + type_length = align_up (value, 8) / 8; + } + } if (type->code () == TYPE_CODE_TYPEDEF) { @@ -2969,7 +2980,7 @@ resolve_dynamic_type_internal (struct type *type, if (type_length.has_value ()) { resolved_type->set_length (*type_length); - resolved_type->remove_dyn_prop (DYN_PROP_BYTE_SIZE); + resolved_type->remove_dyn_prop (type_kind); } /* Resolve data_location attribute. */ diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h index e66701c7029..eee0445b5eb 100644 --- a/gdb/gdbtypes.h +++ b/gdb/gdbtypes.h @@ -133,8 +133,9 @@ DEF_ENUM_FLAGS_TYPE (enum type_instance_flag_value, type_instance_flags); ((t)->dyn_prop (DYN_PROP_VARIANT_PARTS) != nullptr) /* * True if this type has a dynamic length. */ -#define TYPE_HAS_DYNAMIC_LENGTH(t) \ - ((t)->dyn_prop (DYN_PROP_BYTE_SIZE) != nullptr) +#define TYPE_HAS_DYNAMIC_LENGTH(t) \ + (((t)->dyn_prop (DYN_PROP_BYTE_SIZE) != nullptr) \ + || ((t)->dyn_prop (DYN_PROP_BIT_SIZE) != nullptr)) /* * Instruction-space delimited type. This is for Harvard architectures which have separate instruction and data address spaces (and perhaps @@ -456,6 +457,9 @@ enum dynamic_prop_node_kind /* A property holding the size of the type. */ DYN_PROP_BYTE_SIZE, + + /* A property holding the size of the type, in bits. */ + DYN_PROP_BIT_SIZE, }; /* * List for dynamic type attributes. */ diff --git a/gdb/testsuite/gdb.dwarf2/dynamic-bit-size.exp b/gdb/testsuite/gdb.dwarf2/dynamic-bit-size.exp new file mode 100644 index 00000000000..cd57a939196 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dynamic-bit-size.exp @@ -0,0 +1,95 @@ +# 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 . + +# Test DW_AT_bit_size with an expression. This is a DWARF extension. + +load_lib dwarf.exp + +# This test can only be run on targets which support DWARF-2 and use gas. +require dwarf2_support + +standard_testfile ada-array-bound.c -debug.S + +# Set up the DWARF for the test. + +set asm_file [standard_output_file $srcfile2] +Dwarf::assemble $asm_file { + global srcdir subdir srcfile + + cu {} { + DW_TAG_compile_unit { + DW_AT_language @DW_LANG_Ada95 + DW_AT_name $srcfile + } { + declare_labels byte array struct + + byte: DW_TAG_base_type { + DW_AT_byte_size 1 DW_FORM_sdata + DW_AT_encoding @DW_ATE_unsigned + DW_AT_name byte + } + + array: DW_TAG_array_type { + DW_AT_name array_type + DW_AT_type :$byte + } { + DW_TAG_subrange_type { + DW_AT_type :$byte + DW_AT_upper_bound 3 DW_FORM_sdata + } + } + + struct: DW_TAG_structure_type { + DW_AT_name discriminated + # This "expression" is constant, but the point of this + # is to test the code path for evaluating an + # expression here. + DW_AT_bit_size { + DW_OP_const1u 32 + } SPECIAL_expr + } { + DW_TAG_member { + DW_AT_name disc + DW_AT_type :$byte + DW_AT_data_member_location 0 DW_FORM_sdata + } + + DW_TAG_member { + DW_AT_name nums + DW_AT_type :$array + DW_AT_data_bit_offset 8 DW_FORM_udata + } + } + + DW_TAG_variable { + DW_AT_name "value" + DW_AT_type :$struct + DW_AT_external 1 DW_FORM_flag + DW_AT_location { + DW_OP_addr [gdb_target_symbol "our_data"] + } SPECIAL_expr + } + } + } +} + +if {[prepare_for_testing "failed to prepare" ${testfile} \ + [list $srcfile $asm_file] {nodebug}]} { + return +} + +gdb_test_no_output "set language ada" +gdb_test "print value" \ + [string_to_regexp " = (disc => 3, nums => (7, 11, 13))"]