Em Wed, Mar 13, 2019 at 11:07:36PM -0700, Andrii Nakryiko escreveu: > Bitfield offsets can be negative, if field "borrows" few bits from > following aligned field. This causes a bunch of surprises down the line > in pahole's logic (e.g., for hole calculation logic), so instead of > waiting till printf routines adjust this for display, adjust them early > and keep less surprising semantics. > +++ b/btf_loader.c > @@ -482,6 +482,12 @@ static int class__fixup_btf_bitfields(struct tag *tag, struct cu *cu, struct btf > pos->bitfield_offset = pos->bit_offset - pos->byte_offset * 8; > if (!btfe->is_big_endian) > pos->bitfield_offset = pos->bit_size - pos->bitfield_offset - pos->bitfield_size; > + /* re-adjust bitfield offset if it is negative */ > + if (pos->bitfield_offset < 0) { > + pos->bitfield_offset += pos->bit_size; > + pos->byte_offset += pos->byte_size; > + pos->bit_offset = pos->byte_offset * 8 + pos->bitfield_offset; > + } > } else { > pos->byte_offset = pos->bit_offset / 8; > } While testing this one I noticed this output: [acme@quaco pahole]$ pahole -F btf -C ieee80211_tx_rate examples/vmlinux-aarch64 struct ieee80211_tx_rate { s8 idx; /* 0 1 */ /* Bitfield combined with previous fields */ u16 count:5; /* 0: 8 2 */ u16 flags:11; /* 0:13 2 */ /* size: 3, cachelines: 1, members: 3 */ /* padding: 1 */ /* last cacheline: 3 bytes */ }; [acme@quaco pahole]$ The message is confusing, as count:5 is not being combined with previous fields, i.e. the previous field has 8 bits and all those bits are being used by 'idx'. The original struct definition in include/net/mac80211.h: struct ieee80211_tx_rate { s8 idx; u16 count:5, flags:11; } __packed; So we could infer that this is a packed struct, because the next field doesn't come u16 aligned, not that it is a bitfield combined with previous fields. The DWARF info: <1><27639>: Abbrev Number: 16 (DW_TAG_structure_type) <2763a> DW_AT_name : (indirect string, offset: 0x19d5a): ieee80211_tx_rate <2763e> DW_AT_byte_size : 3 <27643> DW_AT_sibling : <0x27678> <2><27647>: Abbrev Number: 19 (DW_TAG_member) <27648> DW_AT_name : idx <27650> DW_AT_type : <0x11d> <27654> DW_AT_data_member_location: 0 <2><27655>: Abbrev Number: 30 (DW_TAG_member) <27656> DW_AT_name : (indirect string, offset: 0x1789d): count <2765e> DW_AT_type : <0x144> <27662> DW_AT_byte_size : 2 <27663> DW_AT_bit_size : 5 <27664> DW_AT_bit_offset : 8 <27665> DW_AT_data_member_location: 0 <2><27666>: Abbrev Number: 30 (DW_TAG_member) <27667> DW_AT_name : (indirect string, offset: 0xc978): flags <2766f> DW_AT_type : <0x144> <27673> DW_AT_byte_size : 2 <27674> DW_AT_bit_size : 11 <27675> DW_AT_bit_offset : 5 <27676> DW_AT_data_member_location: 1 So the message has to take into account if the previous field has a bitfield_size != 0, no? I have to look at the other csets, perhaps you do this there? I'm just trying to test it patch by patch to see what changes after each one. - Arnaldo