From: Tom Tromey <tromey@adacore.com>
To: gdb-patches@sourceware.org
Cc: Tom Tromey <tromey@adacore.com>
Subject: [PATCH] Handle base type without DW_AT_byte_size
Date: Fri, 25 Apr 2025 08:18:13 -0600 [thread overview]
Message-ID: <20250425141813.826220-1-tromey@adacore.com> (raw)
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
next reply other threads:[~2025-04-25 14:18 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-04-25 14:18 Tom Tromey [this message]
2025-04-29 17:09 ` Kevin Buettner
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250425141813.826220-1-tromey@adacore.com \
--to=tromey@adacore.com \
--cc=gdb-patches@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox