dwarves_fprintf: Handle negative bit_offsets in packed structs with bitfields
Andrii reported that structs with bitfields and with __attribute__((packed)) were not producing correct output, that is because pahole and friends didn't knew about something Yonghong discovered: DW_AT_bit_offset may be negative when a bitfield straddles a 4 byte boundary, fix it so that we produce a saner output: $ cat examples/yonghong/packed_bitfield.c struct packed { char x1: 1; char x2: 3; char x3: 3; int y1: 7; int y2: 20; } __attribute__((packed)); struct packed g; $ cc -g -c examples/yonghong/packed_bitfield.c $ readelf -wi packed_bitfield.o | grep bit_offset <37> DW_AT_bit_offset : 7 <46> DW_AT_bit_offset : 4 <55> DW_AT_bit_offset : 1 <64> DW_AT_bit_offset : 18 <73> DW_AT_bit_offset : -2 $ Before: $ pahole packed_bitfield.o struct packed { char x1:1; /* 0: 7 1 */ char x2:3; /* 0: 4 1 */ char x3:3; /* 0: 1 1 */ int y1:7; /* 0:18 4 */ int y2:20; /* 0:4294967294 4 */ /* size: 5, cachelines: 1, members: 5 */ /* padding: 1 */ /* bit_padding: 254 bits */ /* last cacheline: 5 bytes */ /* BRAIN FART ALERT! 5 != 1 + 0(holes), diff = 4 */ }; $ Now: $ pahole packed_bitfield.o struct packed { char x1:1; /* 0: 7 1 */ char x2:3; /* 0: 4 1 */ char x3:3; /* 0: 1 1 */ int y1:7; /* 0:18 4 */ int y2:20; /* 4:30 4 */ /* size: 5, cachelines: 1, members: 5 */ /* padding: 1 */ /* bit_padding: 254 bits */ /* last cacheline: 5 bytes */ /* BRAIN FART ALERT! 5 != 1 + 0(holes), diff = 4 */ }; $ And for two big endian archs, one 32-bit and the other 64-bit: $ file ~acme/git/tmp/packed_bitfield.powerpc.o /home/acme/git/tmp/packed_bitfield.powerpc.o: ELF 32-bit MSB relocatable, PowerPC or cisco 4500, version 1 (SYSV), with debug_info, not stripped $ pahole ~acme/git/tmp/packed_bitfield.powerpc.o struct packed { char x1:1; /* 0: 0 1 */ char x2:3; /* 0: 1 1 */ char x3:3; /* 0: 4 1 */ int y1:7; /* 0: 7 4 */ int y2:20; /* 0:14 4 */ /* size: 5, cachelines: 1, members: 5 */ /* padding: 1 */ /* bit_padding: 254 bits */ /* last cacheline: 5 bytes */ /* BRAIN FART ALERT! 5 != 1 + 0(holes), diff = 4 */ }; $ $ file ~acme/git/tmp/packed_bitfield.sparc64.o /home/acme/git/tmp/packed_bitfield.sparc64.o: ELF 64-bit MSB relocatable, SPARC V9, relaxed memory ordering, version 1 (SYSV), with debug_info, not stripped $ $ pahole ~acme/git/tmp/packed_bitfield.sparc64.o struct packed { char x1:1; /* 0: 0 1 */ char x2:3; /* 0: 1 1 */ char x3:3; /* 0: 4 1 */ int y1:7; /* 0: 7 4 */ int y2:20; /* 0:14 4 */ /* size: 5, cachelines: 1, members: 5 */ /* padding: 1 */ /* bit_padding: 254 bits */ /* last cacheline: 5 bytes */ /* BRAIN FART ALERT! 5 != 1 + 0(holes), diff = 4 */ }; Now to fix the holes calculations. Reported-by: Andrii Nakryiko <andrii.nakryiko@gmail.com> Acked-by: Yonghong Song <yhs@fb.com> Cc: Alexei Starovoitov <ast@fb.com> Cc: Martin Lau <kafai@fb.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
b0cf845e02
commit
1182664d6a
|
@ -753,6 +753,9 @@ static size_t class_member__fprintf(struct class_member *member, bool union_memb
|
|||
sconf.base_offset = offset;
|
||||
}
|
||||
|
||||
if (member->bitfield_offset < 0)
|
||||
offset += member->byte_size;
|
||||
|
||||
if (!conf->suppress_comments)
|
||||
printed_cacheline = class__fprintf_cacheline_boundary(conf, offset, fp);
|
||||
|
||||
|
@ -807,9 +810,14 @@ static size_t class_member__fprintf(struct class_member *member, bool union_memb
|
|||
offset);
|
||||
|
||||
if (member->bitfield_size != 0) {
|
||||
unsigned int bitfield_offset = member->bitfield_offset;
|
||||
|
||||
if (member->bitfield_offset < 0)
|
||||
bitfield_offset = member->byte_size * 8 + member->bitfield_offset;
|
||||
|
||||
printed += fprintf(fp, sconf.hex_fmt ?
|
||||
":%#2x" : ":%2u",
|
||||
member->bitfield_offset);
|
||||
bitfield_offset);
|
||||
size_spacing -= 3;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue