From: Tom Tromey Date: Fri, 25 Apr 2025 14:13:36 +0000 (-0600) Subject: Handle base type without DW_AT_byte_size X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=48d0ac705c45cb588a8e6d19ee911bc225c897cf;p=thirdparty%2Fbinutils-gdb.git Handle base type without DW_AT_byte_size DWARF says that a base type can have DW_AT_bit_size, without DW_AT_byte_size. However, gdb does not correctly handle this; in fact, it crashes, as pointed out in this LLVM merge request: https://github.com/llvm/llvm-project/pull/137123 This patch reworks the base type size logic a bit to handle this situation. Tested-by: Kevin Buettner Approved-by: Kevin Buettner --- diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c index 6b7f2c78476..a177a056e13 100644 --- a/gdb/dwarf2/read.c +++ b/gdb/dwarf2/read.c @@ -13634,7 +13634,6 @@ read_base_type (struct die_info *die, struct dwarf2_cu *cu) struct type *type; struct attribute *attr; ULONGEST encoding = 0; - int bits = 0; const char *name; attr = dwarf2_attr (die, DW_AT_encoding, cu); @@ -13644,9 +13643,33 @@ read_base_type (struct die_info *die, struct dwarf2_cu *cu) if (value.has_value ()) encoding = *value; } + attr = dwarf2_attr (die, DW_AT_byte_size, cu); + std::optional byte_size; + if (attr != nullptr) + byte_size = attr->unsigned_constant (); + attr = dwarf2_attr (die, DW_AT_bit_size, cu); + std::optional bit_size; if (attr != nullptr) - bits = attr->unsigned_constant ().value_or (0) * TARGET_CHAR_BIT; + bit_size = attr->unsigned_constant (); + + attr = dwarf2_attr (die, DW_AT_data_bit_offset, cu); + std::optional bit_offset; + if (attr != nullptr) + bit_offset = attr->unsigned_constant (); + + int bits = 0; + if (byte_size.has_value ()) + bits = TARGET_CHAR_BIT * *byte_size; + else if (bit_size.has_value ()) + bits = align_up (*bit_size, 8); + else + { + /* No size, so arrange for an error type. */ + complaint (_("DW_TAG_base_type has neither bit- nor byte-size")); + encoding = (ULONGEST) -1; + } + name = dwarf2_full_name (nullptr, die, cu); if (!name) complaint (_("DW_AT_name missing from DW_TAG_base_type")); @@ -13792,35 +13815,21 @@ read_base_type (struct die_info *die, struct dwarf2_cu *cu) type->set_endianity_is_not_default (not_default); - if (TYPE_SPECIFIC_FIELD (type) == TYPE_SPECIFIC_INT) + /* If both a byte size and bit size were provided, then that means + that not every bit in the object contributes to the value. */ + if (TYPE_SPECIFIC_FIELD (type) == TYPE_SPECIFIC_INT + && byte_size.has_value () + && bit_size.has_value ()) { - attr = dwarf2_attr (die, DW_AT_bit_size, cu); - if (attr != nullptr && attr->form_is_constant ()) + /* DWARF says: If this attribute is omitted a default data bit + offset of zero is assumed. */ + ULONGEST offset = bit_offset.value_or (0); + + /* Only use the attributes if they make sense together. */ + if (*bit_size + offset <= 8 * type->length ()) { - unsigned real_bit_size = attr->unsigned_constant ().value_or (0); - if (real_bit_size >= 0 && real_bit_size <= 8 * type->length ()) - { - attr = dwarf2_attr (die, DW_AT_data_bit_offset, cu); - /* Only use the attributes if they make sense together. */ - std::optional bit_offset; - if (attr == nullptr) - bit_offset = 0; - else if (attr->form_is_constant ()) - { - bit_offset = attr->unsigned_constant (); - if (bit_offset.has_value () - && *bit_offset + real_bit_size > 8 * type->length ()) - bit_offset.reset (); - } - if (bit_offset.has_value ()) - { - TYPE_MAIN_TYPE (type)->type_specific.int_stuff.bit_size - = real_bit_size; - if (attr != nullptr) - TYPE_MAIN_TYPE (type)->type_specific.int_stuff.bit_offset - = *bit_offset; - } - } + TYPE_MAIN_TYPE (type)->type_specific.int_stuff.bit_size = *bit_size; + TYPE_MAIN_TYPE (type)->type_specific.int_stuff.bit_offset = offset; } } diff --git a/gdb/testsuite/gdb.dwarf2/intbits.c b/gdb/testsuite/gdb.dwarf2/intbits.c index 82e6ae8a052..909d2837b9f 100644 --- a/gdb/testsuite/gdb.dwarf2/intbits.c +++ b/gdb/testsuite/gdb.dwarf2/intbits.c @@ -41,6 +41,9 @@ unsigned char be30_1_off[4] = { 0x80, 0, 0, 2 }; here, to catch any situation where gdb tries to use the memory. */ unsigned char u32_0[4] = { 0xff, 0xff, 0xff, 0xff }; +/* An 8 bit slot holding a 3 bit value. */ +unsigned char just_bit_0 = 5; + int main (void) { diff --git a/gdb/testsuite/gdb.dwarf2/intbits.exp b/gdb/testsuite/gdb.dwarf2/intbits.exp index 7b50e15a0cd..ff1d69ae226 100644 --- a/gdb/testsuite/gdb.dwarf2/intbits.exp +++ b/gdb/testsuite/gdb.dwarf2/intbits.exp @@ -36,7 +36,7 @@ Dwarf::assemble ${asm_file} { {DW_AT_language @DW_LANG_C_plus_plus} } { declare_labels i7_type u1_type u17_type u31_type \ - u31_1_type u32_0_type u0_0_type be30_1_type + u31_1_type u32_0_type u0_0_type be30_1_type just_bit_type i7_type: DW_TAG_base_type { {DW_AT_encoding @DW_ATE_signed} @@ -167,6 +167,20 @@ Dwarf::assemble ${asm_file} { {DW_AT_location {DW_OP_addr [gdb_target_symbol "u32_0"]} SPECIAL_expr} } + + just_bit_type: DW_TAG_base_type { + {DW_AT_encoding @DW_ATE_unsigned} + {DW_AT_name "just_bit_type"} + {DW_AT_bit_size 3 DW_FORM_udata} + } + + DW_TAG_variable { + {DW_AT_name "v_just_bit"} + {DW_AT_type :${just_bit_type}} + {DW_AT_external 1 DW_FORM_flag} + {DW_AT_location {DW_OP_addr [gdb_target_symbol "just_bit_0"]} + SPECIAL_expr} + } } } } @@ -197,3 +211,6 @@ gdb_test "x/4xb &v_u32_1_off" ":\t0x0e\t0x00\t0x00\t0x00" gdb_test "print v_be30_1_off" "= 1" gdb_test "print v_be30_1_off = 7" " = 7" gdb_test "x/4xb &v_be30_1_off" ":\t0x00\t0x00\t0x00\t0x0e" + +gdb_test "print/x v_just_bit" " = 0x5" +gdb_test "print/x (just_bit_type) 5" " = 0x5"