This change allows to use libbpf definitions and APIs from pahole.
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
These are build-only and are not meant to be checked in.
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Because we don't have to lookup the member type that is encoded after
it, i.e. some member fields depend on first processing everything, then
lookup the types to get the sizes, etc.
But the:
member->byte_offset = member->bit_offset / 8;
Can be done soon after we have member->bit_offset loaded from the BTF
section.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
The dwarves class_member field bitfield_offset represents the dwarf tag
DW_AT_bit_offset. For dwarf2, this field can be negative for little
endian for bitfields in packed data structures which cross type
boundary.
-bash-4.4$ cat bitfield.c
struct packed {
char x1: 1;
char x2: 3;
char x3: 3;
int y1: 7;
int y2: 20;
} __attribute__((packed));
struct packed g;
-bash-4.4$ gcc -O2 -c -g bitfield.c
-bash-4.4$ pahole -JV bitfield.o
File bitfield.o:
[1] STRUCT packed kind_flag=1 size=5 vlen=5
x1 type_id=2 bitfield_size=1 bits_offset=0
x2 type_id=2 bitfield_size=3 bits_offset=1
x3 type_id=2 bitfield_size=3 bits_offset=4
y1 type_id=3 bitfield_size=7 bits_offset=7
y2 type_id=3 bitfield_size=255 bits_offset=16776974
[2] INT char size=1 bit_offset=0 nr_bits=8 encoding=(none)
[3] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
-bash-4.4$
The above large negative bits_offset and bitfield_size=255 results from
negative bitfield_offset which is interpreted as positive value in btf
encoding.
With this fix, the pahole works properly for BTF:
-bash-4.4$ pahole -JV bitfield.o
File bitfield.o:
[1] STRUCT packed kind_flag=1 size=5 vlen=5
x1 type_id=2 bitfield_size=1 bits_offset=0
x2 type_id=2 bitfield_size=3 bits_offset=1
x3 type_id=2 bitfield_size=3 bits_offset=4
y1 type_id=3 bitfield_size=7 bits_offset=7
y2 type_id=3 bitfield_size=20 bits_offset=14
[2] INT char size=1 bit_offset=0 nr_bits=8 encoding=(none)
[3] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
-bash-4.4$
Note that change bitfield_offset from uint8_t to int8_t is safe as the
maximum int type we support is __int128 and maximum bitfield_offset is
127.
Signed-off-by: Yonghong Song <yhs@fb.com>
Reported-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Andrii Nakryiko <andriin@fb.com>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: dwarves@vger.kernel.org
Link: https://www.spinics.net/lists/dwarves/msg00199.html
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
I wrote the BTF loader from the CTF loader, where the size of
enumerations is expressed in bits, while BTF encodes it in bytes, fix
it.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
When dealing with BTF encoding of multiple CUs, special `void` type
should be handled explicitly.
This is already handled for all BTF types except recently added
FUNC_PROTO.
Without this fix, any `void` type directly referenced from FUNC_PROTO
will turn into last type from previous CU (see example below, for
FUNC_PROTO [4]).
$ cat test1.c
void (*foo)(void);
int main() {
return 0;
}
$ cat test2.c
void (*bar)(void);
$ cc -g test1.c test2.c -o test
Without fix:
$ LLVM_OBJCOPY=objcopy ~/local/pahole/build/pahole -JV /tmp/test
File /tmp/test:
[1] INT int size=4 bit_offset=0 nr_bits2 encoding=SIGNED
[2] FUNC_PROTO (anon) return=0 args=(void)
[3] PTR (anon) type_id=2
[4] FUNC_PROTO (anon) return=3 args=(void)
[5] PTR (anon) type_id=4
With fix:
$ LLVM_OBJCOPY=objcopy ~/local/pahole/build/pahole -JV /tmp/test
File /tmp/test:
[1] INT int size=4 bit_offset=0 nr_bits2 encoding=SIGNED
[2] FUNC_PROTO (anon) return=0 args=(void)
[3] PTR (anon) type_id=2
[4] FUNC_PROTO (anon) return=0 args=(void)
[5] PTR (anon) type_id=4
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Acked-by: Yonghong Song <yhs@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: dwarves@vger.kernel.org
[ Applied patch by hand, came mangled ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
BTF_KIND_FUNC is generated by llvm (latest trunk, 8.0 or later).
Without BTF_KIND_FUNC support, we will see the following errors,
-bash-4.4$ cat t.c
struct t {
int a;
char b1:1;
char b2:3;
int c;
} g;
int main() { return 0; }
-bash-4.4$ clang -O2 -target bpf -g -c t.c -Xclang -target-feature -Xclang +dwarfris
-bash-4.4$ pahole -F btf t.o
BTF: idx: 3, off: 28, Unknown
struct t {
int a; /* 0 4 */
/* Bitfield combined with previous fields */
<ERROR(__class__fprintf:1342): 5 not found!>
/* Bitfield combined with previous fields */
<ERROR(__class__fprintf:1342): 5 not found!>
int c; /* 8 4 */
/* size: 12, cachelines: 1, members: 4 */
/* last cacheline: 12 bytes */
/* BRAIN FART ALERT! 12 != 8 + 0(holes), diff = 4 */
};
-bash-4.4$
The reason is that llvm generates BTF_KIND_FUNC which btf_loader does not
recognize.
This patch added support for BTF_KIND_FUNC. Since BTF_KIND_FUNC represents
a defined subprogram and not a real type. A null type is used to
represent BTF_KIND_FUNC to avoid skipping type index.
With this fix:
-bash-4.4$ pahole -F btf t.o
struct t {
int a; /* 0 4 */
char b1:1; /* 4: 0 1 */
char b2:3; /* 4: 1 1 */
int c; /* 8 4 */
/* size: 12, cachelines: 1, members: 4 */
/* last cacheline: 12 bytes */
/* BRAIN FART ALERT! 12 != 9 + 0(holes), diff = 3 */
};
Signed-off-by: Yonghong Song <yhs@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Commit 2a82d593be ("btf: Add kind_flag support for btf_loader") added
kind_flag supported in btf_loader to get correct bitfield_size and
bit_offset for struct/union members. The commit unnecessarily stored
the bit in the structure type which is not used later.
So let us remove the kind_flag from the struct type and any other
changes whose purpose is to set this bit.
Signed-off-by: Yonghong Song <yhs@fb.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Martin KaFai Lau <kafai@fb.com>
Fixes: 2a82d593be ("btf: Add kind_flag support for btf_loader")
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Addressing this build warning:
In file included from /home/acme/git/pahole/dutil.c:10:
/home/acme/git/pahole/dutil.h: In function ‘strstarts’:
/home/acme/git/pahole/dutil.h:301:9: warning: implicit declaration of function ‘strncmp’ [-Wimplicit-function-declaration]
return strncmp(str, prefix, strlen(prefix)) == 0;
^~~~~~~
/home/acme/git/pahole/dutil.h:301:30: warning: implicit declaration of function ‘strlen’ [-Wimplicit-function-declaration]
return strncmp(str, prefix, strlen(prefix)) == 0;
^~~~~~
/home/acme/git/pahole/dutil.h:301:30: warning: incompatible implicit declaration of built-in function ‘strlen’
/home/acme/git/pahole/dutil.h:301:30: note: include ‘<string.h>’ or provide a declaration of ‘strlen’
/home/acme/git/pahole/dutil.h:20:1:
+#include <string.h>
/home/acme/git/pahole/dutil.h:301:30:
return strncmp(str, prefix, strlen(prefix)) == 0;
^~~~~~
Fixes: a2cdc6c2a0 ("dutil: Adopt strstart() from the linux perf tools sources")
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
To clear this warning:
[ 97%] Building C object CMakeFiles/pdwtags.dir/pdwtags.o
In file included from /home/acme/git/pahole/dwarves.h:19,
from /home/acme/git/pahole/pdwtags.c:14:
/home/acme/git/pahole/dutil.h:155:1: warning: ignoring attribute ‘noreturn’ because it conflicts with attribute ‘const’ [-Wattributes]
int ____ilog2_NaN(void);
^~~
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Yonghong explains:
<quote>
The bitfield offset in BTF starts from lower number to bigger one. That
is, it is always following the big endian convention, bitfield_offset
will be smaller if close to the top of structure.
This is different from what dwarf is doing, which will show different
things on little endian vs. big endian.
You can make simple adjustment based on all available info. In
btf_encoder.s, we did similar adjustment for little endian from
dwarf to btf.
</>
So fix it up while loading, so that the rebuilt C output shows the same
thing from BTF and from DWARF.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Now unions are handled as well in pahole, so bail out before checking
'struct class' members for struct specific filters when handling
non-structs in class__filter()
Tested-by: Andrii Nakryiko <andriin@fb.com>
Fixes: 31664d60ad ("pahole: Show tagged enums as well when no class is specified")
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
In pahole we started showing 'union' tags as well, and those are
represented by 'struct type', so be defensive in class__find_holes(),
checking if the tag is represented with a 'struct class'.
Tested-by: Andrii Nakryiko <andriin@fb.com>
Fixes: 31664d60ad ("pahole: Show tagged enums as well when no class is specified")
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
For struct/union members, the struct/union type info kind_flag is needed
to calculate correct bitfield_size and bit_offset.
if (kind_flag) {
bitfield_size = BTF_MEMBER_BITFIELD_SIZE(member->offset);
bit_offset = BTF_MEMBER_BIT_OFFSET(member->offset);
} else {
bitfield_size = 0;
bit_offset = member->offset;
}
Note that bitfield_size and bit_offset will not depend on the member
type. The member type will help calculate correct bitfield_offset,
byte_size, byte_offset, bit_size.
For example, with the fix, we will be able to display
bit offset and bitfield size properly.
-bash-4.4$ cat t.c
struct t {
int a:2;
int b:3;
int c:2;
} g;
-bash-4.4$ gcc -c -O2 -g t.c
-bash-4.4$ pahole -JV t.o
File t.o:
[1] STRUCT t kind_flag=1 size=4 vlen=3
a type_id=2 bitfield_size=2 bits_offset=0
b type_id=2 bitfield_size=3 bits_offset=2
c type_id=2 bitfield_size=2 bits_offset=5
[2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
-bash-4.4$ pahole -F btf t.o
struct t {
int a:2; /* 0: 0 4 */
int b:3; /* 0: 2 4 */
int c:2; /* 0: 5 4 */
/* size: 4, cachelines: 1, members: 3 */
/* bit_padding: 25 bits */
/* last cacheline: 4 bytes */
};
Note that the above offset showing is different from the below dwarf as
BTF bitfield_offset is always the offset from the start of structure,
kindly like big endian encoding. This may need adjustment to be
conforming to the dwarf dump format.
-bash-4.4$ pahole -F dwarf t.o
struct t {
int a:2; /* 0:30 4 */
int b:3; /* 0:27 4 */
int c:2; /* 0:25 4 */
/* size: 4, cachelines: 1, members: 3 */
/* bit_padding: 25 bits */
/* last cacheline: 4 bytes */
};
Signed-off-by: Yonghong Song <yhs@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Two new btf kinds, BTF_KIND_FUNC and BTF_KIND_FUNC_PROTO,
have been added in kernel since
https://patchwork.ozlabs.org/cover/1000176/
to support better func introspection.
Currently, for a DW_TAG_subroutine_type dwarf type,
a simple "void *" is generated instead of real subroutine type.
This patch teaches pahole to generate BTF_KIND_FUNC_PROTO
properly. After this patch, pahole should have complete
type coverage for C frontend with types a bpf program cares.
For example,
$ cat t1.c
typedef int __int32;
struct t1 {
int a1;
int (*f1)(char p1, __int32 p2);
} g1;
$ cat t2.c
typedef int __int32;
struct t2 {
int a2;
int (*f2)(char q1, __int32 q2, ...);
int (*f3)();
} g2;
int main() { return 0; }
$ gcc -O2 -o t1 -g t1.c t2.c
$ pahole -JV t1
File t1:
[1] TYPEDEF __int32 type_id=2
[2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
[3] STRUCT t1 kind_flag=0 size=16 vlen=2
a1 type_id=2 bits_offset=0
f1 type_id=6 bits_offset=64
[4] FUNC_PROTO (anon) return=2 args=(5 (anon), 1 (anon))
[5] INT char size=1 bit_offset=0 nr_bits=8 encoding=(none)
[6] PTR (anon) type_id=4
[7] TYPEDEF __int32 type_id=8
[8] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
[9] STRUCT t2 kind_flag=0 size=24 vlen=3
a2 type_id=8 bits_offset=0
f2 type_id=12 bits_offset=64
f3 type_id=14 bits_offset=128
[10] FUNC_PROTO (anon) return=8 args=(11 (anon), 7 (anon), vararg)
[11] INT char size=1 bit_offset=0 nr_bits=8 encoding=(none)
[12] PTR (anon) type_id=10
[13] FUNC_PROTO (anon) return=8 args=(vararg)
[14] PTR (anon) type_id=13
$
In the above example, type [4], [10] and [13] represent the
func_proto types.
BTF_KIND_FUNC, which represents a real subprogram, is not generated in
this patch and will be considered later.
Signed-off-by: Yonghong Song <yhs@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This patch fixed two issues with BTF. One is related to struct/union
bitfield encoding and the other is related to forward type.
Issue #1 and solution:
======================
Current btf encoding of bitfield follows what pahole generates.
For each bitfield, pahole will duplicate the type chain and
put the bitfield size at the final int or enum type.
Since the BTF enum type cannot encode bit size,
commit b18354f64c ("btf: Generate correct struct bitfield
member types") workarounds the issue by generating
an int type whenever the enum bit size is not 32.
The above workaround is not ideal as we lost original type
in BTF. Another undesiable fact is the type duplication
as the pahole duplicates the type chain.
To fix this issue, this patch implemented a compatible
change for BTF struct type encoding:
. the bit 31 of type->info, previously reserved,
now is used to indicate whether bitfield_size is
encoded in btf_member or not.
. if bit 31 of struct_type->info is set,
btf_member->offset will encode like:
bit 0 - 23: bit offset
bit 24 - 31: bitfield size
if bit 31 is not set, the old behavior is preserved:
bit 0 - 31: bit offset
So if the struct contains a bit field, the maximum bit offset
will be reduced to (2^24 - 1) instead of MAX_UINT. The maximum
bitfield size will be 255 which is enough for today as maximum
bitfield in compiler can be 128 where int128 type is supported.
A new global, no_bitfield_type_recode, is introduced and which
will be set to true if BTF encoding is enabled. This global
will prevent pahole duplicating the bitfield types to avoid
type duplication in BTF.
Issue #2 and solution:
======================
Current forward type in BTF does not specify whether the original
type is struct or union. This will not work for type pretty print
and BTF-to-header-file conversion as struct/union must be specified.
To fix this issue, similar to issue #1, type->info bit 31
is used. If the bit is set, it is union type. Otherwise, it is
a struct type.
Examples:
=========
-bash-4.4$ cat t.c
struct s;
union u;
typedef int ___int;
enum A { A1, A2, A3 };
struct t {
int a[5];
___int b:4;
volatile enum A c:4;
struct s *p1;
union u *p2;
} g;
-bash-4.4$ gcc -c -O2 -g t.c
Without this patch:
$ pahole -JV t.o
[1] TYPEDEF ___int type_id=2
[2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
[3] ENUM A size=4 vlen=3
A1 val=0
A2 val=1
A3 val=2
[4] STRUCT t size=40 vlen=5
a type_id=5 bits_offset=0
b type_id=13 bits_offset=160
c type_id=15 bits_offset=164
p1 type_id=9 bits_offset=192
p2 type_id=11 bits_offset=256
[5] ARRAY (anon) type_id=2 index_type_id=2 nr_elems=5
[6] INT sizetype size=8 bit_offset=0 nr_bits=64 encoding=(none)
[7] VOLATILE (anon) type_id=3
[8] FWD s type_id=0
[9] PTR (anon) type_id=8
[10] FWD u type_id=0
[11] PTR (anon) type_id=10
[12] INT int size=1 bit_offset=0 nr_bits=4 encoding=(none)
[13] TYPEDEF ___int type_id=12
[14] INT (anon) size=1 bit_offset=0 nr_bits=4 encoding=SIGNED
[15] VOLATILE (anon) type_id=14
With this patch:
$ pahole -JV t.o
File t.o:
[1] TYPEDEF ___int type_id=2
[2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
[3] ENUM A size=4 vlen=3
A1 val=0
A2 val=1
A3 val=2
[4] STRUCT t kind_flag=1 size=40 vlen=5
a type_id=5 bitfield_size=0 bits_offset=0
b type_id=1 bitfield_size=4 bits_offset=160
c type_id=7 bitfield_size=4 bits_offset=164
p1 type_id=9 bitfield_size=0 bits_offset=192
p2 type_id=11 bitfield_size=0 bits_offset=256
[5] ARRAY (anon) type_id=2 index_type_id=2 nr_elems=5
[6] INT sizetype size=8 bit_offset=0 nr_bits=64 encoding=(none)
[7] VOLATILE (anon) type_id=3
[8] FWD s struct
[9] PTR (anon) type_id=8
[10] FWD u union
[11] PTR (anon) type_id=10
The fix removed the type duplication, preserved the enum type for the
bitfield, and have correct struct/union information for the forward
type.
Signed-off-by: Yonghong Song <yhs@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Currently, the pahole dwarf->btf conversion only supports one
compilation unit. This is not ideal since we would like using pahole to
generate BTF for vmlinux which has a lot of compilation units.
This patch added support to process multiple compilation units per ELF
file. Multiple ELF files are also supported properly.
The following is a demonstration example:
-bash-4.4$ cat t1.c
struct t1 {
int a1;
} g1;
int main(void) { return 0; }
-bash-4.4$ cat t2.c
struct t2 {
char a2;
} g2;
int main() { return 0; }
-bash-4.4$ cat t3.c
struct t3 {
unsigned char a1:4;
} g1;
int main(void) { return 0; }
-bash-4.4$ cat t4.c
struct t4 {
volatile char a4;
} g2;
int main() { return 0; }
-bash-4.4$ gcc -O2 -o t1 -g t1.c t2.c
-bash-4.4$ gcc -O2 -o t3 -g t3.c t4.c
Note that both the binary "t1" and "t3" have two compilation units in
their respective dwarf debug_info sections. The following is the pahole
verbose output for BTF conversion for these two binaries.
-bash-4.4$ pahole -JV t1 t3
File t1:
[1] STRUCT t1 size=4 vlen=1
a1 type_id=2 bits_offset=0
[2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
[3] STRUCT t2 size=1 vlen=1
a2 type_id=4 bits_offset=0
[4] INT char size=1 bit_offset=0 nr_bits=8 encoding=(none)
[5] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
File t3:
[1] STRUCT t3 size=1 vlen=1
a1 type_id=3 bits_offset=0
[2] INT unsigned char size=1 bit_offset=0 nr_bits=8 encoding=(none)
[3] INT unsigned char size=1 bit_offset=0 nr_bits=4 encoding=(none)
[4] INT (anon) size=4 bit_offset=0 nr_bits=32 encoding=(none)
[5] STRUCT t4 size=1 vlen=1
a4 type_id=6 bits_offset=0
[6] VOLATILE (anon) type_id=7
[7] INT char size=1 bit_offset=0 nr_bits=8 encoding=(none)
[8] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Signed-off-by: Yonghong Song <yhs@fb.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Since tools like 'pahole' now shows unions in addition to structs.
Cc: Matthew Wilcox <willy@infradead.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
The pahole tool initial goal was to show struct holes, which can't
happen with a first level of a tagged union (a union with a name),
so those only were displayed when part of a higher level struct.
Show the first level tagged enums as well, as this is useful when just
wanting to see its members.
E.g.:
$ pahole ../build/v4.20-rc5/net/core/sock.o | grep ^union
union fpregs_state {
union irq_stack_union {
union sigval {
union __sifields {
union thread_union {
union kernfs_node_id {
union flowi_uli {
union ethtool_flow_union {
union key_payload {
union bpf_attr {
union tcp_md5_addr {
$
Suggested-by: Matthew Wilcox <willy@infradead.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
For int types, the correct type size will be generated. For enum types,
if the bit size is not 32, current BTF enum cannot represent it so a
signed int type will be generated.
For the following example:
$ cat test.c
enum A { A1, A2, A3 };
struct t {
enum A a:3;
volatile enum A b:4;
} g;
$ gcc -c -g -O2 test.c
Without this patch, we will have:
$ pahole -JV test.o
[1] ENUM A size=4 vlen=3
A1 val=0
A2 val=1
A3 val=2
[2] STRUCT t size=4 vlen=2
a type_id=4 bits_offset=0
b type_id=6 bits_offset=3
[3] VOLATILE (anon) type_id=1
[4] ENUM A size=1 vlen=3
A1 val=0
A2 val=1
A3 val=2
[5] ENUM A size=1 vlen=3
A1 val=0
A2 val=1
A3 val=2
[6] VOLATILE (anon) type_id=5
[7] INT (anon) size=4 bit_offset=0 nr_bits=32 encoding=(none)
There are two issues in the above. The struct "t" member "a" points to
type [4]. But the nr_bits is lost in type [4].
The same for type [5] which is for struct "t" member "b".
Since BTF ENUM type cannot encode nr_bits, this patch fixed the issue by
generating a BTF INT type if the ENUM type number of bits in pahole is
not 32.
With this patch, the incorrect member nr_bits issue is fixed as below:
$ pahole -JV test.o
[1] ENUM A size=4 vlen=3
A1 val=0
A2 val=1
A3 val=2
[2] STRUCT t size=4 vlen=2
a type_id=4 bits_offset=0
b type_id=6 bits_offset=3
[3] VOLATILE (anon) type_id=1
[4] INT (anon) size=1 bit_offset=0 nr_bits=3 encoding=SIGNED
[5] INT (anon) size=1 bit_offset=0 nr_bits=4 encoding=SIGNED
[6] VOLATILE (anon) type_id=5
[7] INT (anon) size=4 bit_offset=0 nr_bits=32 encoding=(none)
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>
union__fprintf() unconditionally uses conf.cachelinep, assuming there is
where the current cacheline is being kept, but if we call
union__fprintf() from something other than __class__fprintf(), then that
pointer is NULL, fix that.
Reported-by: Eric Blake <eblake@redhat.com>
Tested-by: Eric Blake <eblake@redhat.com>
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1633348
Fixes: e975ff247a ("dwarves_fprintf: Print cacheline boundaries in multiple union members")
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This is DWARF specific, we don't have in CTF, AFAIK, info about where a
variable is put, i.e. in a register? in the stack? etc.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
We'll use location in the DWARF sense, i.e. location lists, etc, i.e.
where is this variable? In a register? The stack? etc.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
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>
That wasn't going into the tarballs generated when releasing new
versions.
Reported-by: Michal Schmidt <mschmidt@redhat.com>
Cc: Clark Williams <williams@redhat.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Run 'perf ftrace' to show *btf* functions called to load, validate and
put in place data structures with the .BTF ELF section contents.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Updated elfutils to 0.173, using the fedora 28 packages and, as noted in
https://github.com/cilium/cilium/pull/5106/files ["bpf, doc: further
improvements on the BTF related section #5106"] there is no need to pass
the '-mattr=dwarfris' to llc to have DWARF sections correctly parsed by
tools like pahole.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This allows processing DW_TAG_partial_unit sections, which gets us from
no tags processed in files contained such tags to at least showing the
tags present in those sections.
Further work is required to support DW_TAG_compile_unit sections using
DW_TAG_imported_unit to import those DW_TAG_partial_unit sections, which
will be done by basically readding the contents of the
DW_TAG_partial_unit sections to the DW_TAG_compile_unit sections
importing them and then recoding as if all the tags in the partial units
were in the compile units.
This will make sure we have a contiguous series of types used in a
compile unit so that the converting routines to CTF and BTF can work
just as before.
On a fedora 27 system:
Before:
$ pahole /usr/lib/debug/usr/lib64/libgtk-3.so.0.2200.19.debug
die__process: DW_TAG_compile_unit or DW_TAG_type_unit expected got partial_unit!
$
After:
$ pahole /usr/lib/debug/usr/lib64/libgtk-3.so.0.2200.19.debug
struct _GTimeVal {
glong tv_sec; /* 0 8 */
glong tv_usec; /* 8 8 */
/* size: 16, cachelines: 1, members: 2 */
/* last cacheline: 16 bytes */
};
struct _GError {
GQuark domain; /* 0 4 */
gint code; /* 4 4 */
gchar * message; /* 8 8 */
/* size: 16, cachelines: 1, members: 3 */
/* last cacheline: 16 bytes */
};
struct _GCond {
gpointer p; /* 0 8 */
guint i[2]; /* 8 8 */
/* size: 16, cachelines: 1, members: 2 */
/* last cacheline: 16 bytes */
};
<SNIP some more structs found in DW_TAG_partial unit sections...>
struct _GSourceFuncs {
gboolean (*prepare)(GSource *, gint *); /* 0 8 */
gboolean (*check)(GSource *); /* 8 8 */
gboolean (*dispatch)(GSource *, GSourceFunc, gpointer); /* 16 8 */
void (*finalize)(GSource *); /* 24 8 */
GSourceFunc closure_callback; /* 32 8 */
GSourceDummyMarshal closure_marshal; /* 40 8 */
/* size: 48, cachelines: 1, members: 6 */
/* last cacheline: 48 bytes */
};
struct _GThreadFunctions {
GMutex * (*mutex_new)(void); /* 0 8 */
void (*mutex_lock)(GMutex *); /* 8 8 */
gboolean (*mutex_trylock)(GMutex *)tag__recode_dwarf_type: couldn't find 0x74 type for 0x7fc (typedef)!
tag__recode_dwarf_type: couldn't find 0x7e type for 0x829 (pointer_type)!
tag__recode_dwarf_type: couldn't find 0x829 type for 0x844 (variable)!
tag__recode_dwarf_type: couldn't find 0x7e type for 0x850 (variable)!
tag__recode_dwarf_type: couldn't find 0x22 type for 0x85b (variable)!
tag__recode_dwarf_type: couldn't find 0x22 type for 0x866 (variable)!
tag__recode_dwarf_type: couldn't find 0x22 type for 0x871 (variable)!
namespace__recode_dwarf_types: couldn't find 0x7fc type for 0x8a4 (member)!
tag__recode_dwarf_type: couldn't find 0xfa type for 0x8e8 (volatile_type)!
namespace__recode_dwarf_types: couldn't find 0x8b2 type for 0x90d (member)!
tag__recode_dwarf_type: couldn't find 0x1b type for 0x941 (typedef)!
<SNIP>
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This patch introduces BPF Type Format (BTF).
BTF (BPF Type Format) is the meta data format which describes
the data types of BPF program/map. Hence, it basically focus
on the C programming language which the modern BPF is primary
using. The first use case is to provide a generic pretty print
capability for a BPF map.
Signed-off-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
To help with using just that object file, avoiding processing big files
such as vmlinux, e.g.:
$ pahole -I vmlinux
<SNIP>
/* Used at: /home/acme/git/perf/init/main.c */
/* <1f4a5> /home/acme/git/perf/arch/x86/include/asm/orc_types.h:85 */
struct orc_entry {
s16 sp_offset; /* 0 2 */
s16 bp_offset; /* 2 2 */
unsigned int sp_reg:4; /* 4:28 4 */
unsigned int bp_reg:4; /* 4:24 4 */
unsigned int type:2; /* 4:22 4 */
/* size: 6, cachelines: 1, members: 5 */
/* padding: 65534 */
/* bit_padding: 22 bits */
/* last cacheline: 6 bytes */
/* BRAIN FART ALERT! 6 != 8 + 0(holes), diff = -2 */
};
<SNIP>
So I noticed that BFA, need to work on it, to make the testing process
faster, better not process vmlinux.o, instead, do:
$ pahole -C orc_entry ${kernel_build_dir}/init/main.o
Much faster, as main.o is much smaller than the vmlinux file.
Now to fix the processing of 'struct orc_entry'.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>