btf: Fix bitfield encoding
The btf bitfield encoding is broken. For the following example: -bash-4.2$ cat t.c struct t { int a:2; int b:1; int :3; int c:1; int d; char e:1; char f:1; int g; }; void test(struct t *t) { return; } -bash-4.2$ clang -S -g -emit-llvm t.c The output for bpf "little and big" endian results with pahole dwarf2btf conversion: -bash-4.2$ llc -march=bpfel -mattr=dwarfris -filetype=obj t.ll -bash-4.2$ pahole -JV t.o [1] PTR (anon) type_id=2 [2] STRUCT t size=16 vlen=7 a type_id=5 bits_offset=30 b type_id=6 bits_offset=29 c type_id=6 bits_offset=25 d type_id=3 bits_offset=32 e type_id=7 bits_offset=71 f type_id=7 bits_offset=70 g type_id=3 bits_offset=96 [3] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED [4] INT char size=1 bit_offset=0 nr_bits=8 encoding=(none) [5] INT int size=1 bit_offset=0 nr_bits=2 encoding=(none) [6] INT int size=1 bit_offset=0 nr_bits=1 encoding=(none) [7] INT char size=1 bit_offset=0 nr_bits=1 encoding=(none) -bash-4.2$ llc -march=bpfeb -mattr=dwarfris -filetype=obj t.ll -bash-4.2$ pahole -JV t.o [1] PTR (anon) type_id=2 [2] STRUCT t size=16 vlen=7 a type_id=5 bits_offset=0 b type_id=6 bits_offset=2 c type_id=6 bits_offset=6 d type_id=3 bits_offset=32 e type_id=7 bits_offset=64 f type_id=7 bits_offset=65 g type_id=3 bits_offset=96 [3] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED [4] INT char size=1 bit_offset=0 nr_bits=8 encoding=(none) [5] INT int size=1 bit_offset=0 nr_bits=2 encoding=(none) [6] INT int size=1 bit_offset=0 nr_bits=1 encoding=(none) [7] INT char size=1 bit_offset=0 nr_bits=1 encoding=(none) The BTF struct member bits_offset counts bits from the beginning of the containing entity regardless of endianness, similar to what DW_AT_bit_offset from DWARF4 does. Such counting is equivalent to the big endian conversion in the above. But the little endian conversion is not correct since dwarf generates DW_AT_bit_offset based on actual bit position in the little endian architecture. For example, for the above struct member "a", the dwarf would generate DW_AT_bit_offset=30 for little endian, and DW_AT_bit_offset=0 for big endian. This patch fixed the little endian structure member bits_offset problem with proper calculation based on dwarf attributes. With the fix, we get: -bash-4.2$ llc -march=bpfel -mattr=dwarfris -filetype=obj t.ll -bash-4.2$ pahole -JV t.o [1] STRUCT t size=16 vlen=7 a type_id=5 bits_offset=0 b type_id=6 bits_offset=2 c type_id=6 bits_offset=6 d type_id=2 bits_offset=32 e type_id=7 bits_offset=64 f type_id=7 bits_offset=65 g type_id=2 bits_offset=96 [2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED [3] INT char size=1 bit_offset=0 nr_bits=8 encoding=(none) [4] PTR (anon) type_id=1 [5] INT int size=1 bit_offset=0 nr_bits=2 encoding=(none) [6] INT int size=1 bit_offset=0 nr_bits=1 encoding=(none) [7] INT char size=1 bit_offset=0 nr_bits=1 encoding=(none) -bash-4.2$ llc -march=bpfeb -mattr=dwarfris -filetype=obj t.ll -bash-4.2$ pahole -JV t.o [1] PTR (anon) type_id=2 [2] STRUCT t size=16 vlen=7 a type_id=5 bits_offset=0 b type_id=6 bits_offset=2 c type_id=6 bits_offset=6 d type_id=3 bits_offset=32 e type_id=7 bits_offset=64 f type_id=7 bits_offset=65 g type_id=3 bits_offset=96 [3] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED [4] INT char size=1 bit_offset=0 nr_bits=8 encoding=(none) [5] INT int size=1 bit_offset=0 nr_bits=2 encoding=(none) [6] INT int size=1 bit_offset=0 nr_bits=1 encoding=(none) [7] INT char size=1 bit_offset=0 nr_bits=1 encoding=(none) -bash-4.2$ For both little endian and big endian, we have correct and same bits_offset for struct members. We could fix pos->bit_offset, but pos->bit_offset will be inconsistent to pos->bitfield_offset in the meaning and pos->bitfield_offset is used to print out pahole data structure: -bash-4.2$ llc -march=bpfel -mattr=dwarfris -filetype=obj t.ll -bash-4.2$ /bin/pahole t.o struct t { int a:2; /* 0:30 4 */ int b:1; /* 0:29 4 */ int c:1; /* 0:25 4 */ ..... So this patch just made the change in btf specific routines. Signed-off-by: Yonghong Song <yhs@fb.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Acked-by: Martin KaFai Lau <kafai@fb.com> Cc: Alexei Starovoitov <ast@fb.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
92417082aa
commit
0d2511fd1d
|
@ -34,10 +34,35 @@ static int32_t structure_type__encode(struct btf *btf, struct tag *tag)
|
|||
if (type_id < 0)
|
||||
return type_id;
|
||||
|
||||
type__for_each_data_member(type, pos)
|
||||
type__for_each_data_member(type, pos) {
|
||||
uint32_t bit_offset;
|
||||
|
||||
/* calculate member bits_offset.
|
||||
*
|
||||
* for big endian or non-bitfield little endian,
|
||||
* use pos->bit_offset computed by
|
||||
* dwarf_loader which conforms to BTF requirement.
|
||||
*
|
||||
* for little endian bitfield member, if we have a field like
|
||||
* pos->byte_size = 2,
|
||||
* pos->bitfield_offset = 12,
|
||||
* pos->bitfield_size = 2,
|
||||
* This field occupy bits 12-13 by a 2-byte value,
|
||||
* which corresponds to bits 2-3 from big endian
|
||||
* perspective.
|
||||
*/
|
||||
if (btf->is_big_endian || !pos->bitfield_size)
|
||||
bit_offset = pos->bit_offset;
|
||||
else
|
||||
bit_offset = pos->byte_offset * 8 +
|
||||
pos->byte_size * 8 -
|
||||
pos->bitfield_offset -
|
||||
pos->bitfield_size;
|
||||
|
||||
if (btf__add_member(btf, pos->name, pos->tag.type,
|
||||
pos->bit_offset))
|
||||
bit_offset))
|
||||
return -1;
|
||||
}
|
||||
|
||||
return type_id;
|
||||
}
|
||||
|
|
8
libbtf.c
8
libbtf.c
|
@ -75,6 +75,14 @@ struct btf *btf__new(const char *filename, Elf *elf)
|
|||
goto errout;
|
||||
}
|
||||
|
||||
switch (btf->ehdr.e_ident[EI_DATA]) {
|
||||
case ELFDATA2LSB: btf->is_big_endian = false; break;
|
||||
case ELFDATA2MSB: btf->is_big_endian = true; break;
|
||||
default:
|
||||
fprintf(stderr, "%s: unknown elf endianness.\n", __func__);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
switch (btf->ehdr.e_ident[EI_CLASS]) {
|
||||
case ELFCLASS32: btf->wordsize = 4; break;
|
||||
case ELFCLASS64: btf->wordsize = 8; break;
|
||||
|
|
Loading…
Reference in New Issue