From: Tom Tromey Date: Fri, 18 Apr 2025 14:54:52 +0000 (-0600) Subject: Introduce apply_bit_offset_to_field helper function X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ee580641bc5fbd5086e02cc94eb2dbc70ebb4b5d;p=thirdparty%2Fbinutils-gdb.git 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. --- diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c index 0747a8b7aa3..46639990a5e 100644 --- a/gdb/dwarf2/read.c +++ b/gdb/dwarf2/read.c @@ -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. */ diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c index fb1e8cb0963..2535aad2c3c 100644 --- a/gdb/gdbtypes.c +++ b/gdb/gdbtypes.c @@ -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, diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h index 52d03c40466..67b4bf035ef 100644 --- a/gdb/gdbtypes.h +++ b/gdb/gdbtypes.h @@ -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);