* [PATCH] Handle base type without DW_AT_byte_size
@ 2025-04-25 14:18 Tom Tromey
2025-04-29 17:09 ` Kevin Buettner
0 siblings, 1 reply; 2+ messages in thread
From: Tom Tromey @ 2025-04-25 14:18 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
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.
---
gdb/dwarf2/read.c | 67 ++++++++++++++++------------
gdb/testsuite/gdb.dwarf2/intbits.c | 3 ++
gdb/testsuite/gdb.dwarf2/intbits.exp | 19 +++++++-
3 files changed, 59 insertions(+), 30 deletions(-)
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 2523ca86959..a010113b3d3 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 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"
base-commit: 5363deffcfb1c1825db3a8446d377a0ad56eff70
--
2.49.0
^ permalink raw reply [flat|nested] 2+ messages in thread* Re: [PATCH] Handle base type without DW_AT_byte_size
2025-04-25 14:18 [PATCH] Handle base type without DW_AT_byte_size Tom Tromey
@ 2025-04-29 17:09 ` Kevin Buettner
0 siblings, 0 replies; 2+ messages in thread
From: Kevin Buettner @ 2025-04-29 17:09 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
On Fri, 25 Apr 2025 08:18:13 -0600
Tom Tromey <tromey@adacore.com> wrote:
> 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.
> ---
> gdb/dwarf2/read.c | 67
> ++++++++++++++++------------ gdb/testsuite/gdb.dwarf2/intbits.c |
> 3 ++ gdb/testsuite/gdb.dwarf2/intbits.exp | 19 +++++++-
> 3 files changed, 59 insertions(+), 30 deletions(-)
I've verified that the new tests fail with an unpatched GDB and
pass with your patch.
Also, the patch itself LGTM.
Tested-by: Kevin Buettner <kevinb@redhat.com>
Approved-by: Kevin Buettner <kevinb@redhat.com>
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2025-04-29 17:10 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-04-25 14:18 [PATCH] Handle base type without DW_AT_byte_size Tom Tromey
2025-04-29 17:09 ` Kevin Buettner
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox