This is the first step:
$ pahole -V -C 'perf_event_header(sizeof=size,type=type)' ~/bin/perf
pahole: sizeof_operator for 'perf_event_header' is 'size'
pahole: type member for 'perf_event_header' is 'type'
struct perf_event_header {
__u32 type; /* 0 4 */
__u16 misc; /* 4 2 */
__u16 size; /* 6 2 */
/* size: 8, cachelines: 1, members: 3 */
/* last cacheline: 8 bytes */
};
$
Next step is to add another modifier that will point to an enum that
maps the value in perf_event_header->type to a string that can then be
used to lookup the type to be used to pretty print what is after
'sizeof(struct perf_event_header)', i.e. things like:
$ pahole -EC perf_record_mmap ~/bin/perf
struct perf_record_mmap {
struct perf_event_header {
/* typedef __u32 */ unsigned int type; /* 0 4 */
/* typedef __u16 */ short unsigned int misc; /* 4 2 */
/* typedef __u16 */ short unsigned int size; /* 6 2 */
} header; /* 0 8 */
/* typedef __u32 */ unsigned int pid; /* 8 4 */
/* typedef __u32 */ unsigned int tid; /* 12 4 */
/* typedef __u64 */ long long unsigned int start; /* 16 8 */
/* typedef __u64 */ long long unsigned int len; /* 24 8 */
/* typedef __u64 */ long long unsigned int pgoff; /* 32 8 */
char filename[4096]; /* 40 4096 */
/* size: 4136, cachelines: 65, members: 7 */
/* last cacheline: 40 bytes */
};
$
The various validations performed:
$ pahole -V -C 'perf_event_header(sizeof=size,typ=type)' ~/bin/perf
pahole: sizeof_operator for 'perf_event_header' is 'size'
pahole: invalid arg 'typ' in 'perf_event_header(sizeof=size,typ=type)' (known args: sizeof=member, type=member)
$
$ pahole -V -C 'perf_event_header(sizeof=size,type=bla)' ~/bin/perf
pahole: sizeof_operator for 'perf_event_header' is 'size'
pahole: type member for 'perf_event_header' is 'bla'
pahole: the type member 'bla' wasn't found in the 'perf_event_header' type
$
$ pahole -V -C 'perf_event_header(sizeof=size,type=type)' ~/bin/perf
pahole: sizeof_operator for 'perf_event_header' is 'size'
pahole: type member for 'perf_event_header' is 'type'
struct perf_event_header {
__u32 type; /* 0 4 */
__u16 misc; /* 4 2 */
__u16 size; /* 6 2 */
/* size: 8, cachelines: 1, members: 3 */
/* last cacheline: 8 bytes */
};
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Before we were using the rbtree and then we were traversing in
alphabetical order, not in the command line order, fix that.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
I.e. when we do:
pahole -C a,b,c,d binary
We want that the 'a' type be processed first, etc. So add a list for
that.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
I.e.:
$ pahole -C 'perf_event_header(sizeof=siz),a' ~/bin/perf
pahole: the sizeof member 'siz' not found in the 'perf_event_header' type
$ pahole -C 'perf_event_header(sizeof=size,b),a' ~/bin/perf
pahole: invalid, missing '=' in 'perf_event_header(sizeof=size,b)'
$ pahole -C 'perf_event_header(sizeof=size,b=c),a' ~/bin/perf
pahole: invalid arg 'b' in 'perf_event_header(sizeof=size,b=c)' (known args: sizeof=member)
$ pahole -C 'perf_event_header(sizeof=size),a' ~/bin/perf
struct perf_event_header {
__u32 type; /* 0 4 */
__u16 misc; /* 4 2 */
__u16 size; /* 6 2 */
/* size: 8, cachelines: 1, members: 3 */
/* last cacheline: 8 bytes */
};
$
We're for now considering just the first class in that list, so the 'a'
is parsed but not validated, its there just to test the comma as a
separator of class arguments and also as the separator of multiple
classes.
I.e.:
$ pahole -V -C 'perf_event_header(sizeof=size),a(sizeof=1)' ~/bin/perf
pahole: sizeof_operator for 'a' is '1'
pahole: sizeof_operator for 'perf_event_header' is 'size'
struct perf_event_header {
__u32 type; /* 0 4 */
__u16 misc; /* 4 2 */
__u16 size; /* 6 2 */
/* size: 8, cachelines: 1, members: 3 */
/* last cacheline: 8 bytes */
};
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
I.e. this is now supported:
$ pahole -V -C 'perf_event_header(sizeof=size,b),a' ~/bin/perf
pahole: sizeof_operator for 'perf_event_header' is 'size,b'
pahole: the sizeof member 'size,b' not found in the 'perf_event_header' type
$
Now its up to the class args parser to split its parameters, i.e. make
'size' be the value of 'sizeof' and then consider 'a', then the 'b'
class will be considered and so on.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This one just allows that to be set, i.e.:
$ pahole -C perf_event_header ~/bin/perf
struct perf_event_header {
__u32 type; /* 0 4 */
__u16 misc; /* 4 2 */
__u16 size; /* 6 2 */
/* size: 8, cachelines: 1, members: 3 */
/* last cacheline: 8 bytes */
};
$ pahole -C 'perf_event_header(sizeof=size)' --seek_bytes=0x348 --count 1 ~/bin/perf < perf.data
{
.type = 0xa,
.misc = 0x2,
.size = 0x68,
},
$
But:
$ pahole -C 'perf_event_header(sizeof=bla)' --seek_bytes=0x348 --count 1 ~/bin/perf < perf.data
pahole: the sizeof member 'bla' not found in the 'perf_event_header' type
$
And:
$ pahole -C 'perf_event_header(size=misc)' --seek_bytes=0x348 --count 1 ~/bin/perf < perf.data
pahole: invalid arg 'size' in 'perf_event_header(size=misc)' (known args: sizeof=member)
$
The next cset will implement sizeof(type) with that modifier, using the
stdin bytes to obtain the size (0x68) in the above case, and then we'll
be able to print a sequence of variable-sized records correctly.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
We'll have to at this point look for arguments, like a different way of
finding the sizeof for a class, say:
$ pahole perf_event_header
struct perf_event_header {
__u32 type; /* 0 4 */
__u16 misc; /* 4 2 */
__u16 size; /* 6 2 */
/* size: 8, cachelines: 1, members: 3 */
/* last cacheline: 8 bytes */
};
$
In a perf.data file we should consider sizeof(struct perf_event_header)
to really be header->size, o that we can traverse the file one
perf_event_header at a time.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
On SMP systems, the global percpu variables are placed in a special
'.data..percpu' section, which is stored in a segment whose initial
address is set to 0, the addresses of per-CPU variables are relative
positive addresses [1].
This patch extracts these variables from vmlinux and places them with
their type information in BTF. More specifically, when BTF is encoded,
we find the index of the '.data..percpu' section and then traverse the
symbol table to find those global objects which are in this section.
For each of these objects, we push a BTF_KIND_VAR into the types buffer,
and a BTF_VAR_SECINFO into another buffer, percpu_secinfo. When all the
CUs have finished processing, we push a BTF_KIND_DATASEC into the
btfe->types buffer, followed by the percpu_secinfo's content.
In a v5.8-rc3 linux kernel, I was able to extract 288 such variables.
The build time overhead is small and the space overhead is also small.
See testings below.
A found variable can be invalid in two ways:
- Its name found in elf_sym__name is invalid.
- Its size identified by elf_sym__size is 0.
In either case, the BTF containing such symbols will be rejected by the
BTF verifier. Normally we should not see such symbols. But if one is
seen during BTF encoding, the encoder will exit with error. An new flag
'-j' (or '--force') is implemented to help testing, which skips the
invalid symbols and force emit a BTF.
Testing:
- vmlinux size has increased by ~12kb.
Before:
$ readelf -SW vmlinux | grep BTF
[25] .BTF PROGBITS ffffffff821a905c 13a905c 2d2bf8 00
After:
$ pahole -J vmlinux
$ readelf -SW vmlinux | grep BTF
[25] .BTF PROGBITS ffffffff821a905c 13a905c 2d5bca 00
- Common global percpu VARs and DATASEC are found in BTF section.
$ bpftool btf dump file vmlinux | grep runqueues
[14152] VAR 'runqueues' type_id=13778, linkage=global-alloc
$ bpftool btf dump file vmlinux | grep 'cpu_stopper'
[17582] STRUCT 'cpu_stopper' size=72 vlen=5
[17601] VAR 'cpu_stopper' type_id=17582, linkage=static
$ bpftool btf dump file vmlinux | grep ' DATASEC '
[63652] DATASEC '.data..percpu' size=179288 vlen=288
- Tested bpf selftests.
- pahole exits with error if an invalid symbol is seen during encoding,
make -f Makefile -j 36 -s
PAHOLE: Error: Found symbol of zero size when encoding btf (sym: 'yyy', cu: 'xxx.c').
PAHOLE: Error: Use '-j' or '--force_emit' to ignore such symbols and force emit the btf.
scripts/link-vmlinux.sh: line 137: 2475712 Segmentation fault LLVM_OBJCOPY=${OBJCOPY} ${PAHOLE} -J ${1}
- With the flag '-j' or '--force', the invalid symbols are ignored.
- Further in verbose mode and with '-j' or '--force' set, a warning is generated:
PAHOLE: Warning: Found symbol of zero size when encoding btf, ignored (sym: 'yyy', cu: 'xxx.c').
PAHOLE: Warning: Found symbol of invalid name when encoding btf, ignored (sym: 'zzz', cu: 'sss.c').
References:
[1] https://lwn.net/Articles/531148/
Signed-off-by: Hao Luo <haoluo@google.com>
Tested-by: Andrii Nakryiko <andriin@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Acked-by: Andrii Nakryiko <andriin@fb.com>
Cc: Alexei Starovoitov <alexei.starovoitov@gmail.com>
Cc: Andrii Nakryiko <andrii.nakryiko@gmail.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: Oleg Rombakh <olegrom@google.com>
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
To cope with this warning on s390x:
/usr/bin/cc -DDWARVES_VERSION=\"v1.16\" -D_GNU_SOURCE -Ddwarves_EXPORTS -I/builddir/build/BUILD/dwarves-1.16 -I/builddir/build/BUILD/dwarves-1.16/lib/bpf/include/uapi -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -march=zEC12 -mtune=z13 -fasynchronous-unwind-tables -fstack-clash-protection -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Wall -Werror -ggdb -O2 -fPIC -o CMakeFiles/dwarves.dir/libctf.c.o -c /builddir/build/BUILD/dwarves-1.16/libctf.c
/builddir/build/BUILD/dwarves-1.16/dwarves.h: In function 'cus__load_dir':
/builddir/build/BUILD/dwarves-1.16/dwarves.c:1663:44: error: '%s' directive output may be truncated writing up to 255 bytes into a region of size between 0 and 4095 [-Werror=format-truncation=]
1663 | snprintf(pathname, sizeof(pathname), "%s/%s",
| ^~
In file included from /usr/include/stdio.h:867,
from /builddir/build/BUILD/dwarves-1.16/dwarves.c:18:
/usr/include/bits/stdio2.h:67:10: note: '__builtin___snprintf_chk' output between 2 and 4352 bytes into a destination of size 4096
67 | return __builtin___snprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1,
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
68 | __bos (__s), __fmt, __va_arg_pack ());
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/builddir/build/BUILD/dwarves-1.16/dwarves.c:1663:44: error: '%s' directive output may be truncated writing up to 255 bytes into a region of size between 0 and 4095 [-Werror=format-truncation=]
1663 | snprintf(pathname, sizeof(pathname), "%s/%s",
| ^~
In file included from /usr/include/stdio.h:867,
from /builddir/build/BUILD/dwarves-1.16/dwarves.c:18:
/usr/include/bits/stdio2.h:67:10: note: '__builtin___snprintf_chk' output between 2 and 4352 bytes into a destination of size 4096
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Don't use it if NULL, fixing a segfault with dtagnames as reported in:
https://bugzilla.redhat.com/show_bug.cgi?id=1795379
Reported-by: Jan Pokorný <jpokorny@redhat.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
We need that as the fix in upstream libbpf is in the
tools/lib/bpf/Makefile, that isn't used when building libbpf as part of
pahole, see:
"Makefile: back-port _FILE_OFFSET_BITS=64 and _LARGEFILE64_SOURCE to Makefile"
4a50ceb043
That refers to this in the kernel sources:
71dd77fd4bf7 ("libbpf: use LFS (_FILE_OFFSET_BITS) instead of direct mmap2 syscall")
Cc: Andrii Nakryiko <andrii.nakryiko@gmail.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Julia Kartseva <hex@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Since elfutils 178, libebl is now part of libdw, so searching for libebl
always fails. Simply remove it from the search.
Reviewer notes:
I even built dwarves with the patch against and old elfutils-0.176 and a
new elfutils-0.178 to double check. Builds fine with both.
With elfutils-0.178 pahole even automagically works with the new
debuginfo-client support. See
https://sourceware.org/elfutils/Debuginfod.html
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Reviewed-by: Mark Wielaard <mark@klomp.org>
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Its not yet correct, misses cases where a top level struct doesn't have
the contained type but some of its substructs have, i.e. right now it
looks if the top level struct has the looked up container type and if it
has, it prints its name and then goes to look at all its members if some
has the looked up container type, recursively.
It should go all the way down, even when a struct doesn't have the
looked up contained type some of its members may have.
So for now its better to use 'pahole -E struct_name | less' and then
search for the type, will be fixed after DevConf.cz 2020 :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
pahole -J .tmp_linux.btf during Linux build process always crashes
on my system.
Problem is that when gobuffer is initialized via gobuffer__init(),
it is in state where 'index' (AKA its size) is set to 1, but
'entries' is NULL.
State corrects itself if 'gobuffer__add()' is invoked, as that
will allocate buffer (even if added len == 0). But if __add()
is never invoked because only anonymous symbols are present,
one ends up with gobuffer that crashes gobuffer__copy.
Instead of allocating single-byte buffer always I opted for
checking if gobuffer entries is NULL before use in copy and
compress - gobuffer__init() would need prototype change to
report malloc failures, and it seems unnecessary to allocate
memory always - even if file does not have any symbols after
all.
(gdb) bt
#0 __memmove_sse2_unaligned_erms () at ../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:287
#1 0x00007f2f2c1ec2ee in btf_elf__encode (btfe=0x5654e31e2e30, flags=flags@entry=0 '\000') at libbtf.c:750
#2 0x00007f2f2c1e9af0 in btf_encoder__encode () at btf_encoder.c:164
#3 0x00005654e2407599 in main (argc=3, argv=0x7ffcd8783f18) at pahole.c:1344
(gdb) frame 1
#1 0x00007f2f2c1ec2ee in btf_elf__encode (btfe=0x5654e31e2e30, flags=flags@entry=0 '\000') at libbtf.c:750
750 gobuffer__copy(btfe->strings, btf_elf__nohdr_data(btfe) + hdr->str_off);
(gdb) print btfe->strings
$1 = (struct gobuffer *) 0x5654e31db2c8
(gdb) print *btfe->strings
$2 = {entries = 0x0, nr_entries = 0, index = 1, allocated_size = 0}
(gdb) print btfe->types
$3 = {entries = 0x5654e31e2ef0 "", nr_entries = 1, index = 16, allocated_size = 8192}
(gdb) x /16bx btfe->types.entries
0x5654e31e2ef0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01
0x5654e31e2ef8: 0x04 0x00 0x00 0x00 0x20 0x00 0x00 0x00
Signed-off-by: Petr Vandrovec <petr@vmware.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
That str variable _will_ be initialized at that point, but lets set it
to NULL to silence gcc version 4.8.5 20150623.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
The default is to show structs and unions, if just structs should be
considered, use --structs, just don't use it together with --unions or
nothing will be shown 8-)
$ pahole --find_pointers_to ehci_qh
ehci_hcd: qh_scan_next
ehci_hcd: async
ehci_hcd: dummy
ehci_shadow: qh
$ pahole --structs --find_pointers_to ehci_qh
ehci_hcd: qh_scan_next
ehci_hcd: async
ehci_hcd: dummy
$ pahole --unions --find_pointers_to ehci_qh
ehci_shadow: qh
$ pahole --structs --unions --find_pointers_to ehci_qh
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
I.e. when looking for unions or structs that contains/embeds or looking
for unions/structs that have pointers to a given type.
E.g:
$ pahole --contains inet_sock
sctp_sock
inet_connection_sock
raw_sock
udp_sock
raw6_sock
$ pahole --unions --contains inet_sock
$
We have structs embedding 'struct inet_sock', but no unions doing that.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
When we started supporting unions in pahole some corner cases where
classes were expected needed fixing, this was one such case, that
printed bogus number of holes when handling unions, that is represented
as a 'struct type', that doesn't have ->nr_holes, just 'struct class'
that is has 'struct type' as its first member, i.e. extends it.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
I.e. no point in looking for holes in unions.
Now 'pahole -H 10' will only show the structs with 10 or more alignment
holes, not those + all unions.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>