Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [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

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