aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Tromey <tromey@adacore.com>2025-04-25 08:13:36 -0600
committerTom Tromey <tromey@adacore.com>2025-04-29 11:34:49 -0600
commit48d0ac705c45cb588a8e6d19ee911bc225c897cf (patch)
tree2916bf012082517567d779b19488042893825a91
parenta7175864d96765b291276cf3a6508b78ad3a9b23 (diff)
downloadbinutils-48d0ac705c45cb588a8e6d19ee911bc225c897cf.zip
binutils-48d0ac705c45cb588a8e6d19ee911bc225c897cf.tar.gz
binutils-48d0ac705c45cb588a8e6d19ee911bc225c897cf.tar.bz2
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 <kevinb@redhat.com> Approved-by: Kevin Buettner <kevinb@redhat.com>
-rw-r--r--gdb/dwarf2/read.c67
-rw-r--r--gdb/testsuite/gdb.dwarf2/intbits.c3
-rw-r--r--gdb/testsuite/gdb.dwarf2/intbits.exp19
3 files changed, 59 insertions, 30 deletions
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 6b7f2c7..a177a05 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<ULONGEST> byte_size;
+ if (attr != nullptr)
+ byte_size = attr->unsigned_constant ();
+ attr = dwarf2_attr (die, DW_AT_bit_size, cu);
+ std::optional<ULONGEST> 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<ULONGEST> 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<ULONGEST> 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 82e6ae8..909d283 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 7b50e15..ff1d69a 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"