]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Introduce apply_bit_offset_to_field helper function
authorTom Tromey <tromey@adacore.com>
Fri, 18 Apr 2025 14:54:52 +0000 (08:54 -0600)
committerTom Tromey <tromey@adacore.com>
Tue, 6 May 2025 15:01:55 +0000 (09:01 -0600)
This patch makes a new function, apply_bit_offset_to_field, that is
used to handle the logic of DW_AT_bit_offset.  Currently there is just
a single caller, but the next patch will change this.

gdb/dwarf2/read.c
gdb/gdbtypes.c
gdb/gdbtypes.h

index 0747a8b7aa3b77d8f338621b262292bc4b8c9b06..46639990a5e551fc9c85be22e9d7ad61c63173e3 100644 (file)
@@ -9940,8 +9940,6 @@ static void
 dwarf2_add_field (struct field_info *fip, struct die_info *die,
                  struct dwarf2_cu *cu)
 {
-  struct objfile *objfile = cu->per_objfile->objfile;
-  struct gdbarch *gdbarch = objfile->arch ();
   struct nextfield *new_field;
   struct attribute *attr;
   struct field *fp;
@@ -10008,46 +10006,19 @@ dwarf2_add_field (struct field_info *fip, struct die_info *die,
       attr = dwarf2_attr (die, DW_AT_bit_offset, cu);
       if (attr != nullptr && attr->form_is_constant ())
        {
-         ULONGEST bit_offset = attr->unsigned_constant ().value_or (0);
-         if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
-           {
-             /* For big endian bits, the DW_AT_bit_offset gives the
-                additional bit offset from the MSB of the containing
-                anonymous object to the MSB of the field.  We don't
-                have to do anything special since we don't need to
-                know the size of the anonymous object.  */
-             fp->set_loc_bitpos (fp->loc_bitpos () + bit_offset);
-           }
-         else
+         LONGEST bit_offset = attr->unsigned_constant ().value_or (0);
+
+         LONGEST anonymous_size = 0;
+         attr = dwarf2_attr (die, DW_AT_byte_size, cu);
+         if (attr != nullptr && attr->form_is_constant ())
            {
-             /* For little endian bits, compute the bit offset to the
-                MSB of the anonymous object, subtract off the number of
-                bits from the MSB of the field to the MSB of the
-                object, and then subtract off the number of bits of
-                the field itself.  The result is the bit offset of
-                the LSB of the field.  */
-             int anonymous_size;
-
-             attr = dwarf2_attr (die, DW_AT_byte_size, cu);
-             if (attr != nullptr && attr->form_is_constant ())
-               {
-                 /* The size of the anonymous object containing
-                    the bit field is explicit, so use the
-                    indicated size (in bytes).  */
-                 anonymous_size = attr->unsigned_constant ().value_or (0);
-               }
-             else
-               {
-                 /* The size of the anonymous object containing
-                    the bit field must be inferred from the type
-                    attribute of the data member containing the
-                    bit field.  */
-                 anonymous_size = fp->type ()->length ();
-               }
-             fp->set_loc_bitpos (fp->loc_bitpos ()
-                                 + anonymous_size * bits_per_byte
-                                 - bit_offset - fp->bitsize ());
+             /* The size of the anonymous object containing
+                the bit field is explicit, so use the
+                indicated size (in bytes).  */
+             anonymous_size = attr->unsigned_constant ().value_or (0);
            }
+
+         apply_bit_offset_to_field (*fp, bit_offset, anonymous_size);
        }
 
       /* Get name of field.  */
index fb1e8cb09637f15876fa7d2b0393955a66a43a0a..2535aad2c3cc433d1512dbfd94b961f2a6abaf76 100644 (file)
@@ -2678,6 +2678,44 @@ compute_variant_fields (struct type *type,
 
 /* See gdbtypes.h.  */
 
+void
+apply_bit_offset_to_field (struct field &field, LONGEST bit_offset,
+                          LONGEST explicit_byte_size)
+{
+  struct type *field_type = field.type ();
+  struct gdbarch *gdbarch = field_type->arch ();
+  LONGEST current_bitpos = field.loc_bitpos ();
+
+  if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+    {
+      /* For big endian bits, the DW_AT_bit_offset gives the
+        additional bit offset from the MSB of the containing
+        anonymous object to the MSB of the field.  We don't
+        have to do anything special since we don't need to
+        know the size of the anonymous object.  */
+      field.set_loc_bitpos (current_bitpos + bit_offset);
+    }
+  else
+    {
+      /* For little endian bits, compute the bit offset to the
+        MSB of the anonymous object, subtract off the number of
+        bits from the MSB of the field to the MSB of the
+        object, and then subtract off the number of bits of
+        the field itself.  The result is the bit offset of
+        the LSB of the field.  */
+      LONGEST object_size = explicit_byte_size;
+      if (object_size == 0)
+       object_size = field_type->length ();
+
+      field.set_loc_bitpos (current_bitpos
+                           + 8 * object_size
+                           - bit_offset
+                           - field.bitsize ());
+    }
+}
+
+/* See gdbtypes.h.  */
+
 void
 resolve_dynamic_field (struct field &field,
                       const property_addr_info *addr_stack,
index 52d03c40466deed229816c1e18376146a0487f80..67b4bf035ef6635f7ceaacc783c81b4331afd9f5 100644 (file)
@@ -2641,6 +2641,29 @@ extern void resolve_dynamic_field (struct field &field,
                                   const struct property_addr_info *addr_stack,
                                   const frame_info_ptr &frame);
 
+/* A helper function that handles the DWARF semantics for
+   DW_AT_bit_offset.
+
+   DWARF 3 specified DW_AT_bit_offset in a funny way, making it simple
+   to use on big-endian targets but somewhat difficult for
+   little-endian.  This function handles the logic here.
+
+   While DW_AT_bit_offset was deprecated in DWARF 4 (and removed
+   entirely from DWARF 5), it is still useful because it is the only
+   way to describe a field that appears at a non-constant bit
+   offset.
+
+   FIELD is updated in-place.  It is assumed that FIELD already has a
+   constant bit position.  BIT_OFFSET is the value of the
+   DW_AT_bit_offset attribute, and EXPLICIT_BYTE_SIZE is either the
+   value of a DW_AT_byte_size from the field's DIE -- indicating an
+   explicit size of the enclosing anonymous object -- or it may be 0,
+   indicating that the field's type size should be used.  */
+
+extern void apply_bit_offset_to_field (struct field &field,
+                                      LONGEST bit_offset,
+                                      LONGEST explicit_byte_size);
+
 extern struct type *check_typedef (struct type *);
 
 extern void check_stub_method_group (struct type *, int);