Introduce apply_bit_offset_to_field helper function

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.
This commit is contained in:
Tom Tromey
2025-04-18 08:54:52 -06:00
parent 1d9fb3ba19
commit ee580641bc
3 changed files with 72 additions and 40 deletions

View File

@@ -9940,8 +9940,6 @@ static void
dwarf2_add_field (struct field_info *fip, struct die_info *die, dwarf2_add_field (struct field_info *fip, struct die_info *die,
struct dwarf2_cu *cu) struct dwarf2_cu *cu)
{ {
struct objfile *objfile = cu->per_objfile->objfile;
struct gdbarch *gdbarch = objfile->arch ();
struct nextfield *new_field; struct nextfield *new_field;
struct attribute *attr; struct attribute *attr;
struct field *fp; 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); attr = dwarf2_attr (die, DW_AT_bit_offset, cu);
if (attr != nullptr && attr->form_is_constant ()) if (attr != nullptr && attr->form_is_constant ())
{ {
ULONGEST bit_offset = attr->unsigned_constant ().value_or (0); LONGEST 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
{
/* 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); LONGEST anonymous_size = 0;
if (attr != nullptr && attr->form_is_constant ()) 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 /* The size of the anonymous object containing
indicated size (in bytes). */ the bit field is explicit, so use the
anonymous_size = attr->unsigned_constant ().value_or (0); 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 ());
} }
apply_bit_offset_to_field (*fp, bit_offset, anonymous_size);
} }
/* Get name of field. */ /* Get name of field. */

View File

@@ -2678,6 +2678,44 @@ compute_variant_fields (struct type *type,
/* See gdbtypes.h. */ /* 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 void
resolve_dynamic_field (struct field &field, resolve_dynamic_field (struct field &field,
const property_addr_info *addr_stack, const property_addr_info *addr_stack,

View File

@@ -2641,6 +2641,29 @@ extern void resolve_dynamic_field (struct field &field,
const struct property_addr_info *addr_stack, const struct property_addr_info *addr_stack,
const frame_info_ptr &frame); 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 struct type *check_typedef (struct type *);
extern void check_stub_method_group (struct type *, int); extern void check_stub_method_group (struct type *, int);