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>
Build instructions:
1. install cmake
2. mkdir build
3. cd build
4. cmake -D__LIB=lib ..
5. make install
Default is to be installed on /usr/local, see rpm spec file for
installing on other places.
Known to work scenarios:
Mandriva Cooker:
cmake 2.4.5-1mdv2007.1
libelfutils1-devel 0.123-1mdv2007.1
Debian Unstable:
cmake 2.4.5-1
libdw-dev 0.123-2
Fedora Core 6:
cmake 2.4.5-2.fc6
elfutils-devel 0.126-1.fc6