dwarf_loader: Support DW_AT_data_bit_offset
This appeared in DWARF4 but is supported only in gcc's -gdwarf-5, support it in a way that makes the output be the same for both cases: $ gcc -gdwarf-4 -c examples/dwarf5/bf.c $ pahole bf.o struct pea { long int a:1; /* 0: 0 8 */ long int b:1; /* 0: 1 8 */ long int c:1; /* 0: 2 8 */ /* XXX 29 bits hole, try to pack */ /* Bitfield combined with next fields */ int after_bitfield; /* 4 4 */ /* size: 8, cachelines: 1, members: 4 */ /* sum members: 4 */ /* sum bitfield members: 3 bits, bit holes: 1, sum bit holes: 29 bits */ /* last cacheline: 8 bytes */ }; $ gcc -gdwarf-5 -c examples/dwarf5/bf.c $ pahole bf.o struct pea { long int a:1; /* 0: 0 8 */ long int b:1; /* 0: 1 8 */ long int c:1; /* 0: 2 8 */ /* XXX 29 bits hole, try to pack */ /* Bitfield combined with next fields */ int after_bitfield; /* 4 4 */ /* size: 8, cachelines: 1, members: 4 */ /* sum members: 4 */ /* sum bitfield members: 3 bits, bit holes: 1, sum bit holes: 29 bits */ /* last cacheline: 8 bytes */ }; $ Now with an integer before the bitfield: $ cat examples/dwarf5/bf.c struct pea { int before_bitfield; long a:1, b:1, c:1; int after_bitfield; } p; $ gcc -gdwarf-4 -c examples/dwarf5/bf.c $ pahole bf.o struct pea { int before_bitfield; /* 0 4 */ /* Bitfield combined with previous fields */ long int a:1; /* 0:32 8 */ long int b:1; /* 0:33 8 */ long int c:1; /* 0:34 8 */ /* XXX 29 bits hole, try to pack */ int after_bitfield; /* 8 4 */ /* size: 16, cachelines: 1, members: 5 */ /* sum members: 8 */ /* sum bitfield members: 3 bits, bit holes: 1, sum bit holes: 29 bits */ /* padding: 4 */ /* last cacheline: 16 bytes */ }; $ gcc -gdwarf-5 -c examples/dwarf5/bf.c $ pahole bf.o struct pea { int before_bitfield; /* 0 4 */ /* Bitfield combined with previous fields */ long int a:1; /* 0:32 8 */ long int b:1; /* 0:33 8 */ long int c:1; /* 0:34 8 */ /* XXX 29 bits hole, try to pack */ int after_bitfield; /* 8 4 */ /* size: 16, cachelines: 1, members: 5 */ /* sum members: 8 */ /* sum bitfield members: 3 bits, bit holes: 1, sum bit holes: 29 bits */ /* padding: 4 */ /* last cacheline: 16 bytes */ }; $ And an array of long integers at the start, before the combination of an integer with a long integer bitfield: $ cat examples/dwarf5/bf.c struct pea { long array[3]; int before_bitfield; long a:1, b:1, c:1; int after_bitfield; } p; $ gcc -gdwarf-4 -c examples/dwarf5/bf.c $ pahole bf.o struct pea { long int array[3]; /* 0 24 */ int before_bitfield; /* 24 4 */ /* Bitfield combined with previous fields */ long int a:1; /* 24:32 8 */ long int b:1; /* 24:33 8 */ long int c:1; /* 24:34 8 */ /* XXX 29 bits hole, try to pack */ int after_bitfield; /* 32 4 */ /* size: 40, cachelines: 1, members: 6 */ /* sum members: 32 */ /* sum bitfield members: 3 bits, bit holes: 1, sum bit holes: 29 bits */ /* padding: 4 */ /* last cacheline: 40 bytes */ }; $ gcc -gdwarf-5 -c examples/dwarf5/bf.c $ pahole bf.o struct pea { long int array[3]; /* 0 24 */ int before_bitfield; /* 24 4 */ /* Bitfield combined with previous fields */ long int a:1; /* 24:32 8 */ long int b:1; /* 24:33 8 */ long int c:1; /* 24:34 8 */ /* XXX 29 bits hole, try to pack */ int after_bitfield; /* 32 4 */ /* size: 40, cachelines: 1, members: 6 */ /* sum members: 32 */ /* sum bitfield members: 3 bits, bit holes: 1, sum bit holes: 29 bits */ /* padding: 4 */ /* last cacheline: 40 bytes */ }; $ Reported-by: Mark Wielaard <mark@klomp.org> Tested-by: "Daniel P. Berrangé" <berrange@redhat.com> Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1919965 Link: https://lore.kernel.org/dwarves/20210128121122.GA775562@kernel.org/ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
c692e8ac5c
commit
b91b19840b
|
@ -776,27 +776,36 @@ static struct class_member *class_member__new(Dwarf_Die *die, struct cu *cu,
|
|||
|
||||
Dwarf_Attribute attr;
|
||||
|
||||
if (dwarf_attr(die, DW_AT_data_member_location, &attr) != NULL) {
|
||||
member->byte_offset = __attr_offset(&attr);
|
||||
member->has_bit_offset = dwarf_attr(die, DW_AT_data_bit_offset, &attr) != NULL;
|
||||
|
||||
if (member->has_bit_offset) {
|
||||
member->bit_offset = __attr_offset(&attr);
|
||||
// byte_offset and bitfield_offset will be recalculated later, when
|
||||
// we discover the size of this bitfield base type.
|
||||
} else {
|
||||
member->is_static = !in_union;
|
||||
if (dwarf_attr(die, DW_AT_data_member_location, &attr) != NULL) {
|
||||
member->byte_offset = __attr_offset(&attr);
|
||||
} else {
|
||||
member->is_static = !in_union;
|
||||
}
|
||||
|
||||
/*
|
||||
* Bit offset calculated here is valid only for byte-aligned
|
||||
* fields. For bitfields on little-endian archs we need to
|
||||
* adjust them taking into account byte size of the field,
|
||||
* which might not be yet known. So we'll re-calculate bit
|
||||
* offset later, in class_member__cache_byte_size.
|
||||
*/
|
||||
member->bit_offset = member->byte_offset * 8;
|
||||
member->bitfield_offset = attr_numeric(die, DW_AT_bit_offset);
|
||||
}
|
||||
|
||||
/*
|
||||
* Bit offset calculated here is valid only for byte-aligned
|
||||
* fields. For bitfields on little-endian archs we need to
|
||||
* adjust them taking into account byte size of the field,
|
||||
* which might not be yet known. So we'll re-calculate bit
|
||||
* offset later, in class_member__cache_byte_size.
|
||||
*/
|
||||
member->bit_offset = member->byte_offset * 8;
|
||||
/*
|
||||
* If DW_AT_byte_size is not present, byte size will be
|
||||
* determined later in class_member__cache_byte_size using
|
||||
* base integer/enum type
|
||||
*/
|
||||
member->byte_size = attr_numeric(die, DW_AT_byte_size);
|
||||
member->bitfield_offset = attr_numeric(die, DW_AT_bit_offset);
|
||||
member->bitfield_size = attr_numeric(die, DW_AT_bit_size);
|
||||
member->bit_hole = 0;
|
||||
member->bitfield_end = 0;
|
||||
|
@ -2275,24 +2284,31 @@ static int class_member__cache_byte_size(struct tag *tag, struct cu *cu,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* For little-endian architectures, DWARF data emitted by gcc/clang
|
||||
* specifies bitfield offset as an offset from the highest-order bit
|
||||
* of an underlying integral type (e.g., int) to a highest-order bit
|
||||
* of a bitfield. E.g., for bitfield taking first 5 bits of int-backed
|
||||
* bitfield, bit offset will be 27 (sizeof(int) - 0 offset - 5 bit
|
||||
* size), which is very counter-intuitive and isn't a natural
|
||||
* extension of byte offset, which on little-endian points to
|
||||
* lowest-order byte. So here we re-adjust bitfield offset to be an
|
||||
* offset from lowest-order bit of underlying integral type to
|
||||
* a lowest-order bit of a bitfield. This makes bitfield offset
|
||||
* a natural extension of byte offset for bitfields and is uniform
|
||||
* with how big-endian bit offsets work.
|
||||
*/
|
||||
if (cu->little_endian) {
|
||||
member->bitfield_offset = member->bit_size - member->bitfield_offset - member->bitfield_size;
|
||||
if (!member->has_bit_offset) {
|
||||
/*
|
||||
* For little-endian architectures, DWARF data emitted by gcc/clang
|
||||
* specifies bitfield offset as an offset from the highest-order bit
|
||||
* of an underlying integral type (e.g., int) to a highest-order bit
|
||||
* of a bitfield. E.g., for bitfield taking first 5 bits of int-backed
|
||||
* bitfield, bit offset will be 27 (sizeof(int) - 0 offset - 5 bit
|
||||
* size), which is very counter-intuitive and isn't a natural
|
||||
* extension of byte offset, which on little-endian points to
|
||||
* lowest-order byte. So here we re-adjust bitfield offset to be an
|
||||
* offset from lowest-order bit of underlying integral type to
|
||||
* a lowest-order bit of a bitfield. This makes bitfield offset
|
||||
* a natural extension of byte offset for bitfields and is uniform
|
||||
* with how big-endian bit offsets work.
|
||||
*/
|
||||
if (cu->little_endian)
|
||||
member->bitfield_offset = member->bit_size - member->bitfield_offset - member->bitfield_size;
|
||||
|
||||
member->bit_offset = member->byte_offset * 8 + member->bitfield_offset;
|
||||
} else {
|
||||
// DWARF5 has DW_AT_data_bit_offset, offset in bits from the
|
||||
// start of the container type (struct, class, etc).
|
||||
member->byte_offset = member->bit_offset / 8;
|
||||
member->bitfield_offset = member->bit_offset - member->byte_offset * 8;
|
||||
}
|
||||
member->bit_offset = member->byte_offset * 8 + member->bitfield_offset;
|
||||
|
||||
/* make sure bitfield offset is non-negative */
|
||||
if (member->bitfield_offset < 0) {
|
||||
|
|
|
@ -899,6 +899,7 @@ static inline int function__inlined(const struct function *func)
|
|||
* @accessibility - DW_ACCESS_{public,protected,private}
|
||||
* @virtuality - DW_VIRTUALITY_{none,virtual,pure_virtual}
|
||||
* @hole - If there is a hole before the next one (or the end of the struct)
|
||||
* @has_bit_offset: Don't recalcule this, it came from the debug info (DWARF5's DW_AT_data_bit_offset)
|
||||
*/
|
||||
struct class_member {
|
||||
struct tag tag;
|
||||
|
@ -915,6 +916,7 @@ struct class_member {
|
|||
uint32_t alignment;
|
||||
uint8_t visited:1;
|
||||
uint8_t is_static:1;
|
||||
uint8_t has_bit_offset:1;
|
||||
uint8_t accessibility:2;
|
||||
uint8_t virtuality:2;
|
||||
uint16_t hole;
|
||||
|
|
Loading…
Reference in New Issue