btf_loader relies on guessing base integral type size for enums and integers, which is unreliable. There doesn't seem to be a need for that, as all this information could be extracted from BTF information. Before: $ PAHOLE=~/local/pahole/build/pahole ./btfdiff ~/local/btf/libc-2.28.so.debug base_type__name_to_size: base_type _Float128 class__fixup_btf_bitfields: unknown base type name "_Float128"! base_type__name_to_size: base_type _Float128 class__fixup_btf_bitfields: unknown base type name "_Float128"! base_type__name_to_size: base_type _Float128 class__fixup_btf_bitfields: unknown base type name "_Float128"! base_type__name_to_size: base_type _Float128 class__fixup_btf_bitfields: unknown base type name "_Float128"! base_type__name_to_size: base_type _Float128 class__fixup_btf_bitfields: unknown base type name "_Float128"! base_type__name_to_size: base_type _Float128 class__fixup_btf_bitfields: unknown base type name "_Float128"! --- /tmp/btfdiff.dwarf.aV4wSL 2019-02-25 13:31:54.787923673 -0800 +++ /tmp/btfdiff.btf.22NQmJ 2019-02-25 13:31:54.802923668 -0800 @@ -461,9 +461,15 @@ struct La_x86_64_retval { uint64_t lrv_rdx; /* 8 8 */ La_x86_64_xmm lrv_xmm0; /* 16 16 */ La_x86_64_xmm lrv_xmm1; /* 32 16 */ - long double lrv_st0; /* 48 16 */ + long double lrv_st0; /* 48 8 */ + + /* XXX 8 bytes hole, try to pack */ + /* --- cacheline 1 boundary (64 bytes) --- */ - long double lrv_st1; /* 64 16 */ + long double lrv_st1; /* 64 8 */ + + /* XXX 8 bytes hole, try to pack */ + La_x86_64_vector lrv_vector0; /* 80 64 */ /* --- cacheline 2 boundary (128 bytes) was 16 bytes ago --- */ La_x86_64_vector lrv_vector1; /* 144 64 */ @@ -472,6 +478,7 @@ struct La_x86_64_retval { __int128 lrv_bnd1; /* 224 16 */ /* size: 240, cachelines: 4, members: 10 */ + /* sum members: 224, holes: 2, sum holes: 16 */ /* last cacheline: 48 bytes */ }; struct r_debug { @@ -2044,7 +2051,7 @@ union ieee754_float { } ieee_nan; /* 0 4 */ }; union ieee854_long_double { - long double d; /* 0 16 */ + long double d; /* 0 8 */ struct { unsigned int mantissa1:32; /* 0: 0 4 */ unsigned int mantissa0:32; /* 4: 0 4 */ @@ -2141,7 +2148,7 @@ struct ucontext_t { /* last cacheline: 8 bytes */ }; union ieee854_float128 { - _Float128 d; /* 0 16 */ + _Float128 d; /* 0 0 */ struct { unsigned int mantissa3:32; /* 0: 0 4 */ unsigned int mantissa2:32; /* 4: 0 4 */ @@ -2219,7 +2226,7 @@ union printf_arg { long unsigned int pa_u_long_int; /* 0 8 */ long long unsigned int pa_u_long_long_int; /* 0 8 */ double pa_double; /* 0 8 */ - long double pa_long_double; /* 0 16 */ + long double pa_long_double; /* 0 8 */ const char * pa_string; /* 0 8 */ const wchar_t * pa_wstring; /* 0 8 */ void * pa_pointer; /* 0 8 */ $ PAHOLE=~/local/pahole/build/pahole ./btfdiff ~/local/btf/libc-2.28.so.debug <empty output> Still good for kernel image: $ PAHOLE=~/local/pahole/build/pahole ./btfdiff ~/local/btf/vmlinux4 <empty output> Signed-off-by: Andrii Nakryiko <andriin@xxxxxx> --- btf_loader.c | 59 ++++++++++------------------------------------------ 1 file changed, 11 insertions(+), 48 deletions(-) diff --git a/btf_loader.c b/btf_loader.c index 62e7e30..3b4fb40 100644 --- a/btf_loader.c +++ b/btf_loader.c @@ -463,64 +463,27 @@ static int class__fixup_btf_bitfields(struct tag *tag, struct cu *cu, struct btf continue; pos->bitfield_offset = 0; + pos->byte_size = tag__size(type, cu); + pos->bit_size = pos->byte_size * 8; - uint16_t type_bit_size; - size_t integral_bit_size; - - switch (type->tag) { - case DW_TAG_enumeration_type: - type_bit_size = tag__type(type)->size; - /* Best we can do to check if this is a packed enum */ - if (is_power_of_2(type_bit_size)) - integral_bit_size = roundup(type_bit_size, 8); - else - integral_bit_size = sizeof(int) * 8; - break; - case DW_TAG_base_type: { - struct base_type *bt = tag__base_type(type); - char name[256]; - type_bit_size = bt->bit_size; - integral_bit_size = base_type__name_to_size(bt, cu); - if (integral_bit_size == 0) { - fprintf(stderr, "%s: unknown base type name \"%s\"!\n", - __func__, base_type__name(bt, cu, name, - sizeof(name))); - } - } - break; - default: - pos->byte_size = tag__size(type, cu); - pos->bit_size = pos->byte_size * 8; + /* bitfield fixup is needed for enums and base types only */ + if (type->tag != DW_TAG_base_type && type->tag != DW_TAG_enumeration_type) continue; - } - /* - * XXX: integral_bit_size can be zero if base_type__name_to_size doesn't - * know about the base_type name, so one has to add there when - * such base_type isn't found. pahole will put zero on the - * struct output so it should be easy to spot the name when - * such unlikely thing happens. - */ - pos->byte_size = integral_bit_size / 8; - pos->bit_size = type_bit_size; - - if (integral_bit_size == 0) { - pos->bit_size = 0; + /* if BTF data is incorrect and has size == 0, skip field, + * instead of crashing */ + if (pos->byte_size == 0) { continue; } if (pos->bitfield_size) { /* bitfields seem to be always aligned, no matter the packing */ - pos->byte_offset = pos->bit_offset / integral_bit_size * integral_bit_size / 8; - } else { - pos->byte_offset = pos->bit_offset / 8; - } - - - if (pos->bitfield_size) { + pos->byte_offset = pos->bit_offset / pos->bit_size * pos->bit_size / 8; pos->bitfield_offset = pos->bit_offset - pos->byte_offset * 8; if (!btfe->is_big_endian) - pos->bitfield_offset = integral_bit_size - pos->bitfield_offset - pos->bitfield_size; + pos->bitfield_offset = pos->bit_size - pos->bitfield_offset - pos->bitfield_size; + } else { + pos->byte_offset = pos->bit_offset / 8; } } -- 2.17.1