dwarves/libbtf.c

895 lines
22 KiB
C
Raw Normal View History

/*
SPDX-License-Identifier: GPL-2.0-only
Copyright (C) 2019 Facebook
*/
#include <fcntl.h>
#include <gelf.h>
#include <limits.h>
#include <malloc.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
btf loader: Support raw BTF as available in /sys/kernel/btf/vmlinux Be it automatically when no -F option is passed and /sys/kernel/btf/vmlinux is available, or when /sys/kernel/btf/vmlinux is passed as the filename to the tool, i.e.: $ pahole -C list_head struct list_head { struct list_head * next; /* 0 8 */ struct list_head * prev; /* 8 8 */ /* size: 16, cachelines: 1, members: 2 */ /* last cacheline: 16 bytes */ }; $ strace -e openat pahole -C list_head |& grep /sys/kernel/btf/ openat(AT_FDCWD, "/sys/kernel/btf/vmlinux", O_RDONLY) = 3 $ $ pahole -C list_head /sys/kernel/btf/vmlinux struct list_head { struct list_head * next; /* 0 8 */ struct list_head * prev; /* 8 8 */ /* size: 16, cachelines: 1, members: 2 */ /* last cacheline: 16 bytes */ }; $ If one wants to grab the matching vmlinux to use its DWARF info instead, which is useful to compare the results with what we have from BTF, for instance, its just a matter of using '-F dwarf'. This in turn shows something that at first came as a surprise, but then has a simple explanation: For very common data structures, that will probably appear in all of the DWARF CUs (Compilation Units), like 'struct list_head', using '-F dwarf' is faster: [acme@quaco pahole]$ perf stat -e cycles pahole -F btf -C list_head > /dev/null Performance counter stats for 'pahole -F btf -C list_head': 45,722,518 cycles:u 0.023717300 seconds time elapsed 0.016474000 seconds user 0.007212000 seconds sys [acme@quaco pahole]$ perf stat -e cycles pahole -F dwarf -C list_head > /dev/null Performance counter stats for 'pahole -F dwarf -C list_head': 14,170,321 cycles:u 0.006668904 seconds time elapsed 0.005562000 seconds user 0.001109000 seconds sys [acme@quaco pahole]$ But for something that is more specific to a subsystem, the DWARF loader will have to process way more stuff till it gets to that struct: $ perf stat -e cycles pahole -F dwarf -C tcp_sock > /dev/null Performance counter stats for 'pahole -F dwarf -C tcp_sock': 31,579,795,238 cycles:u 8.332272930 seconds time elapsed 8.032124000 seconds user 0.286537000 seconds sys $ While using the BTF loader the time should be constant, as it loads everything from /sys/kernel/btf/vmlinux: $ perf stat -e cycles pahole -F btf -C tcp_sock > /dev/null Performance counter stats for 'pahole -F btf -C tcp_sock': 48,823,488 cycles:u 0.024102760 seconds time elapsed 0.012035000 seconds user 0.012046000 seconds sys $ Above I used '-F btf' just to show that it can be used, but its not really needed, i.e. those are equivalent: $ strace -e openat pahole -F btf -C list_head |& grep /sys/kernel/btf/vmlinux openat(AT_FDCWD, "/sys/kernel/btf/vmlinux", O_RDONLY) = 3 $ strace -e openat pahole -C list_head |& grep /sys/kernel/btf/vmlinux openat(AT_FDCWD, "/sys/kernel/btf/vmlinux", O_RDONLY) = 3 $ The btf_raw__load() function that ends up being grafted into the preexisting btf_elf routines was based on libbpf's btf_load_raw(). Acked-by: Alexei Starovoitov <ast@fb.com> Cc: Andrii Nakryiko <andriin@fb.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-01-02 19:22:23 +01:00
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdarg.h>
#include "libbtf.h"
#include "lib/bpf/include/uapi/linux/btf.h"
#include "lib/bpf/include/linux/err.h"
#include "lib/bpf/src/btf.h"
#include "lib/bpf/src/libbpf.h"
#include "dutil.h"
#include "gobuffer.h"
#include "dwarves.h"
btf_encoder: Teach pahole to store percpu variables in vmlinux BTF. 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>
2020-07-08 22:44:10 +02:00
#include "elf_symtab.h"
btf: fix struct/union/fwd types with kind_flag 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 b18354f64cc2 ("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>
2018-12-18 23:09:41 +01:00
#define BTF_INFO_ENCODE(kind, kind_flag, vlen) \
((!!(kind_flag) << 31) | ((kind) << 24) | ((vlen) & BTF_MAX_VLEN))
#define BTF_INT_ENCODE(encoding, bits_offset, nr_bits) \
((encoding) << 24 | (bits_offset) << 16 | (nr_bits))
struct btf_int_type {
struct btf_type type;
uint32_t data;
};
struct btf_enum_type {
struct btf_type type;
struct btf_enum btf_enum;
};
struct btf_array_type {
struct btf_type type;
struct btf_array array;
};
btf_encoder: Teach pahole to store percpu variables in vmlinux BTF. 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>
2020-07-08 22:44:10 +02:00
struct btf_var_type {
struct btf_type type;
struct btf_var var;
};
uint8_t btf_elf__verbose;
btf_encoder: Teach pahole to store percpu variables in vmlinux BTF. 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>
2020-07-08 22:44:10 +02:00
static int btf_var_secinfo_cmp(const void *a, const void *b)
{
const struct btf_var_secinfo *av = a;
const struct btf_var_secinfo *bv = b;
return av->offset - bv->offset;
}
uint32_t btf_elf__get32(struct btf_elf *btfe, uint32_t *p)
btf_loader: Introduce a loader for the BTF format Show 'struct list_head' from DWARF info: $ pahole -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o struct list_head { struct list_head * next; /* 0 8 */ struct list_head * prev; /* 8 8 */ /* size: 16, cachelines: 1, members: 2 */ /* last cacheline: 16 bytes */ }; Try to show it from BTF, on a file without it: $ pahole -F btf -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o pahole: /home/acme/git/build/v4.20-rc5+/net/ipv4/tcp.o: No debugging information found Encode BTF from the DWARF info: $ pahole -J ~/git/build/v4.20-rc5+/net/ipv4/tcp.o Check that it is there: $ readelf -SW ~/git/build/v4.20-rc5+/net/ipv4/tcp.o | grep BTF readelf: /home/acme/git/build/v4.20-rc5+/net/ipv4/tcp.o: Warning: possibly corrupt ELF header - it has a non-zero program header offset, but no program headers [136] .BTF PROGBITS 0000000000000000 101d0e 042edf 00 0 0 1 Now try again printing 'struct list_head' from the BTF info just encoded: $ pahole -F btf -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o 2> /dev/null struct list_head { struct list_head * next; /* 0 8 */ struct list_head * prev; /* 8 8 */ /* size: 16, cachelines: 1, members: 2 */ /* last cacheline: 16 bytes */ }; $ There is the bitfields case that BTF desn't have the bit_size info for bitfield members that makes the output from dwarf to be different than the one from BTF: $ pahole -F btf -C sk_buff ~/git/build/v4.20-rc5+/net/ipv4/tcp.o > /tmp/sk_buff.btf $ pahole -F dwarf -C sk_buff ~/git/build/v4.20-rc5+/net/ipv4/tcp.o > /tmp/sk_buff.dwarf $ diff -u /tmp/sk_buff.dwarf /tmp/sk_buff.btf --- /tmp/sk_buff.dwarf 2018-12-20 14:50:51.428653046 -0300 +++ /tmp/sk_buff.btf 2018-12-20 14:50:46.302601516 -0300 @@ -38,45 +38,45 @@ __u16 hdr_len; /* 138 2 */ __u16 queue_mapping; /* 140 2 */ __u8 __cloned_offset[0]; /* 142 0 */ - __u8 cloned:1; /* 142: 7 1 */ - __u8 nohdr:1; /* 142: 6 1 */ - __u8 fclone:2; /* 142: 4 1 */ - __u8 peeked:1; /* 142: 3 1 */ - __u8 head_frag:1; /* 142: 2 1 */ - __u8 xmit_more:1; /* 142: 1 1 */ - __u8 pfmemalloc:1; /* 142: 0 1 */ + __u8 cloned; /* 142 1 */ + __u8 nohdr; /* 142 1 */ + __u8 fclone; /* 142 1 */ + __u8 peeked; /* 142 1 */ + __u8 head_frag; /* 142 1 */ + __u8 xmit_more; /* 142 1 */ + __u8 pfmemalloc; /* 142 1 */ /* XXX 1 byte hole, try to pack */ __u32 headers_start[0]; /* 144 0 */ __u8 __pkt_type_offset[0]; /* 144 0 */ - __u8 pkt_type:3; /* 144: 5 1 */ - __u8 ignore_df:1; /* 144: 4 1 */ - __u8 nf_trace:1; /* 144: 3 1 */ - __u8 ip_summed:2; /* 144: 1 1 */ - __u8 ooo_okay:1; /* 144: 0 1 */ - __u8 l4_hash:1; /* 145: 7 1 */ - __u8 sw_hash:1; /* 145: 6 1 */ - __u8 wifi_acked_valid:1; /* 145: 5 1 */ - __u8 wifi_acked:1; /* 145: 4 1 */ - __u8 no_fcs:1; /* 145: 3 1 */ - __u8 encapsulation:1; /* 145: 2 1 */ - __u8 encap_hdr_csum:1; /* 145: 1 1 */ - __u8 csum_valid:1; /* 145: 0 1 */ - __u8 csum_complete_sw:1; /* 146: 7 1 */ - __u8 csum_level:2; /* 146: 5 1 */ - __u8 csum_not_inet:1; /* 146: 4 1 */ - __u8 dst_pending_confirm:1; /* 146: 3 1 */ - __u8 ndisc_nodetype:2; /* 146: 1 1 */ - __u8 ipvs_property:1; /* 146: 0 1 */ - __u8 inner_protocol_type:1; /* 147: 7 1 */ - __u8 remcsum_offload:1; /* 147: 6 1 */ - __u8 offload_fwd_mark:1; /* 147: 5 1 */ - __u8 offload_mr_fwd_mark:1; /* 147: 4 1 */ - __u8 tc_skip_classify:1; /* 147: 3 1 */ - __u8 tc_at_ingress:1; /* 147: 2 1 */ - __u8 tc_redirected:1; /* 147: 1 1 */ - __u8 tc_from_ingress:1; /* 147: 0 1 */ + __u8 pkt_type; /* 144 1 */ + __u8 ignore_df; /* 144 1 */ + __u8 nf_trace; /* 144 1 */ + __u8 ip_summed; /* 144 1 */ + __u8 ooo_okay; /* 144 1 */ + __u8 l4_hash; /* 145 1 */ + __u8 sw_hash; /* 145 1 */ + __u8 wifi_acked_valid; /* 145 1 */ + __u8 wifi_acked; /* 145 1 */ + __u8 no_fcs; /* 145 1 */ + __u8 encapsulation; /* 145 1 */ + __u8 encap_hdr_csum; /* 145 1 */ + __u8 csum_valid; /* 145 1 */ + __u8 csum_complete_sw; /* 146 1 */ + __u8 csum_level; /* 146 1 */ + __u8 csum_not_inet; /* 146 1 */ + __u8 dst_pending_confirm; /* 146 1 */ + __u8 ndisc_nodetype; /* 146 1 */ + __u8 ipvs_property; /* 146 1 */ + __u8 inner_protocol_type; /* 147 1 */ + __u8 remcsum_offload; /* 147 1 */ + __u8 offload_fwd_mark; /* 147 1 */ + __u8 offload_mr_fwd_mark; /* 147 1 */ + __u8 tc_skip_classify; /* 147 1 */ + __u8 tc_at_ingress; /* 147 1 */ + __u8 tc_redirected; /* 147 1 */ + __u8 tc_from_ingress; /* 147 1 */ __u16 tc_index; /* 148 2 */ /* XXX 2 bytes hole, try to pack */ $ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-03 19:44:16 +01:00
{
uint32_t val = *p;
if (btfe->swapped)
btf_loader: Introduce a loader for the BTF format Show 'struct list_head' from DWARF info: $ pahole -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o struct list_head { struct list_head * next; /* 0 8 */ struct list_head * prev; /* 8 8 */ /* size: 16, cachelines: 1, members: 2 */ /* last cacheline: 16 bytes */ }; Try to show it from BTF, on a file without it: $ pahole -F btf -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o pahole: /home/acme/git/build/v4.20-rc5+/net/ipv4/tcp.o: No debugging information found Encode BTF from the DWARF info: $ pahole -J ~/git/build/v4.20-rc5+/net/ipv4/tcp.o Check that it is there: $ readelf -SW ~/git/build/v4.20-rc5+/net/ipv4/tcp.o | grep BTF readelf: /home/acme/git/build/v4.20-rc5+/net/ipv4/tcp.o: Warning: possibly corrupt ELF header - it has a non-zero program header offset, but no program headers [136] .BTF PROGBITS 0000000000000000 101d0e 042edf 00 0 0 1 Now try again printing 'struct list_head' from the BTF info just encoded: $ pahole -F btf -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o 2> /dev/null struct list_head { struct list_head * next; /* 0 8 */ struct list_head * prev; /* 8 8 */ /* size: 16, cachelines: 1, members: 2 */ /* last cacheline: 16 bytes */ }; $ There is the bitfields case that BTF desn't have the bit_size info for bitfield members that makes the output from dwarf to be different than the one from BTF: $ pahole -F btf -C sk_buff ~/git/build/v4.20-rc5+/net/ipv4/tcp.o > /tmp/sk_buff.btf $ pahole -F dwarf -C sk_buff ~/git/build/v4.20-rc5+/net/ipv4/tcp.o > /tmp/sk_buff.dwarf $ diff -u /tmp/sk_buff.dwarf /tmp/sk_buff.btf --- /tmp/sk_buff.dwarf 2018-12-20 14:50:51.428653046 -0300 +++ /tmp/sk_buff.btf 2018-12-20 14:50:46.302601516 -0300 @@ -38,45 +38,45 @@ __u16 hdr_len; /* 138 2 */ __u16 queue_mapping; /* 140 2 */ __u8 __cloned_offset[0]; /* 142 0 */ - __u8 cloned:1; /* 142: 7 1 */ - __u8 nohdr:1; /* 142: 6 1 */ - __u8 fclone:2; /* 142: 4 1 */ - __u8 peeked:1; /* 142: 3 1 */ - __u8 head_frag:1; /* 142: 2 1 */ - __u8 xmit_more:1; /* 142: 1 1 */ - __u8 pfmemalloc:1; /* 142: 0 1 */ + __u8 cloned; /* 142 1 */ + __u8 nohdr; /* 142 1 */ + __u8 fclone; /* 142 1 */ + __u8 peeked; /* 142 1 */ + __u8 head_frag; /* 142 1 */ + __u8 xmit_more; /* 142 1 */ + __u8 pfmemalloc; /* 142 1 */ /* XXX 1 byte hole, try to pack */ __u32 headers_start[0]; /* 144 0 */ __u8 __pkt_type_offset[0]; /* 144 0 */ - __u8 pkt_type:3; /* 144: 5 1 */ - __u8 ignore_df:1; /* 144: 4 1 */ - __u8 nf_trace:1; /* 144: 3 1 */ - __u8 ip_summed:2; /* 144: 1 1 */ - __u8 ooo_okay:1; /* 144: 0 1 */ - __u8 l4_hash:1; /* 145: 7 1 */ - __u8 sw_hash:1; /* 145: 6 1 */ - __u8 wifi_acked_valid:1; /* 145: 5 1 */ - __u8 wifi_acked:1; /* 145: 4 1 */ - __u8 no_fcs:1; /* 145: 3 1 */ - __u8 encapsulation:1; /* 145: 2 1 */ - __u8 encap_hdr_csum:1; /* 145: 1 1 */ - __u8 csum_valid:1; /* 145: 0 1 */ - __u8 csum_complete_sw:1; /* 146: 7 1 */ - __u8 csum_level:2; /* 146: 5 1 */ - __u8 csum_not_inet:1; /* 146: 4 1 */ - __u8 dst_pending_confirm:1; /* 146: 3 1 */ - __u8 ndisc_nodetype:2; /* 146: 1 1 */ - __u8 ipvs_property:1; /* 146: 0 1 */ - __u8 inner_protocol_type:1; /* 147: 7 1 */ - __u8 remcsum_offload:1; /* 147: 6 1 */ - __u8 offload_fwd_mark:1; /* 147: 5 1 */ - __u8 offload_mr_fwd_mark:1; /* 147: 4 1 */ - __u8 tc_skip_classify:1; /* 147: 3 1 */ - __u8 tc_at_ingress:1; /* 147: 2 1 */ - __u8 tc_redirected:1; /* 147: 1 1 */ - __u8 tc_from_ingress:1; /* 147: 0 1 */ + __u8 pkt_type; /* 144 1 */ + __u8 ignore_df; /* 144 1 */ + __u8 nf_trace; /* 144 1 */ + __u8 ip_summed; /* 144 1 */ + __u8 ooo_okay; /* 144 1 */ + __u8 l4_hash; /* 145 1 */ + __u8 sw_hash; /* 145 1 */ + __u8 wifi_acked_valid; /* 145 1 */ + __u8 wifi_acked; /* 145 1 */ + __u8 no_fcs; /* 145 1 */ + __u8 encapsulation; /* 145 1 */ + __u8 encap_hdr_csum; /* 145 1 */ + __u8 csum_valid; /* 145 1 */ + __u8 csum_complete_sw; /* 146 1 */ + __u8 csum_level; /* 146 1 */ + __u8 csum_not_inet; /* 146 1 */ + __u8 dst_pending_confirm; /* 146 1 */ + __u8 ndisc_nodetype; /* 146 1 */ + __u8 ipvs_property; /* 146 1 */ + __u8 inner_protocol_type; /* 147 1 */ + __u8 remcsum_offload; /* 147 1 */ + __u8 offload_fwd_mark; /* 147 1 */ + __u8 offload_mr_fwd_mark; /* 147 1 */ + __u8 tc_skip_classify; /* 147 1 */ + __u8 tc_at_ingress; /* 147 1 */ + __u8 tc_redirected; /* 147 1 */ + __u8 tc_from_ingress; /* 147 1 */ __u16 tc_index; /* 148 2 */ /* XXX 2 bytes hole, try to pack */ $ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-03 19:44:16 +01:00
val = ((val >> 24) |
((val >> 8) & 0x0000ff00) |
((val << 8) & 0x00ff0000) |
(val << 24));
return val;
}
btf loader: Support raw BTF as available in /sys/kernel/btf/vmlinux Be it automatically when no -F option is passed and /sys/kernel/btf/vmlinux is available, or when /sys/kernel/btf/vmlinux is passed as the filename to the tool, i.e.: $ pahole -C list_head struct list_head { struct list_head * next; /* 0 8 */ struct list_head * prev; /* 8 8 */ /* size: 16, cachelines: 1, members: 2 */ /* last cacheline: 16 bytes */ }; $ strace -e openat pahole -C list_head |& grep /sys/kernel/btf/ openat(AT_FDCWD, "/sys/kernel/btf/vmlinux", O_RDONLY) = 3 $ $ pahole -C list_head /sys/kernel/btf/vmlinux struct list_head { struct list_head * next; /* 0 8 */ struct list_head * prev; /* 8 8 */ /* size: 16, cachelines: 1, members: 2 */ /* last cacheline: 16 bytes */ }; $ If one wants to grab the matching vmlinux to use its DWARF info instead, which is useful to compare the results with what we have from BTF, for instance, its just a matter of using '-F dwarf'. This in turn shows something that at first came as a surprise, but then has a simple explanation: For very common data structures, that will probably appear in all of the DWARF CUs (Compilation Units), like 'struct list_head', using '-F dwarf' is faster: [acme@quaco pahole]$ perf stat -e cycles pahole -F btf -C list_head > /dev/null Performance counter stats for 'pahole -F btf -C list_head': 45,722,518 cycles:u 0.023717300 seconds time elapsed 0.016474000 seconds user 0.007212000 seconds sys [acme@quaco pahole]$ perf stat -e cycles pahole -F dwarf -C list_head > /dev/null Performance counter stats for 'pahole -F dwarf -C list_head': 14,170,321 cycles:u 0.006668904 seconds time elapsed 0.005562000 seconds user 0.001109000 seconds sys [acme@quaco pahole]$ But for something that is more specific to a subsystem, the DWARF loader will have to process way more stuff till it gets to that struct: $ perf stat -e cycles pahole -F dwarf -C tcp_sock > /dev/null Performance counter stats for 'pahole -F dwarf -C tcp_sock': 31,579,795,238 cycles:u 8.332272930 seconds time elapsed 8.032124000 seconds user 0.286537000 seconds sys $ While using the BTF loader the time should be constant, as it loads everything from /sys/kernel/btf/vmlinux: $ perf stat -e cycles pahole -F btf -C tcp_sock > /dev/null Performance counter stats for 'pahole -F btf -C tcp_sock': 48,823,488 cycles:u 0.024102760 seconds time elapsed 0.012035000 seconds user 0.012046000 seconds sys $ Above I used '-F btf' just to show that it can be used, but its not really needed, i.e. those are equivalent: $ strace -e openat pahole -F btf -C list_head |& grep /sys/kernel/btf/vmlinux openat(AT_FDCWD, "/sys/kernel/btf/vmlinux", O_RDONLY) = 3 $ strace -e openat pahole -C list_head |& grep /sys/kernel/btf/vmlinux openat(AT_FDCWD, "/sys/kernel/btf/vmlinux", O_RDONLY) = 3 $ The btf_raw__load() function that ends up being grafted into the preexisting btf_elf routines was based on libbpf's btf_load_raw(). Acked-by: Alexei Starovoitov <ast@fb.com> Cc: Andrii Nakryiko <andriin@fb.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-01-02 19:22:23 +01:00
static int btf_raw__load(struct btf_elf *btfe)
{
size_t read_cnt;
struct stat st;
void *data;
FILE *fp;
if (stat(btfe->filename, &st))
return -1;
data = malloc(st.st_size);
if (!data)
return -1;
fp = fopen(btfe->filename, "rb");
if (!fp)
goto cleanup;
read_cnt = fread(data, 1, st.st_size, fp);
fclose(fp);
if (read_cnt < st.st_size)
goto cleanup;
btfe->swapped = 0;
btfe->data = data;
btfe->size = read_cnt;
return 0;
cleanup:
free(data);
return -1;
}
int btf_elf__load(struct btf_elf *btfe)
btf_loader: Introduce a loader for the BTF format Show 'struct list_head' from DWARF info: $ pahole -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o struct list_head { struct list_head * next; /* 0 8 */ struct list_head * prev; /* 8 8 */ /* size: 16, cachelines: 1, members: 2 */ /* last cacheline: 16 bytes */ }; Try to show it from BTF, on a file without it: $ pahole -F btf -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o pahole: /home/acme/git/build/v4.20-rc5+/net/ipv4/tcp.o: No debugging information found Encode BTF from the DWARF info: $ pahole -J ~/git/build/v4.20-rc5+/net/ipv4/tcp.o Check that it is there: $ readelf -SW ~/git/build/v4.20-rc5+/net/ipv4/tcp.o | grep BTF readelf: /home/acme/git/build/v4.20-rc5+/net/ipv4/tcp.o: Warning: possibly corrupt ELF header - it has a non-zero program header offset, but no program headers [136] .BTF PROGBITS 0000000000000000 101d0e 042edf 00 0 0 1 Now try again printing 'struct list_head' from the BTF info just encoded: $ pahole -F btf -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o 2> /dev/null struct list_head { struct list_head * next; /* 0 8 */ struct list_head * prev; /* 8 8 */ /* size: 16, cachelines: 1, members: 2 */ /* last cacheline: 16 bytes */ }; $ There is the bitfields case that BTF desn't have the bit_size info for bitfield members that makes the output from dwarf to be different than the one from BTF: $ pahole -F btf -C sk_buff ~/git/build/v4.20-rc5+/net/ipv4/tcp.o > /tmp/sk_buff.btf $ pahole -F dwarf -C sk_buff ~/git/build/v4.20-rc5+/net/ipv4/tcp.o > /tmp/sk_buff.dwarf $ diff -u /tmp/sk_buff.dwarf /tmp/sk_buff.btf --- /tmp/sk_buff.dwarf 2018-12-20 14:50:51.428653046 -0300 +++ /tmp/sk_buff.btf 2018-12-20 14:50:46.302601516 -0300 @@ -38,45 +38,45 @@ __u16 hdr_len; /* 138 2 */ __u16 queue_mapping; /* 140 2 */ __u8 __cloned_offset[0]; /* 142 0 */ - __u8 cloned:1; /* 142: 7 1 */ - __u8 nohdr:1; /* 142: 6 1 */ - __u8 fclone:2; /* 142: 4 1 */ - __u8 peeked:1; /* 142: 3 1 */ - __u8 head_frag:1; /* 142: 2 1 */ - __u8 xmit_more:1; /* 142: 1 1 */ - __u8 pfmemalloc:1; /* 142: 0 1 */ + __u8 cloned; /* 142 1 */ + __u8 nohdr; /* 142 1 */ + __u8 fclone; /* 142 1 */ + __u8 peeked; /* 142 1 */ + __u8 head_frag; /* 142 1 */ + __u8 xmit_more; /* 142 1 */ + __u8 pfmemalloc; /* 142 1 */ /* XXX 1 byte hole, try to pack */ __u32 headers_start[0]; /* 144 0 */ __u8 __pkt_type_offset[0]; /* 144 0 */ - __u8 pkt_type:3; /* 144: 5 1 */ - __u8 ignore_df:1; /* 144: 4 1 */ - __u8 nf_trace:1; /* 144: 3 1 */ - __u8 ip_summed:2; /* 144: 1 1 */ - __u8 ooo_okay:1; /* 144: 0 1 */ - __u8 l4_hash:1; /* 145: 7 1 */ - __u8 sw_hash:1; /* 145: 6 1 */ - __u8 wifi_acked_valid:1; /* 145: 5 1 */ - __u8 wifi_acked:1; /* 145: 4 1 */ - __u8 no_fcs:1; /* 145: 3 1 */ - __u8 encapsulation:1; /* 145: 2 1 */ - __u8 encap_hdr_csum:1; /* 145: 1 1 */ - __u8 csum_valid:1; /* 145: 0 1 */ - __u8 csum_complete_sw:1; /* 146: 7 1 */ - __u8 csum_level:2; /* 146: 5 1 */ - __u8 csum_not_inet:1; /* 146: 4 1 */ - __u8 dst_pending_confirm:1; /* 146: 3 1 */ - __u8 ndisc_nodetype:2; /* 146: 1 1 */ - __u8 ipvs_property:1; /* 146: 0 1 */ - __u8 inner_protocol_type:1; /* 147: 7 1 */ - __u8 remcsum_offload:1; /* 147: 6 1 */ - __u8 offload_fwd_mark:1; /* 147: 5 1 */ - __u8 offload_mr_fwd_mark:1; /* 147: 4 1 */ - __u8 tc_skip_classify:1; /* 147: 3 1 */ - __u8 tc_at_ingress:1; /* 147: 2 1 */ - __u8 tc_redirected:1; /* 147: 1 1 */ - __u8 tc_from_ingress:1; /* 147: 0 1 */ + __u8 pkt_type; /* 144 1 */ + __u8 ignore_df; /* 144 1 */ + __u8 nf_trace; /* 144 1 */ + __u8 ip_summed; /* 144 1 */ + __u8 ooo_okay; /* 144 1 */ + __u8 l4_hash; /* 145 1 */ + __u8 sw_hash; /* 145 1 */ + __u8 wifi_acked_valid; /* 145 1 */ + __u8 wifi_acked; /* 145 1 */ + __u8 no_fcs; /* 145 1 */ + __u8 encapsulation; /* 145 1 */ + __u8 encap_hdr_csum; /* 145 1 */ + __u8 csum_valid; /* 145 1 */ + __u8 csum_complete_sw; /* 146 1 */ + __u8 csum_level; /* 146 1 */ + __u8 csum_not_inet; /* 146 1 */ + __u8 dst_pending_confirm; /* 146 1 */ + __u8 ndisc_nodetype; /* 146 1 */ + __u8 ipvs_property; /* 146 1 */ + __u8 inner_protocol_type; /* 147 1 */ + __u8 remcsum_offload; /* 147 1 */ + __u8 offload_fwd_mark; /* 147 1 */ + __u8 offload_mr_fwd_mark; /* 147 1 */ + __u8 tc_skip_classify; /* 147 1 */ + __u8 tc_at_ingress; /* 147 1 */ + __u8 tc_redirected; /* 147 1 */ + __u8 tc_from_ingress; /* 147 1 */ __u16 tc_index; /* 148 2 */ /* XXX 2 bytes hole, try to pack */ $ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-03 19:44:16 +01:00
{
btf loader: Support raw BTF as available in /sys/kernel/btf/vmlinux Be it automatically when no -F option is passed and /sys/kernel/btf/vmlinux is available, or when /sys/kernel/btf/vmlinux is passed as the filename to the tool, i.e.: $ pahole -C list_head struct list_head { struct list_head * next; /* 0 8 */ struct list_head * prev; /* 8 8 */ /* size: 16, cachelines: 1, members: 2 */ /* last cacheline: 16 bytes */ }; $ strace -e openat pahole -C list_head |& grep /sys/kernel/btf/ openat(AT_FDCWD, "/sys/kernel/btf/vmlinux", O_RDONLY) = 3 $ $ pahole -C list_head /sys/kernel/btf/vmlinux struct list_head { struct list_head * next; /* 0 8 */ struct list_head * prev; /* 8 8 */ /* size: 16, cachelines: 1, members: 2 */ /* last cacheline: 16 bytes */ }; $ If one wants to grab the matching vmlinux to use its DWARF info instead, which is useful to compare the results with what we have from BTF, for instance, its just a matter of using '-F dwarf'. This in turn shows something that at first came as a surprise, but then has a simple explanation: For very common data structures, that will probably appear in all of the DWARF CUs (Compilation Units), like 'struct list_head', using '-F dwarf' is faster: [acme@quaco pahole]$ perf stat -e cycles pahole -F btf -C list_head > /dev/null Performance counter stats for 'pahole -F btf -C list_head': 45,722,518 cycles:u 0.023717300 seconds time elapsed 0.016474000 seconds user 0.007212000 seconds sys [acme@quaco pahole]$ perf stat -e cycles pahole -F dwarf -C list_head > /dev/null Performance counter stats for 'pahole -F dwarf -C list_head': 14,170,321 cycles:u 0.006668904 seconds time elapsed 0.005562000 seconds user 0.001109000 seconds sys [acme@quaco pahole]$ But for something that is more specific to a subsystem, the DWARF loader will have to process way more stuff till it gets to that struct: $ perf stat -e cycles pahole -F dwarf -C tcp_sock > /dev/null Performance counter stats for 'pahole -F dwarf -C tcp_sock': 31,579,795,238 cycles:u 8.332272930 seconds time elapsed 8.032124000 seconds user 0.286537000 seconds sys $ While using the BTF loader the time should be constant, as it loads everything from /sys/kernel/btf/vmlinux: $ perf stat -e cycles pahole -F btf -C tcp_sock > /dev/null Performance counter stats for 'pahole -F btf -C tcp_sock': 48,823,488 cycles:u 0.024102760 seconds time elapsed 0.012035000 seconds user 0.012046000 seconds sys $ Above I used '-F btf' just to show that it can be used, but its not really needed, i.e. those are equivalent: $ strace -e openat pahole -F btf -C list_head |& grep /sys/kernel/btf/vmlinux openat(AT_FDCWD, "/sys/kernel/btf/vmlinux", O_RDONLY) = 3 $ strace -e openat pahole -C list_head |& grep /sys/kernel/btf/vmlinux openat(AT_FDCWD, "/sys/kernel/btf/vmlinux", O_RDONLY) = 3 $ The btf_raw__load() function that ends up being grafted into the preexisting btf_elf routines was based on libbpf's btf_load_raw(). Acked-by: Alexei Starovoitov <ast@fb.com> Cc: Andrii Nakryiko <andriin@fb.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-01-02 19:22:23 +01:00
if (btfe->raw_btf)
return btf_raw__load(btfe);
btf_loader: Introduce a loader for the BTF format Show 'struct list_head' from DWARF info: $ pahole -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o struct list_head { struct list_head * next; /* 0 8 */ struct list_head * prev; /* 8 8 */ /* size: 16, cachelines: 1, members: 2 */ /* last cacheline: 16 bytes */ }; Try to show it from BTF, on a file without it: $ pahole -F btf -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o pahole: /home/acme/git/build/v4.20-rc5+/net/ipv4/tcp.o: No debugging information found Encode BTF from the DWARF info: $ pahole -J ~/git/build/v4.20-rc5+/net/ipv4/tcp.o Check that it is there: $ readelf -SW ~/git/build/v4.20-rc5+/net/ipv4/tcp.o | grep BTF readelf: /home/acme/git/build/v4.20-rc5+/net/ipv4/tcp.o: Warning: possibly corrupt ELF header - it has a non-zero program header offset, but no program headers [136] .BTF PROGBITS 0000000000000000 101d0e 042edf 00 0 0 1 Now try again printing 'struct list_head' from the BTF info just encoded: $ pahole -F btf -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o 2> /dev/null struct list_head { struct list_head * next; /* 0 8 */ struct list_head * prev; /* 8 8 */ /* size: 16, cachelines: 1, members: 2 */ /* last cacheline: 16 bytes */ }; $ There is the bitfields case that BTF desn't have the bit_size info for bitfield members that makes the output from dwarf to be different than the one from BTF: $ pahole -F btf -C sk_buff ~/git/build/v4.20-rc5+/net/ipv4/tcp.o > /tmp/sk_buff.btf $ pahole -F dwarf -C sk_buff ~/git/build/v4.20-rc5+/net/ipv4/tcp.o > /tmp/sk_buff.dwarf $ diff -u /tmp/sk_buff.dwarf /tmp/sk_buff.btf --- /tmp/sk_buff.dwarf 2018-12-20 14:50:51.428653046 -0300 +++ /tmp/sk_buff.btf 2018-12-20 14:50:46.302601516 -0300 @@ -38,45 +38,45 @@ __u16 hdr_len; /* 138 2 */ __u16 queue_mapping; /* 140 2 */ __u8 __cloned_offset[0]; /* 142 0 */ - __u8 cloned:1; /* 142: 7 1 */ - __u8 nohdr:1; /* 142: 6 1 */ - __u8 fclone:2; /* 142: 4 1 */ - __u8 peeked:1; /* 142: 3 1 */ - __u8 head_frag:1; /* 142: 2 1 */ - __u8 xmit_more:1; /* 142: 1 1 */ - __u8 pfmemalloc:1; /* 142: 0 1 */ + __u8 cloned; /* 142 1 */ + __u8 nohdr; /* 142 1 */ + __u8 fclone; /* 142 1 */ + __u8 peeked; /* 142 1 */ + __u8 head_frag; /* 142 1 */ + __u8 xmit_more; /* 142 1 */ + __u8 pfmemalloc; /* 142 1 */ /* XXX 1 byte hole, try to pack */ __u32 headers_start[0]; /* 144 0 */ __u8 __pkt_type_offset[0]; /* 144 0 */ - __u8 pkt_type:3; /* 144: 5 1 */ - __u8 ignore_df:1; /* 144: 4 1 */ - __u8 nf_trace:1; /* 144: 3 1 */ - __u8 ip_summed:2; /* 144: 1 1 */ - __u8 ooo_okay:1; /* 144: 0 1 */ - __u8 l4_hash:1; /* 145: 7 1 */ - __u8 sw_hash:1; /* 145: 6 1 */ - __u8 wifi_acked_valid:1; /* 145: 5 1 */ - __u8 wifi_acked:1; /* 145: 4 1 */ - __u8 no_fcs:1; /* 145: 3 1 */ - __u8 encapsulation:1; /* 145: 2 1 */ - __u8 encap_hdr_csum:1; /* 145: 1 1 */ - __u8 csum_valid:1; /* 145: 0 1 */ - __u8 csum_complete_sw:1; /* 146: 7 1 */ - __u8 csum_level:2; /* 146: 5 1 */ - __u8 csum_not_inet:1; /* 146: 4 1 */ - __u8 dst_pending_confirm:1; /* 146: 3 1 */ - __u8 ndisc_nodetype:2; /* 146: 1 1 */ - __u8 ipvs_property:1; /* 146: 0 1 */ - __u8 inner_protocol_type:1; /* 147: 7 1 */ - __u8 remcsum_offload:1; /* 147: 6 1 */ - __u8 offload_fwd_mark:1; /* 147: 5 1 */ - __u8 offload_mr_fwd_mark:1; /* 147: 4 1 */ - __u8 tc_skip_classify:1; /* 147: 3 1 */ - __u8 tc_at_ingress:1; /* 147: 2 1 */ - __u8 tc_redirected:1; /* 147: 1 1 */ - __u8 tc_from_ingress:1; /* 147: 0 1 */ + __u8 pkt_type; /* 144 1 */ + __u8 ignore_df; /* 144 1 */ + __u8 nf_trace; /* 144 1 */ + __u8 ip_summed; /* 144 1 */ + __u8 ooo_okay; /* 144 1 */ + __u8 l4_hash; /* 145 1 */ + __u8 sw_hash; /* 145 1 */ + __u8 wifi_acked_valid; /* 145 1 */ + __u8 wifi_acked; /* 145 1 */ + __u8 no_fcs; /* 145 1 */ + __u8 encapsulation; /* 145 1 */ + __u8 encap_hdr_csum; /* 145 1 */ + __u8 csum_valid; /* 145 1 */ + __u8 csum_complete_sw; /* 146 1 */ + __u8 csum_level; /* 146 1 */ + __u8 csum_not_inet; /* 146 1 */ + __u8 dst_pending_confirm; /* 146 1 */ + __u8 ndisc_nodetype; /* 146 1 */ + __u8 ipvs_property; /* 146 1 */ + __u8 inner_protocol_type; /* 147 1 */ + __u8 remcsum_offload; /* 147 1 */ + __u8 offload_fwd_mark; /* 147 1 */ + __u8 offload_mr_fwd_mark; /* 147 1 */ + __u8 tc_skip_classify; /* 147 1 */ + __u8 tc_at_ingress; /* 147 1 */ + __u8 tc_redirected; /* 147 1 */ + __u8 tc_from_ingress; /* 147 1 */ __u16 tc_index; /* 148 2 */ /* XXX 2 bytes hole, try to pack */ $ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-03 19:44:16 +01:00
int err = -ENOTSUP;
GElf_Shdr shdr;
Elf_Scn *sec = elf_section_by_name(btfe->elf, &btfe->ehdr, &shdr, ".BTF", NULL);
btf_loader: Introduce a loader for the BTF format Show 'struct list_head' from DWARF info: $ pahole -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o struct list_head { struct list_head * next; /* 0 8 */ struct list_head * prev; /* 8 8 */ /* size: 16, cachelines: 1, members: 2 */ /* last cacheline: 16 bytes */ }; Try to show it from BTF, on a file without it: $ pahole -F btf -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o pahole: /home/acme/git/build/v4.20-rc5+/net/ipv4/tcp.o: No debugging information found Encode BTF from the DWARF info: $ pahole -J ~/git/build/v4.20-rc5+/net/ipv4/tcp.o Check that it is there: $ readelf -SW ~/git/build/v4.20-rc5+/net/ipv4/tcp.o | grep BTF readelf: /home/acme/git/build/v4.20-rc5+/net/ipv4/tcp.o: Warning: possibly corrupt ELF header - it has a non-zero program header offset, but no program headers [136] .BTF PROGBITS 0000000000000000 101d0e 042edf 00 0 0 1 Now try again printing 'struct list_head' from the BTF info just encoded: $ pahole -F btf -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o 2> /dev/null struct list_head { struct list_head * next; /* 0 8 */ struct list_head * prev; /* 8 8 */ /* size: 16, cachelines: 1, members: 2 */ /* last cacheline: 16 bytes */ }; $ There is the bitfields case that BTF desn't have the bit_size info for bitfield members that makes the output from dwarf to be different than the one from BTF: $ pahole -F btf -C sk_buff ~/git/build/v4.20-rc5+/net/ipv4/tcp.o > /tmp/sk_buff.btf $ pahole -F dwarf -C sk_buff ~/git/build/v4.20-rc5+/net/ipv4/tcp.o > /tmp/sk_buff.dwarf $ diff -u /tmp/sk_buff.dwarf /tmp/sk_buff.btf --- /tmp/sk_buff.dwarf 2018-12-20 14:50:51.428653046 -0300 +++ /tmp/sk_buff.btf 2018-12-20 14:50:46.302601516 -0300 @@ -38,45 +38,45 @@ __u16 hdr_len; /* 138 2 */ __u16 queue_mapping; /* 140 2 */ __u8 __cloned_offset[0]; /* 142 0 */ - __u8 cloned:1; /* 142: 7 1 */ - __u8 nohdr:1; /* 142: 6 1 */ - __u8 fclone:2; /* 142: 4 1 */ - __u8 peeked:1; /* 142: 3 1 */ - __u8 head_frag:1; /* 142: 2 1 */ - __u8 xmit_more:1; /* 142: 1 1 */ - __u8 pfmemalloc:1; /* 142: 0 1 */ + __u8 cloned; /* 142 1 */ + __u8 nohdr; /* 142 1 */ + __u8 fclone; /* 142 1 */ + __u8 peeked; /* 142 1 */ + __u8 head_frag; /* 142 1 */ + __u8 xmit_more; /* 142 1 */ + __u8 pfmemalloc; /* 142 1 */ /* XXX 1 byte hole, try to pack */ __u32 headers_start[0]; /* 144 0 */ __u8 __pkt_type_offset[0]; /* 144 0 */ - __u8 pkt_type:3; /* 144: 5 1 */ - __u8 ignore_df:1; /* 144: 4 1 */ - __u8 nf_trace:1; /* 144: 3 1 */ - __u8 ip_summed:2; /* 144: 1 1 */ - __u8 ooo_okay:1; /* 144: 0 1 */ - __u8 l4_hash:1; /* 145: 7 1 */ - __u8 sw_hash:1; /* 145: 6 1 */ - __u8 wifi_acked_valid:1; /* 145: 5 1 */ - __u8 wifi_acked:1; /* 145: 4 1 */ - __u8 no_fcs:1; /* 145: 3 1 */ - __u8 encapsulation:1; /* 145: 2 1 */ - __u8 encap_hdr_csum:1; /* 145: 1 1 */ - __u8 csum_valid:1; /* 145: 0 1 */ - __u8 csum_complete_sw:1; /* 146: 7 1 */ - __u8 csum_level:2; /* 146: 5 1 */ - __u8 csum_not_inet:1; /* 146: 4 1 */ - __u8 dst_pending_confirm:1; /* 146: 3 1 */ - __u8 ndisc_nodetype:2; /* 146: 1 1 */ - __u8 ipvs_property:1; /* 146: 0 1 */ - __u8 inner_protocol_type:1; /* 147: 7 1 */ - __u8 remcsum_offload:1; /* 147: 6 1 */ - __u8 offload_fwd_mark:1; /* 147: 5 1 */ - __u8 offload_mr_fwd_mark:1; /* 147: 4 1 */ - __u8 tc_skip_classify:1; /* 147: 3 1 */ - __u8 tc_at_ingress:1; /* 147: 2 1 */ - __u8 tc_redirected:1; /* 147: 1 1 */ - __u8 tc_from_ingress:1; /* 147: 0 1 */ + __u8 pkt_type; /* 144 1 */ + __u8 ignore_df; /* 144 1 */ + __u8 nf_trace; /* 144 1 */ + __u8 ip_summed; /* 144 1 */ + __u8 ooo_okay; /* 144 1 */ + __u8 l4_hash; /* 145 1 */ + __u8 sw_hash; /* 145 1 */ + __u8 wifi_acked_valid; /* 145 1 */ + __u8 wifi_acked; /* 145 1 */ + __u8 no_fcs; /* 145 1 */ + __u8 encapsulation; /* 145 1 */ + __u8 encap_hdr_csum; /* 145 1 */ + __u8 csum_valid; /* 145 1 */ + __u8 csum_complete_sw; /* 146 1 */ + __u8 csum_level; /* 146 1 */ + __u8 csum_not_inet; /* 146 1 */ + __u8 dst_pending_confirm; /* 146 1 */ + __u8 ndisc_nodetype; /* 146 1 */ + __u8 ipvs_property; /* 146 1 */ + __u8 inner_protocol_type; /* 147 1 */ + __u8 remcsum_offload; /* 147 1 */ + __u8 offload_fwd_mark; /* 147 1 */ + __u8 offload_mr_fwd_mark; /* 147 1 */ + __u8 tc_skip_classify; /* 147 1 */ + __u8 tc_at_ingress; /* 147 1 */ + __u8 tc_redirected; /* 147 1 */ + __u8 tc_from_ingress; /* 147 1 */ __u16 tc_index; /* 148 2 */ /* XXX 2 bytes hole, try to pack */ $ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-03 19:44:16 +01:00
if (sec == NULL)
return -ESRCH;
Elf_Data *data = elf_getdata(sec, NULL);
if (data == NULL) {
fprintf(stderr, "%s: cannot get data of BTF section.\n", __func__);
return -1;
}
struct btf_header *hp = data->d_buf;
size_t orig_size = data->d_size;
if (hp->version != BTF_VERSION)
goto out;
err = -EINVAL;
if (hp->magic == BTF_MAGIC)
btfe->swapped = 0;
btf_loader: Introduce a loader for the BTF format Show 'struct list_head' from DWARF info: $ pahole -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o struct list_head { struct list_head * next; /* 0 8 */ struct list_head * prev; /* 8 8 */ /* size: 16, cachelines: 1, members: 2 */ /* last cacheline: 16 bytes */ }; Try to show it from BTF, on a file without it: $ pahole -F btf -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o pahole: /home/acme/git/build/v4.20-rc5+/net/ipv4/tcp.o: No debugging information found Encode BTF from the DWARF info: $ pahole -J ~/git/build/v4.20-rc5+/net/ipv4/tcp.o Check that it is there: $ readelf -SW ~/git/build/v4.20-rc5+/net/ipv4/tcp.o | grep BTF readelf: /home/acme/git/build/v4.20-rc5+/net/ipv4/tcp.o: Warning: possibly corrupt ELF header - it has a non-zero program header offset, but no program headers [136] .BTF PROGBITS 0000000000000000 101d0e 042edf 00 0 0 1 Now try again printing 'struct list_head' from the BTF info just encoded: $ pahole -F btf -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o 2> /dev/null struct list_head { struct list_head * next; /* 0 8 */ struct list_head * prev; /* 8 8 */ /* size: 16, cachelines: 1, members: 2 */ /* last cacheline: 16 bytes */ }; $ There is the bitfields case that BTF desn't have the bit_size info for bitfield members that makes the output from dwarf to be different than the one from BTF: $ pahole -F btf -C sk_buff ~/git/build/v4.20-rc5+/net/ipv4/tcp.o > /tmp/sk_buff.btf $ pahole -F dwarf -C sk_buff ~/git/build/v4.20-rc5+/net/ipv4/tcp.o > /tmp/sk_buff.dwarf $ diff -u /tmp/sk_buff.dwarf /tmp/sk_buff.btf --- /tmp/sk_buff.dwarf 2018-12-20 14:50:51.428653046 -0300 +++ /tmp/sk_buff.btf 2018-12-20 14:50:46.302601516 -0300 @@ -38,45 +38,45 @@ __u16 hdr_len; /* 138 2 */ __u16 queue_mapping; /* 140 2 */ __u8 __cloned_offset[0]; /* 142 0 */ - __u8 cloned:1; /* 142: 7 1 */ - __u8 nohdr:1; /* 142: 6 1 */ - __u8 fclone:2; /* 142: 4 1 */ - __u8 peeked:1; /* 142: 3 1 */ - __u8 head_frag:1; /* 142: 2 1 */ - __u8 xmit_more:1; /* 142: 1 1 */ - __u8 pfmemalloc:1; /* 142: 0 1 */ + __u8 cloned; /* 142 1 */ + __u8 nohdr; /* 142 1 */ + __u8 fclone; /* 142 1 */ + __u8 peeked; /* 142 1 */ + __u8 head_frag; /* 142 1 */ + __u8 xmit_more; /* 142 1 */ + __u8 pfmemalloc; /* 142 1 */ /* XXX 1 byte hole, try to pack */ __u32 headers_start[0]; /* 144 0 */ __u8 __pkt_type_offset[0]; /* 144 0 */ - __u8 pkt_type:3; /* 144: 5 1 */ - __u8 ignore_df:1; /* 144: 4 1 */ - __u8 nf_trace:1; /* 144: 3 1 */ - __u8 ip_summed:2; /* 144: 1 1 */ - __u8 ooo_okay:1; /* 144: 0 1 */ - __u8 l4_hash:1; /* 145: 7 1 */ - __u8 sw_hash:1; /* 145: 6 1 */ - __u8 wifi_acked_valid:1; /* 145: 5 1 */ - __u8 wifi_acked:1; /* 145: 4 1 */ - __u8 no_fcs:1; /* 145: 3 1 */ - __u8 encapsulation:1; /* 145: 2 1 */ - __u8 encap_hdr_csum:1; /* 145: 1 1 */ - __u8 csum_valid:1; /* 145: 0 1 */ - __u8 csum_complete_sw:1; /* 146: 7 1 */ - __u8 csum_level:2; /* 146: 5 1 */ - __u8 csum_not_inet:1; /* 146: 4 1 */ - __u8 dst_pending_confirm:1; /* 146: 3 1 */ - __u8 ndisc_nodetype:2; /* 146: 1 1 */ - __u8 ipvs_property:1; /* 146: 0 1 */ - __u8 inner_protocol_type:1; /* 147: 7 1 */ - __u8 remcsum_offload:1; /* 147: 6 1 */ - __u8 offload_fwd_mark:1; /* 147: 5 1 */ - __u8 offload_mr_fwd_mark:1; /* 147: 4 1 */ - __u8 tc_skip_classify:1; /* 147: 3 1 */ - __u8 tc_at_ingress:1; /* 147: 2 1 */ - __u8 tc_redirected:1; /* 147: 1 1 */ - __u8 tc_from_ingress:1; /* 147: 0 1 */ + __u8 pkt_type; /* 144 1 */ + __u8 ignore_df; /* 144 1 */ + __u8 nf_trace; /* 144 1 */ + __u8 ip_summed; /* 144 1 */ + __u8 ooo_okay; /* 144 1 */ + __u8 l4_hash; /* 145 1 */ + __u8 sw_hash; /* 145 1 */ + __u8 wifi_acked_valid; /* 145 1 */ + __u8 wifi_acked; /* 145 1 */ + __u8 no_fcs; /* 145 1 */ + __u8 encapsulation; /* 145 1 */ + __u8 encap_hdr_csum; /* 145 1 */ + __u8 csum_valid; /* 145 1 */ + __u8 csum_complete_sw; /* 146 1 */ + __u8 csum_level; /* 146 1 */ + __u8 csum_not_inet; /* 146 1 */ + __u8 dst_pending_confirm; /* 146 1 */ + __u8 ndisc_nodetype; /* 146 1 */ + __u8 ipvs_property; /* 146 1 */ + __u8 inner_protocol_type; /* 147 1 */ + __u8 remcsum_offload; /* 147 1 */ + __u8 offload_fwd_mark; /* 147 1 */ + __u8 offload_mr_fwd_mark; /* 147 1 */ + __u8 tc_skip_classify; /* 147 1 */ + __u8 tc_at_ingress; /* 147 1 */ + __u8 tc_redirected; /* 147 1 */ + __u8 tc_from_ingress; /* 147 1 */ __u16 tc_index; /* 148 2 */ /* XXX 2 bytes hole, try to pack */ $ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-03 19:44:16 +01:00
else
goto out;
err = -ENOMEM;
btfe->data = malloc(orig_size);
if (btfe->data != NULL) {
memcpy(btfe->data, hp, orig_size);
btfe->size = orig_size;
btf_loader: Introduce a loader for the BTF format Show 'struct list_head' from DWARF info: $ pahole -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o struct list_head { struct list_head * next; /* 0 8 */ struct list_head * prev; /* 8 8 */ /* size: 16, cachelines: 1, members: 2 */ /* last cacheline: 16 bytes */ }; Try to show it from BTF, on a file without it: $ pahole -F btf -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o pahole: /home/acme/git/build/v4.20-rc5+/net/ipv4/tcp.o: No debugging information found Encode BTF from the DWARF info: $ pahole -J ~/git/build/v4.20-rc5+/net/ipv4/tcp.o Check that it is there: $ readelf -SW ~/git/build/v4.20-rc5+/net/ipv4/tcp.o | grep BTF readelf: /home/acme/git/build/v4.20-rc5+/net/ipv4/tcp.o: Warning: possibly corrupt ELF header - it has a non-zero program header offset, but no program headers [136] .BTF PROGBITS 0000000000000000 101d0e 042edf 00 0 0 1 Now try again printing 'struct list_head' from the BTF info just encoded: $ pahole -F btf -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o 2> /dev/null struct list_head { struct list_head * next; /* 0 8 */ struct list_head * prev; /* 8 8 */ /* size: 16, cachelines: 1, members: 2 */ /* last cacheline: 16 bytes */ }; $ There is the bitfields case that BTF desn't have the bit_size info for bitfield members that makes the output from dwarf to be different than the one from BTF: $ pahole -F btf -C sk_buff ~/git/build/v4.20-rc5+/net/ipv4/tcp.o > /tmp/sk_buff.btf $ pahole -F dwarf -C sk_buff ~/git/build/v4.20-rc5+/net/ipv4/tcp.o > /tmp/sk_buff.dwarf $ diff -u /tmp/sk_buff.dwarf /tmp/sk_buff.btf --- /tmp/sk_buff.dwarf 2018-12-20 14:50:51.428653046 -0300 +++ /tmp/sk_buff.btf 2018-12-20 14:50:46.302601516 -0300 @@ -38,45 +38,45 @@ __u16 hdr_len; /* 138 2 */ __u16 queue_mapping; /* 140 2 */ __u8 __cloned_offset[0]; /* 142 0 */ - __u8 cloned:1; /* 142: 7 1 */ - __u8 nohdr:1; /* 142: 6 1 */ - __u8 fclone:2; /* 142: 4 1 */ - __u8 peeked:1; /* 142: 3 1 */ - __u8 head_frag:1; /* 142: 2 1 */ - __u8 xmit_more:1; /* 142: 1 1 */ - __u8 pfmemalloc:1; /* 142: 0 1 */ + __u8 cloned; /* 142 1 */ + __u8 nohdr; /* 142 1 */ + __u8 fclone; /* 142 1 */ + __u8 peeked; /* 142 1 */ + __u8 head_frag; /* 142 1 */ + __u8 xmit_more; /* 142 1 */ + __u8 pfmemalloc; /* 142 1 */ /* XXX 1 byte hole, try to pack */ __u32 headers_start[0]; /* 144 0 */ __u8 __pkt_type_offset[0]; /* 144 0 */ - __u8 pkt_type:3; /* 144: 5 1 */ - __u8 ignore_df:1; /* 144: 4 1 */ - __u8 nf_trace:1; /* 144: 3 1 */ - __u8 ip_summed:2; /* 144: 1 1 */ - __u8 ooo_okay:1; /* 144: 0 1 */ - __u8 l4_hash:1; /* 145: 7 1 */ - __u8 sw_hash:1; /* 145: 6 1 */ - __u8 wifi_acked_valid:1; /* 145: 5 1 */ - __u8 wifi_acked:1; /* 145: 4 1 */ - __u8 no_fcs:1; /* 145: 3 1 */ - __u8 encapsulation:1; /* 145: 2 1 */ - __u8 encap_hdr_csum:1; /* 145: 1 1 */ - __u8 csum_valid:1; /* 145: 0 1 */ - __u8 csum_complete_sw:1; /* 146: 7 1 */ - __u8 csum_level:2; /* 146: 5 1 */ - __u8 csum_not_inet:1; /* 146: 4 1 */ - __u8 dst_pending_confirm:1; /* 146: 3 1 */ - __u8 ndisc_nodetype:2; /* 146: 1 1 */ - __u8 ipvs_property:1; /* 146: 0 1 */ - __u8 inner_protocol_type:1; /* 147: 7 1 */ - __u8 remcsum_offload:1; /* 147: 6 1 */ - __u8 offload_fwd_mark:1; /* 147: 5 1 */ - __u8 offload_mr_fwd_mark:1; /* 147: 4 1 */ - __u8 tc_skip_classify:1; /* 147: 3 1 */ - __u8 tc_at_ingress:1; /* 147: 2 1 */ - __u8 tc_redirected:1; /* 147: 1 1 */ - __u8 tc_from_ingress:1; /* 147: 0 1 */ + __u8 pkt_type; /* 144 1 */ + __u8 ignore_df; /* 144 1 */ + __u8 nf_trace; /* 144 1 */ + __u8 ip_summed; /* 144 1 */ + __u8 ooo_okay; /* 144 1 */ + __u8 l4_hash; /* 145 1 */ + __u8 sw_hash; /* 145 1 */ + __u8 wifi_acked_valid; /* 145 1 */ + __u8 wifi_acked; /* 145 1 */ + __u8 no_fcs; /* 145 1 */ + __u8 encapsulation; /* 145 1 */ + __u8 encap_hdr_csum; /* 145 1 */ + __u8 csum_valid; /* 145 1 */ + __u8 csum_complete_sw; /* 146 1 */ + __u8 csum_level; /* 146 1 */ + __u8 csum_not_inet; /* 146 1 */ + __u8 dst_pending_confirm; /* 146 1 */ + __u8 ndisc_nodetype; /* 146 1 */ + __u8 ipvs_property; /* 146 1 */ + __u8 inner_protocol_type; /* 147 1 */ + __u8 remcsum_offload; /* 147 1 */ + __u8 offload_fwd_mark; /* 147 1 */ + __u8 offload_mr_fwd_mark; /* 147 1 */ + __u8 tc_skip_classify; /* 147 1 */ + __u8 tc_at_ingress; /* 147 1 */ + __u8 tc_redirected; /* 147 1 */ + __u8 tc_from_ingress; /* 147 1 */ __u16 tc_index; /* 148 2 */ /* XXX 2 bytes hole, try to pack */ $ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-03 19:44:16 +01:00
err = 0;
}
out:
return err;
}
struct btf_elf *btf_elf__new(const char *filename, Elf *elf)
{
struct btf_elf *btfe = zalloc(sizeof(*btfe));
btf_encoder: Teach pahole to store percpu variables in vmlinux BTF. 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>
2020-07-08 22:44:10 +02:00
GElf_Shdr shdr;
Elf_Scn *sec;
if (!btfe)
return NULL;
btfe->in_fd = -1;
btfe->filename = strdup(filename);
if (btfe->filename == NULL)
goto errout;
btf loader: Support raw BTF as available in /sys/kernel/btf/vmlinux Be it automatically when no -F option is passed and /sys/kernel/btf/vmlinux is available, or when /sys/kernel/btf/vmlinux is passed as the filename to the tool, i.e.: $ pahole -C list_head struct list_head { struct list_head * next; /* 0 8 */ struct list_head * prev; /* 8 8 */ /* size: 16, cachelines: 1, members: 2 */ /* last cacheline: 16 bytes */ }; $ strace -e openat pahole -C list_head |& grep /sys/kernel/btf/ openat(AT_FDCWD, "/sys/kernel/btf/vmlinux", O_RDONLY) = 3 $ $ pahole -C list_head /sys/kernel/btf/vmlinux struct list_head { struct list_head * next; /* 0 8 */ struct list_head * prev; /* 8 8 */ /* size: 16, cachelines: 1, members: 2 */ /* last cacheline: 16 bytes */ }; $ If one wants to grab the matching vmlinux to use its DWARF info instead, which is useful to compare the results with what we have from BTF, for instance, its just a matter of using '-F dwarf'. This in turn shows something that at first came as a surprise, but then has a simple explanation: For very common data structures, that will probably appear in all of the DWARF CUs (Compilation Units), like 'struct list_head', using '-F dwarf' is faster: [acme@quaco pahole]$ perf stat -e cycles pahole -F btf -C list_head > /dev/null Performance counter stats for 'pahole -F btf -C list_head': 45,722,518 cycles:u 0.023717300 seconds time elapsed 0.016474000 seconds user 0.007212000 seconds sys [acme@quaco pahole]$ perf stat -e cycles pahole -F dwarf -C list_head > /dev/null Performance counter stats for 'pahole -F dwarf -C list_head': 14,170,321 cycles:u 0.006668904 seconds time elapsed 0.005562000 seconds user 0.001109000 seconds sys [acme@quaco pahole]$ But for something that is more specific to a subsystem, the DWARF loader will have to process way more stuff till it gets to that struct: $ perf stat -e cycles pahole -F dwarf -C tcp_sock > /dev/null Performance counter stats for 'pahole -F dwarf -C tcp_sock': 31,579,795,238 cycles:u 8.332272930 seconds time elapsed 8.032124000 seconds user 0.286537000 seconds sys $ While using the BTF loader the time should be constant, as it loads everything from /sys/kernel/btf/vmlinux: $ perf stat -e cycles pahole -F btf -C tcp_sock > /dev/null Performance counter stats for 'pahole -F btf -C tcp_sock': 48,823,488 cycles:u 0.024102760 seconds time elapsed 0.012035000 seconds user 0.012046000 seconds sys $ Above I used '-F btf' just to show that it can be used, but its not really needed, i.e. those are equivalent: $ strace -e openat pahole -F btf -C list_head |& grep /sys/kernel/btf/vmlinux openat(AT_FDCWD, "/sys/kernel/btf/vmlinux", O_RDONLY) = 3 $ strace -e openat pahole -C list_head |& grep /sys/kernel/btf/vmlinux openat(AT_FDCWD, "/sys/kernel/btf/vmlinux", O_RDONLY) = 3 $ The btf_raw__load() function that ends up being grafted into the preexisting btf_elf routines was based on libbpf's btf_load_raw(). Acked-by: Alexei Starovoitov <ast@fb.com> Cc: Andrii Nakryiko <andriin@fb.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-01-02 19:22:23 +01:00
if (strcmp(filename, "/sys/kernel/btf/vmlinux") == 0) {
btfe->raw_btf = true;
btfe->wordsize = sizeof(long);
btfe->is_big_endian = BYTE_ORDER == BIG_ENDIAN;
return btfe;
}
if (elf != NULL) {
btfe->elf = elf;
} else {
btfe->in_fd = open(filename, O_RDONLY);
if (btfe->in_fd < 0)
goto errout;
if (elf_version(EV_CURRENT) == EV_NONE) {
fprintf(stderr, "%s: cannot set libelf version.\n",
__func__);
goto errout;
}
btfe->elf = elf_begin(btfe->in_fd, ELF_C_READ_MMAP, NULL);
if (!btfe->elf) {
fprintf(stderr, "%s: cannot read %s ELF file.\n",
__func__, filename);
goto errout;
}
}
if (gelf_getehdr(btfe->elf, &btfe->ehdr) == NULL) {
fprintf(stderr, "%s: cannot get elf header.\n", __func__);
goto errout;
}
switch (btfe->ehdr.e_ident[EI_DATA]) {
case ELFDATA2LSB: btfe->is_big_endian = false; break;
case ELFDATA2MSB: btfe->is_big_endian = true; break;
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>
2018-09-13 18:19:40 +02:00
default:
fprintf(stderr, "%s: unknown elf endianness.\n", __func__);
goto errout;
}
switch (btfe->ehdr.e_ident[EI_CLASS]) {
case ELFCLASS32: btfe->wordsize = 4; break;
case ELFCLASS64: btfe->wordsize = 8; break;
default: btfe->wordsize = 0; break;
}
btf_encoder: Teach pahole to store percpu variables in vmlinux BTF. 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>
2020-07-08 22:44:10 +02:00
btfe->symtab = elf_symtab__new(NULL, btfe->elf, &btfe->ehdr);
if (!btfe->symtab) {
if (btf_elf__verbose)
printf("%s: '%s' doesn't have symtab.\n", __func__,
btfe->filename);
return btfe;
}
/* find percpu section's shndx */
sec = elf_section_by_name(btfe->elf, &btfe->ehdr, &shdr, PERCPU_SECTION,
NULL);
if (!sec) {
if (btf_elf__verbose)
printf("%s: '%s' doesn't have '%s' section\n", __func__,
btfe->filename, PERCPU_SECTION);
return btfe;
}
btfe->percpu_shndx = elf_ndxscn(sec);
btfe->percpu_base_addr = shdr.sh_addr;
return btfe;
errout:
btf_elf__delete(btfe);
return NULL;
}
void btf_elf__delete(struct btf_elf *btfe)
{
if (!btfe)
return;
if (btfe->in_fd != -1) {
close(btfe->in_fd);
if (btfe->elf)
elf_end(btfe->elf);
}
btf_encoder: Teach pahole to store percpu variables in vmlinux BTF. 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>
2020-07-08 22:44:10 +02:00
elf_symtab__delete(btfe->symtab);
__gobuffer__delete(&btfe->types);
btf_encoder: Teach pahole to store percpu variables in vmlinux BTF. 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>
2020-07-08 22:44:10 +02:00
__gobuffer__delete(&btfe->percpu_secinfo);
free(btfe->filename);
free(btfe->data);
free(btfe);
}
char *btf_elf__string(struct btf_elf *btfe, uint32_t ref)
btf_loader: Introduce a loader for the BTF format Show 'struct list_head' from DWARF info: $ pahole -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o struct list_head { struct list_head * next; /* 0 8 */ struct list_head * prev; /* 8 8 */ /* size: 16, cachelines: 1, members: 2 */ /* last cacheline: 16 bytes */ }; Try to show it from BTF, on a file without it: $ pahole -F btf -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o pahole: /home/acme/git/build/v4.20-rc5+/net/ipv4/tcp.o: No debugging information found Encode BTF from the DWARF info: $ pahole -J ~/git/build/v4.20-rc5+/net/ipv4/tcp.o Check that it is there: $ readelf -SW ~/git/build/v4.20-rc5+/net/ipv4/tcp.o | grep BTF readelf: /home/acme/git/build/v4.20-rc5+/net/ipv4/tcp.o: Warning: possibly corrupt ELF header - it has a non-zero program header offset, but no program headers [136] .BTF PROGBITS 0000000000000000 101d0e 042edf 00 0 0 1 Now try again printing 'struct list_head' from the BTF info just encoded: $ pahole -F btf -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o 2> /dev/null struct list_head { struct list_head * next; /* 0 8 */ struct list_head * prev; /* 8 8 */ /* size: 16, cachelines: 1, members: 2 */ /* last cacheline: 16 bytes */ }; $ There is the bitfields case that BTF desn't have the bit_size info for bitfield members that makes the output from dwarf to be different than the one from BTF: $ pahole -F btf -C sk_buff ~/git/build/v4.20-rc5+/net/ipv4/tcp.o > /tmp/sk_buff.btf $ pahole -F dwarf -C sk_buff ~/git/build/v4.20-rc5+/net/ipv4/tcp.o > /tmp/sk_buff.dwarf $ diff -u /tmp/sk_buff.dwarf /tmp/sk_buff.btf --- /tmp/sk_buff.dwarf 2018-12-20 14:50:51.428653046 -0300 +++ /tmp/sk_buff.btf 2018-12-20 14:50:46.302601516 -0300 @@ -38,45 +38,45 @@ __u16 hdr_len; /* 138 2 */ __u16 queue_mapping; /* 140 2 */ __u8 __cloned_offset[0]; /* 142 0 */ - __u8 cloned:1; /* 142: 7 1 */ - __u8 nohdr:1; /* 142: 6 1 */ - __u8 fclone:2; /* 142: 4 1 */ - __u8 peeked:1; /* 142: 3 1 */ - __u8 head_frag:1; /* 142: 2 1 */ - __u8 xmit_more:1; /* 142: 1 1 */ - __u8 pfmemalloc:1; /* 142: 0 1 */ + __u8 cloned; /* 142 1 */ + __u8 nohdr; /* 142 1 */ + __u8 fclone; /* 142 1 */ + __u8 peeked; /* 142 1 */ + __u8 head_frag; /* 142 1 */ + __u8 xmit_more; /* 142 1 */ + __u8 pfmemalloc; /* 142 1 */ /* XXX 1 byte hole, try to pack */ __u32 headers_start[0]; /* 144 0 */ __u8 __pkt_type_offset[0]; /* 144 0 */ - __u8 pkt_type:3; /* 144: 5 1 */ - __u8 ignore_df:1; /* 144: 4 1 */ - __u8 nf_trace:1; /* 144: 3 1 */ - __u8 ip_summed:2; /* 144: 1 1 */ - __u8 ooo_okay:1; /* 144: 0 1 */ - __u8 l4_hash:1; /* 145: 7 1 */ - __u8 sw_hash:1; /* 145: 6 1 */ - __u8 wifi_acked_valid:1; /* 145: 5 1 */ - __u8 wifi_acked:1; /* 145: 4 1 */ - __u8 no_fcs:1; /* 145: 3 1 */ - __u8 encapsulation:1; /* 145: 2 1 */ - __u8 encap_hdr_csum:1; /* 145: 1 1 */ - __u8 csum_valid:1; /* 145: 0 1 */ - __u8 csum_complete_sw:1; /* 146: 7 1 */ - __u8 csum_level:2; /* 146: 5 1 */ - __u8 csum_not_inet:1; /* 146: 4 1 */ - __u8 dst_pending_confirm:1; /* 146: 3 1 */ - __u8 ndisc_nodetype:2; /* 146: 1 1 */ - __u8 ipvs_property:1; /* 146: 0 1 */ - __u8 inner_protocol_type:1; /* 147: 7 1 */ - __u8 remcsum_offload:1; /* 147: 6 1 */ - __u8 offload_fwd_mark:1; /* 147: 5 1 */ - __u8 offload_mr_fwd_mark:1; /* 147: 4 1 */ - __u8 tc_skip_classify:1; /* 147: 3 1 */ - __u8 tc_at_ingress:1; /* 147: 2 1 */ - __u8 tc_redirected:1; /* 147: 1 1 */ - __u8 tc_from_ingress:1; /* 147: 0 1 */ + __u8 pkt_type; /* 144 1 */ + __u8 ignore_df; /* 144 1 */ + __u8 nf_trace; /* 144 1 */ + __u8 ip_summed; /* 144 1 */ + __u8 ooo_okay; /* 144 1 */ + __u8 l4_hash; /* 145 1 */ + __u8 sw_hash; /* 145 1 */ + __u8 wifi_acked_valid; /* 145 1 */ + __u8 wifi_acked; /* 145 1 */ + __u8 no_fcs; /* 145 1 */ + __u8 encapsulation; /* 145 1 */ + __u8 encap_hdr_csum; /* 145 1 */ + __u8 csum_valid; /* 145 1 */ + __u8 csum_complete_sw; /* 146 1 */ + __u8 csum_level; /* 146 1 */ + __u8 csum_not_inet; /* 146 1 */ + __u8 dst_pending_confirm; /* 146 1 */ + __u8 ndisc_nodetype; /* 146 1 */ + __u8 ipvs_property; /* 146 1 */ + __u8 inner_protocol_type; /* 147 1 */ + __u8 remcsum_offload; /* 147 1 */ + __u8 offload_fwd_mark; /* 147 1 */ + __u8 offload_mr_fwd_mark; /* 147 1 */ + __u8 tc_skip_classify; /* 147 1 */ + __u8 tc_at_ingress; /* 147 1 */ + __u8 tc_redirected; /* 147 1 */ + __u8 tc_from_ingress; /* 147 1 */ __u16 tc_index; /* 148 2 */ /* XXX 2 bytes hole, try to pack */ $ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-03 19:44:16 +01:00
{
struct btf_header *hp = btfe->hdr;
btf_loader: Introduce a loader for the BTF format Show 'struct list_head' from DWARF info: $ pahole -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o struct list_head { struct list_head * next; /* 0 8 */ struct list_head * prev; /* 8 8 */ /* size: 16, cachelines: 1, members: 2 */ /* last cacheline: 16 bytes */ }; Try to show it from BTF, on a file without it: $ pahole -F btf -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o pahole: /home/acme/git/build/v4.20-rc5+/net/ipv4/tcp.o: No debugging information found Encode BTF from the DWARF info: $ pahole -J ~/git/build/v4.20-rc5+/net/ipv4/tcp.o Check that it is there: $ readelf -SW ~/git/build/v4.20-rc5+/net/ipv4/tcp.o | grep BTF readelf: /home/acme/git/build/v4.20-rc5+/net/ipv4/tcp.o: Warning: possibly corrupt ELF header - it has a non-zero program header offset, but no program headers [136] .BTF PROGBITS 0000000000000000 101d0e 042edf 00 0 0 1 Now try again printing 'struct list_head' from the BTF info just encoded: $ pahole -F btf -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o 2> /dev/null struct list_head { struct list_head * next; /* 0 8 */ struct list_head * prev; /* 8 8 */ /* size: 16, cachelines: 1, members: 2 */ /* last cacheline: 16 bytes */ }; $ There is the bitfields case that BTF desn't have the bit_size info for bitfield members that makes the output from dwarf to be different than the one from BTF: $ pahole -F btf -C sk_buff ~/git/build/v4.20-rc5+/net/ipv4/tcp.o > /tmp/sk_buff.btf $ pahole -F dwarf -C sk_buff ~/git/build/v4.20-rc5+/net/ipv4/tcp.o > /tmp/sk_buff.dwarf $ diff -u /tmp/sk_buff.dwarf /tmp/sk_buff.btf --- /tmp/sk_buff.dwarf 2018-12-20 14:50:51.428653046 -0300 +++ /tmp/sk_buff.btf 2018-12-20 14:50:46.302601516 -0300 @@ -38,45 +38,45 @@ __u16 hdr_len; /* 138 2 */ __u16 queue_mapping; /* 140 2 */ __u8 __cloned_offset[0]; /* 142 0 */ - __u8 cloned:1; /* 142: 7 1 */ - __u8 nohdr:1; /* 142: 6 1 */ - __u8 fclone:2; /* 142: 4 1 */ - __u8 peeked:1; /* 142: 3 1 */ - __u8 head_frag:1; /* 142: 2 1 */ - __u8 xmit_more:1; /* 142: 1 1 */ - __u8 pfmemalloc:1; /* 142: 0 1 */ + __u8 cloned; /* 142 1 */ + __u8 nohdr; /* 142 1 */ + __u8 fclone; /* 142 1 */ + __u8 peeked; /* 142 1 */ + __u8 head_frag; /* 142 1 */ + __u8 xmit_more; /* 142 1 */ + __u8 pfmemalloc; /* 142 1 */ /* XXX 1 byte hole, try to pack */ __u32 headers_start[0]; /* 144 0 */ __u8 __pkt_type_offset[0]; /* 144 0 */ - __u8 pkt_type:3; /* 144: 5 1 */ - __u8 ignore_df:1; /* 144: 4 1 */ - __u8 nf_trace:1; /* 144: 3 1 */ - __u8 ip_summed:2; /* 144: 1 1 */ - __u8 ooo_okay:1; /* 144: 0 1 */ - __u8 l4_hash:1; /* 145: 7 1 */ - __u8 sw_hash:1; /* 145: 6 1 */ - __u8 wifi_acked_valid:1; /* 145: 5 1 */ - __u8 wifi_acked:1; /* 145: 4 1 */ - __u8 no_fcs:1; /* 145: 3 1 */ - __u8 encapsulation:1; /* 145: 2 1 */ - __u8 encap_hdr_csum:1; /* 145: 1 1 */ - __u8 csum_valid:1; /* 145: 0 1 */ - __u8 csum_complete_sw:1; /* 146: 7 1 */ - __u8 csum_level:2; /* 146: 5 1 */ - __u8 csum_not_inet:1; /* 146: 4 1 */ - __u8 dst_pending_confirm:1; /* 146: 3 1 */ - __u8 ndisc_nodetype:2; /* 146: 1 1 */ - __u8 ipvs_property:1; /* 146: 0 1 */ - __u8 inner_protocol_type:1; /* 147: 7 1 */ - __u8 remcsum_offload:1; /* 147: 6 1 */ - __u8 offload_fwd_mark:1; /* 147: 5 1 */ - __u8 offload_mr_fwd_mark:1; /* 147: 4 1 */ - __u8 tc_skip_classify:1; /* 147: 3 1 */ - __u8 tc_at_ingress:1; /* 147: 2 1 */ - __u8 tc_redirected:1; /* 147: 1 1 */ - __u8 tc_from_ingress:1; /* 147: 0 1 */ + __u8 pkt_type; /* 144 1 */ + __u8 ignore_df; /* 144 1 */ + __u8 nf_trace; /* 144 1 */ + __u8 ip_summed; /* 144 1 */ + __u8 ooo_okay; /* 144 1 */ + __u8 l4_hash; /* 145 1 */ + __u8 sw_hash; /* 145 1 */ + __u8 wifi_acked_valid; /* 145 1 */ + __u8 wifi_acked; /* 145 1 */ + __u8 no_fcs; /* 145 1 */ + __u8 encapsulation; /* 145 1 */ + __u8 encap_hdr_csum; /* 145 1 */ + __u8 csum_valid; /* 145 1 */ + __u8 csum_complete_sw; /* 146 1 */ + __u8 csum_level; /* 146 1 */ + __u8 csum_not_inet; /* 146 1 */ + __u8 dst_pending_confirm; /* 146 1 */ + __u8 ndisc_nodetype; /* 146 1 */ + __u8 ipvs_property; /* 146 1 */ + __u8 inner_protocol_type; /* 147 1 */ + __u8 remcsum_offload; /* 147 1 */ + __u8 offload_fwd_mark; /* 147 1 */ + __u8 offload_mr_fwd_mark; /* 147 1 */ + __u8 tc_skip_classify; /* 147 1 */ + __u8 tc_at_ingress; /* 147 1 */ + __u8 tc_redirected; /* 147 1 */ + __u8 tc_from_ingress; /* 147 1 */ __u16 tc_index; /* 148 2 */ /* XXX 2 bytes hole, try to pack */ $ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-03 19:44:16 +01:00
uint32_t off = ref;
char *name;
if (off >= btf_elf__get32(btfe, &hp->str_len))
btf_loader: Introduce a loader for the BTF format Show 'struct list_head' from DWARF info: $ pahole -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o struct list_head { struct list_head * next; /* 0 8 */ struct list_head * prev; /* 8 8 */ /* size: 16, cachelines: 1, members: 2 */ /* last cacheline: 16 bytes */ }; Try to show it from BTF, on a file without it: $ pahole -F btf -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o pahole: /home/acme/git/build/v4.20-rc5+/net/ipv4/tcp.o: No debugging information found Encode BTF from the DWARF info: $ pahole -J ~/git/build/v4.20-rc5+/net/ipv4/tcp.o Check that it is there: $ readelf -SW ~/git/build/v4.20-rc5+/net/ipv4/tcp.o | grep BTF readelf: /home/acme/git/build/v4.20-rc5+/net/ipv4/tcp.o: Warning: possibly corrupt ELF header - it has a non-zero program header offset, but no program headers [136] .BTF PROGBITS 0000000000000000 101d0e 042edf 00 0 0 1 Now try again printing 'struct list_head' from the BTF info just encoded: $ pahole -F btf -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o 2> /dev/null struct list_head { struct list_head * next; /* 0 8 */ struct list_head * prev; /* 8 8 */ /* size: 16, cachelines: 1, members: 2 */ /* last cacheline: 16 bytes */ }; $ There is the bitfields case that BTF desn't have the bit_size info for bitfield members that makes the output from dwarf to be different than the one from BTF: $ pahole -F btf -C sk_buff ~/git/build/v4.20-rc5+/net/ipv4/tcp.o > /tmp/sk_buff.btf $ pahole -F dwarf -C sk_buff ~/git/build/v4.20-rc5+/net/ipv4/tcp.o > /tmp/sk_buff.dwarf $ diff -u /tmp/sk_buff.dwarf /tmp/sk_buff.btf --- /tmp/sk_buff.dwarf 2018-12-20 14:50:51.428653046 -0300 +++ /tmp/sk_buff.btf 2018-12-20 14:50:46.302601516 -0300 @@ -38,45 +38,45 @@ __u16 hdr_len; /* 138 2 */ __u16 queue_mapping; /* 140 2 */ __u8 __cloned_offset[0]; /* 142 0 */ - __u8 cloned:1; /* 142: 7 1 */ - __u8 nohdr:1; /* 142: 6 1 */ - __u8 fclone:2; /* 142: 4 1 */ - __u8 peeked:1; /* 142: 3 1 */ - __u8 head_frag:1; /* 142: 2 1 */ - __u8 xmit_more:1; /* 142: 1 1 */ - __u8 pfmemalloc:1; /* 142: 0 1 */ + __u8 cloned; /* 142 1 */ + __u8 nohdr; /* 142 1 */ + __u8 fclone; /* 142 1 */ + __u8 peeked; /* 142 1 */ + __u8 head_frag; /* 142 1 */ + __u8 xmit_more; /* 142 1 */ + __u8 pfmemalloc; /* 142 1 */ /* XXX 1 byte hole, try to pack */ __u32 headers_start[0]; /* 144 0 */ __u8 __pkt_type_offset[0]; /* 144 0 */ - __u8 pkt_type:3; /* 144: 5 1 */ - __u8 ignore_df:1; /* 144: 4 1 */ - __u8 nf_trace:1; /* 144: 3 1 */ - __u8 ip_summed:2; /* 144: 1 1 */ - __u8 ooo_okay:1; /* 144: 0 1 */ - __u8 l4_hash:1; /* 145: 7 1 */ - __u8 sw_hash:1; /* 145: 6 1 */ - __u8 wifi_acked_valid:1; /* 145: 5 1 */ - __u8 wifi_acked:1; /* 145: 4 1 */ - __u8 no_fcs:1; /* 145: 3 1 */ - __u8 encapsulation:1; /* 145: 2 1 */ - __u8 encap_hdr_csum:1; /* 145: 1 1 */ - __u8 csum_valid:1; /* 145: 0 1 */ - __u8 csum_complete_sw:1; /* 146: 7 1 */ - __u8 csum_level:2; /* 146: 5 1 */ - __u8 csum_not_inet:1; /* 146: 4 1 */ - __u8 dst_pending_confirm:1; /* 146: 3 1 */ - __u8 ndisc_nodetype:2; /* 146: 1 1 */ - __u8 ipvs_property:1; /* 146: 0 1 */ - __u8 inner_protocol_type:1; /* 147: 7 1 */ - __u8 remcsum_offload:1; /* 147: 6 1 */ - __u8 offload_fwd_mark:1; /* 147: 5 1 */ - __u8 offload_mr_fwd_mark:1; /* 147: 4 1 */ - __u8 tc_skip_classify:1; /* 147: 3 1 */ - __u8 tc_at_ingress:1; /* 147: 2 1 */ - __u8 tc_redirected:1; /* 147: 1 1 */ - __u8 tc_from_ingress:1; /* 147: 0 1 */ + __u8 pkt_type; /* 144 1 */ + __u8 ignore_df; /* 144 1 */ + __u8 nf_trace; /* 144 1 */ + __u8 ip_summed; /* 144 1 */ + __u8 ooo_okay; /* 144 1 */ + __u8 l4_hash; /* 145 1 */ + __u8 sw_hash; /* 145 1 */ + __u8 wifi_acked_valid; /* 145 1 */ + __u8 wifi_acked; /* 145 1 */ + __u8 no_fcs; /* 145 1 */ + __u8 encapsulation; /* 145 1 */ + __u8 encap_hdr_csum; /* 145 1 */ + __u8 csum_valid; /* 145 1 */ + __u8 csum_complete_sw; /* 146 1 */ + __u8 csum_level; /* 146 1 */ + __u8 csum_not_inet; /* 146 1 */ + __u8 dst_pending_confirm; /* 146 1 */ + __u8 ndisc_nodetype; /* 146 1 */ + __u8 ipvs_property; /* 146 1 */ + __u8 inner_protocol_type; /* 147 1 */ + __u8 remcsum_offload; /* 147 1 */ + __u8 offload_fwd_mark; /* 147 1 */ + __u8 offload_mr_fwd_mark; /* 147 1 */ + __u8 tc_skip_classify; /* 147 1 */ + __u8 tc_at_ingress; /* 147 1 */ + __u8 tc_redirected; /* 147 1 */ + __u8 tc_from_ingress; /* 147 1 */ __u16 tc_index; /* 148 2 */ /* XXX 2 bytes hole, try to pack */ $ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-03 19:44:16 +01:00
return "(ref out-of-bounds)";
if ((off + btf_elf__get32(btfe, &hp->str_off)) >= btfe->size)
btf_loader: Introduce a loader for the BTF format Show 'struct list_head' from DWARF info: $ pahole -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o struct list_head { struct list_head * next; /* 0 8 */ struct list_head * prev; /* 8 8 */ /* size: 16, cachelines: 1, members: 2 */ /* last cacheline: 16 bytes */ }; Try to show it from BTF, on a file without it: $ pahole -F btf -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o pahole: /home/acme/git/build/v4.20-rc5+/net/ipv4/tcp.o: No debugging information found Encode BTF from the DWARF info: $ pahole -J ~/git/build/v4.20-rc5+/net/ipv4/tcp.o Check that it is there: $ readelf -SW ~/git/build/v4.20-rc5+/net/ipv4/tcp.o | grep BTF readelf: /home/acme/git/build/v4.20-rc5+/net/ipv4/tcp.o: Warning: possibly corrupt ELF header - it has a non-zero program header offset, but no program headers [136] .BTF PROGBITS 0000000000000000 101d0e 042edf 00 0 0 1 Now try again printing 'struct list_head' from the BTF info just encoded: $ pahole -F btf -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o 2> /dev/null struct list_head { struct list_head * next; /* 0 8 */ struct list_head * prev; /* 8 8 */ /* size: 16, cachelines: 1, members: 2 */ /* last cacheline: 16 bytes */ }; $ There is the bitfields case that BTF desn't have the bit_size info for bitfield members that makes the output from dwarf to be different than the one from BTF: $ pahole -F btf -C sk_buff ~/git/build/v4.20-rc5+/net/ipv4/tcp.o > /tmp/sk_buff.btf $ pahole -F dwarf -C sk_buff ~/git/build/v4.20-rc5+/net/ipv4/tcp.o > /tmp/sk_buff.dwarf $ diff -u /tmp/sk_buff.dwarf /tmp/sk_buff.btf --- /tmp/sk_buff.dwarf 2018-12-20 14:50:51.428653046 -0300 +++ /tmp/sk_buff.btf 2018-12-20 14:50:46.302601516 -0300 @@ -38,45 +38,45 @@ __u16 hdr_len; /* 138 2 */ __u16 queue_mapping; /* 140 2 */ __u8 __cloned_offset[0]; /* 142 0 */ - __u8 cloned:1; /* 142: 7 1 */ - __u8 nohdr:1; /* 142: 6 1 */ - __u8 fclone:2; /* 142: 4 1 */ - __u8 peeked:1; /* 142: 3 1 */ - __u8 head_frag:1; /* 142: 2 1 */ - __u8 xmit_more:1; /* 142: 1 1 */ - __u8 pfmemalloc:1; /* 142: 0 1 */ + __u8 cloned; /* 142 1 */ + __u8 nohdr; /* 142 1 */ + __u8 fclone; /* 142 1 */ + __u8 peeked; /* 142 1 */ + __u8 head_frag; /* 142 1 */ + __u8 xmit_more; /* 142 1 */ + __u8 pfmemalloc; /* 142 1 */ /* XXX 1 byte hole, try to pack */ __u32 headers_start[0]; /* 144 0 */ __u8 __pkt_type_offset[0]; /* 144 0 */ - __u8 pkt_type:3; /* 144: 5 1 */ - __u8 ignore_df:1; /* 144: 4 1 */ - __u8 nf_trace:1; /* 144: 3 1 */ - __u8 ip_summed:2; /* 144: 1 1 */ - __u8 ooo_okay:1; /* 144: 0 1 */ - __u8 l4_hash:1; /* 145: 7 1 */ - __u8 sw_hash:1; /* 145: 6 1 */ - __u8 wifi_acked_valid:1; /* 145: 5 1 */ - __u8 wifi_acked:1; /* 145: 4 1 */ - __u8 no_fcs:1; /* 145: 3 1 */ - __u8 encapsulation:1; /* 145: 2 1 */ - __u8 encap_hdr_csum:1; /* 145: 1 1 */ - __u8 csum_valid:1; /* 145: 0 1 */ - __u8 csum_complete_sw:1; /* 146: 7 1 */ - __u8 csum_level:2; /* 146: 5 1 */ - __u8 csum_not_inet:1; /* 146: 4 1 */ - __u8 dst_pending_confirm:1; /* 146: 3 1 */ - __u8 ndisc_nodetype:2; /* 146: 1 1 */ - __u8 ipvs_property:1; /* 146: 0 1 */ - __u8 inner_protocol_type:1; /* 147: 7 1 */ - __u8 remcsum_offload:1; /* 147: 6 1 */ - __u8 offload_fwd_mark:1; /* 147: 5 1 */ - __u8 offload_mr_fwd_mark:1; /* 147: 4 1 */ - __u8 tc_skip_classify:1; /* 147: 3 1 */ - __u8 tc_at_ingress:1; /* 147: 2 1 */ - __u8 tc_redirected:1; /* 147: 1 1 */ - __u8 tc_from_ingress:1; /* 147: 0 1 */ + __u8 pkt_type; /* 144 1 */ + __u8 ignore_df; /* 144 1 */ + __u8 nf_trace; /* 144 1 */ + __u8 ip_summed; /* 144 1 */ + __u8 ooo_okay; /* 144 1 */ + __u8 l4_hash; /* 145 1 */ + __u8 sw_hash; /* 145 1 */ + __u8 wifi_acked_valid; /* 145 1 */ + __u8 wifi_acked; /* 145 1 */ + __u8 no_fcs; /* 145 1 */ + __u8 encapsulation; /* 145 1 */ + __u8 encap_hdr_csum; /* 145 1 */ + __u8 csum_valid; /* 145 1 */ + __u8 csum_complete_sw; /* 146 1 */ + __u8 csum_level; /* 146 1 */ + __u8 csum_not_inet; /* 146 1 */ + __u8 dst_pending_confirm; /* 146 1 */ + __u8 ndisc_nodetype; /* 146 1 */ + __u8 ipvs_property; /* 146 1 */ + __u8 inner_protocol_type; /* 147 1 */ + __u8 remcsum_offload; /* 147 1 */ + __u8 offload_fwd_mark; /* 147 1 */ + __u8 offload_mr_fwd_mark; /* 147 1 */ + __u8 tc_skip_classify; /* 147 1 */ + __u8 tc_at_ingress; /* 147 1 */ + __u8 tc_redirected; /* 147 1 */ + __u8 tc_from_ingress; /* 147 1 */ __u16 tc_index; /* 148 2 */ /* XXX 2 bytes hole, try to pack */ $ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-03 19:44:16 +01:00
return "(string table truncated)";
name = ((char *)(hp + 1) + btf_elf__get32(btfe, &hp->str_off) + off);
btf_loader: Introduce a loader for the BTF format Show 'struct list_head' from DWARF info: $ pahole -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o struct list_head { struct list_head * next; /* 0 8 */ struct list_head * prev; /* 8 8 */ /* size: 16, cachelines: 1, members: 2 */ /* last cacheline: 16 bytes */ }; Try to show it from BTF, on a file without it: $ pahole -F btf -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o pahole: /home/acme/git/build/v4.20-rc5+/net/ipv4/tcp.o: No debugging information found Encode BTF from the DWARF info: $ pahole -J ~/git/build/v4.20-rc5+/net/ipv4/tcp.o Check that it is there: $ readelf -SW ~/git/build/v4.20-rc5+/net/ipv4/tcp.o | grep BTF readelf: /home/acme/git/build/v4.20-rc5+/net/ipv4/tcp.o: Warning: possibly corrupt ELF header - it has a non-zero program header offset, but no program headers [136] .BTF PROGBITS 0000000000000000 101d0e 042edf 00 0 0 1 Now try again printing 'struct list_head' from the BTF info just encoded: $ pahole -F btf -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o 2> /dev/null struct list_head { struct list_head * next; /* 0 8 */ struct list_head * prev; /* 8 8 */ /* size: 16, cachelines: 1, members: 2 */ /* last cacheline: 16 bytes */ }; $ There is the bitfields case that BTF desn't have the bit_size info for bitfield members that makes the output from dwarf to be different than the one from BTF: $ pahole -F btf -C sk_buff ~/git/build/v4.20-rc5+/net/ipv4/tcp.o > /tmp/sk_buff.btf $ pahole -F dwarf -C sk_buff ~/git/build/v4.20-rc5+/net/ipv4/tcp.o > /tmp/sk_buff.dwarf $ diff -u /tmp/sk_buff.dwarf /tmp/sk_buff.btf --- /tmp/sk_buff.dwarf 2018-12-20 14:50:51.428653046 -0300 +++ /tmp/sk_buff.btf 2018-12-20 14:50:46.302601516 -0300 @@ -38,45 +38,45 @@ __u16 hdr_len; /* 138 2 */ __u16 queue_mapping; /* 140 2 */ __u8 __cloned_offset[0]; /* 142 0 */ - __u8 cloned:1; /* 142: 7 1 */ - __u8 nohdr:1; /* 142: 6 1 */ - __u8 fclone:2; /* 142: 4 1 */ - __u8 peeked:1; /* 142: 3 1 */ - __u8 head_frag:1; /* 142: 2 1 */ - __u8 xmit_more:1; /* 142: 1 1 */ - __u8 pfmemalloc:1; /* 142: 0 1 */ + __u8 cloned; /* 142 1 */ + __u8 nohdr; /* 142 1 */ + __u8 fclone; /* 142 1 */ + __u8 peeked; /* 142 1 */ + __u8 head_frag; /* 142 1 */ + __u8 xmit_more; /* 142 1 */ + __u8 pfmemalloc; /* 142 1 */ /* XXX 1 byte hole, try to pack */ __u32 headers_start[0]; /* 144 0 */ __u8 __pkt_type_offset[0]; /* 144 0 */ - __u8 pkt_type:3; /* 144: 5 1 */ - __u8 ignore_df:1; /* 144: 4 1 */ - __u8 nf_trace:1; /* 144: 3 1 */ - __u8 ip_summed:2; /* 144: 1 1 */ - __u8 ooo_okay:1; /* 144: 0 1 */ - __u8 l4_hash:1; /* 145: 7 1 */ - __u8 sw_hash:1; /* 145: 6 1 */ - __u8 wifi_acked_valid:1; /* 145: 5 1 */ - __u8 wifi_acked:1; /* 145: 4 1 */ - __u8 no_fcs:1; /* 145: 3 1 */ - __u8 encapsulation:1; /* 145: 2 1 */ - __u8 encap_hdr_csum:1; /* 145: 1 1 */ - __u8 csum_valid:1; /* 145: 0 1 */ - __u8 csum_complete_sw:1; /* 146: 7 1 */ - __u8 csum_level:2; /* 146: 5 1 */ - __u8 csum_not_inet:1; /* 146: 4 1 */ - __u8 dst_pending_confirm:1; /* 146: 3 1 */ - __u8 ndisc_nodetype:2; /* 146: 1 1 */ - __u8 ipvs_property:1; /* 146: 0 1 */ - __u8 inner_protocol_type:1; /* 147: 7 1 */ - __u8 remcsum_offload:1; /* 147: 6 1 */ - __u8 offload_fwd_mark:1; /* 147: 5 1 */ - __u8 offload_mr_fwd_mark:1; /* 147: 4 1 */ - __u8 tc_skip_classify:1; /* 147: 3 1 */ - __u8 tc_at_ingress:1; /* 147: 2 1 */ - __u8 tc_redirected:1; /* 147: 1 1 */ - __u8 tc_from_ingress:1; /* 147: 0 1 */ + __u8 pkt_type; /* 144 1 */ + __u8 ignore_df; /* 144 1 */ + __u8 nf_trace; /* 144 1 */ + __u8 ip_summed; /* 144 1 */ + __u8 ooo_okay; /* 144 1 */ + __u8 l4_hash; /* 145 1 */ + __u8 sw_hash; /* 145 1 */ + __u8 wifi_acked_valid; /* 145 1 */ + __u8 wifi_acked; /* 145 1 */ + __u8 no_fcs; /* 145 1 */ + __u8 encapsulation; /* 145 1 */ + __u8 encap_hdr_csum; /* 145 1 */ + __u8 csum_valid; /* 145 1 */ + __u8 csum_complete_sw; /* 146 1 */ + __u8 csum_level; /* 146 1 */ + __u8 csum_not_inet; /* 146 1 */ + __u8 dst_pending_confirm; /* 146 1 */ + __u8 ndisc_nodetype; /* 146 1 */ + __u8 ipvs_property; /* 146 1 */ + __u8 inner_protocol_type; /* 147 1 */ + __u8 remcsum_offload; /* 147 1 */ + __u8 offload_fwd_mark; /* 147 1 */ + __u8 offload_mr_fwd_mark; /* 147 1 */ + __u8 tc_skip_classify; /* 147 1 */ + __u8 tc_at_ingress; /* 147 1 */ + __u8 tc_redirected; /* 147 1 */ + __u8 tc_from_ingress; /* 147 1 */ __u16 tc_index; /* 148 2 */ /* XXX 2 bytes hole, try to pack */ $ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-03 19:44:16 +01:00
return name[0] == '\0' ? NULL : name;
}
static void *btf_elf__nohdr_data(struct btf_elf *btfe)
{
return btfe->hdr + 1;
}
void btf_elf__set_strings(struct btf_elf *btfe, struct gobuffer *strings)
{
btfe->strings = strings;
}
#define BITS_PER_BYTE 8
#define BITS_PER_BYTE_MASK (BITS_PER_BYTE - 1)
#define BITS_PER_BYTE_MASKED(bits) ((bits) & BITS_PER_BYTE_MASK)
#define BITS_ROUNDDOWN_BYTES(bits) ((bits) >> 3)
#define BITS_ROUNDUP_BYTES(bits) (BITS_ROUNDDOWN_BYTES(bits) + !!BITS_PER_BYTE_MASKED(bits))
static const char * const btf_kind_str[NR_BTF_KINDS] = {
[BTF_KIND_UNKN] = "UNKNOWN",
[BTF_KIND_INT] = "INT",
[BTF_KIND_PTR] = "PTR",
[BTF_KIND_ARRAY] = "ARRAY",
[BTF_KIND_STRUCT] = "STRUCT",
[BTF_KIND_UNION] = "UNION",
[BTF_KIND_ENUM] = "ENUM",
[BTF_KIND_FWD] = "FWD",
[BTF_KIND_TYPEDEF] = "TYPEDEF",
[BTF_KIND_VOLATILE] = "VOLATILE",
[BTF_KIND_CONST] = "CONST",
[BTF_KIND_RESTRICT] = "RESTRICT",
btf: add func_proto support 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>
2018-12-18 23:09:42 +01:00
[BTF_KIND_FUNC] = "FUNC",
[BTF_KIND_FUNC_PROTO] = "FUNC_PROTO",
};
static const char *btf_elf__name_in_gobuf(const struct btf_elf *btfe, uint32_t offset)
{
if (!offset)
return "(anon)";
else
return &btfe->strings->entries[offset];
}
static const char * btf_elf__int_encoding_str(uint8_t encoding)
{
if (encoding == 0)
return "(none)";
else if (encoding == BTF_INT_SIGNED)
return "SIGNED";
else if (encoding == BTF_INT_CHAR)
return "CHAR";
else if (encoding == BTF_INT_BOOL)
return "BOOL";
else
return "UNKN";
}
btf: add func_proto support 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>
2018-12-18 23:09:42 +01:00
__attribute ((format (printf, 5, 6)))
static void btf_elf__log_type(const struct btf_elf *btfe, const struct btf_type *t,
bool err, bool output_cr, const char *fmt, ...)
{
uint8_t kind;
FILE *out;
if (!btf_elf__verbose && !err)
return;
kind = BTF_INFO_KIND(t->info);
out = err ? stderr : stdout;
fprintf(out, "[%u] %s %s",
btfe->type_index, btf_kind_str[kind],
btf_elf__name_in_gobuf(btfe, t->name_off));
if (fmt && *fmt) {
va_list ap;
fprintf(out, " ");
va_start(ap, fmt);
vfprintf(out, fmt, ap);
va_end(ap);
}
btf: add func_proto support 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>
2018-12-18 23:09:42 +01:00
if (output_cr)
fprintf(out, "\n");
}
btf: fix struct/union/fwd types with kind_flag 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 b18354f64cc2 ("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>
2018-12-18 23:09:41 +01:00
__attribute ((format (printf, 5, 6)))
static void btf_log_member(const struct btf_elf *btfe,
const struct btf_member *member,
btf: fix struct/union/fwd types with kind_flag 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 b18354f64cc2 ("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>
2018-12-18 23:09:41 +01:00
bool kind_flag, bool err, const char *fmt, ...)
{
FILE *out;
if (!btf_elf__verbose && !err)
return;
out = err ? stderr : stdout;
btf: fix struct/union/fwd types with kind_flag 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 b18354f64cc2 ("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>
2018-12-18 23:09:41 +01:00
if (kind_flag)
fprintf(out, "\t%s type_id=%u bitfield_size=%u bits_offset=%u",
btf_elf__name_in_gobuf(btfe, member->name_off),
btf: fix struct/union/fwd types with kind_flag 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 b18354f64cc2 ("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>
2018-12-18 23:09:41 +01:00
member->type,
BTF_MEMBER_BITFIELD_SIZE(member->offset),
BTF_MEMBER_BIT_OFFSET(member->offset));
else
fprintf(out, "\t%s type_id=%u bits_offset=%u",
btf_elf__name_in_gobuf(btfe, member->name_off),
btf: fix struct/union/fwd types with kind_flag 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 b18354f64cc2 ("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>
2018-12-18 23:09:41 +01:00
member->type,
member->offset);
if (fmt && *fmt) {
va_list ap;
fprintf(out, " ");
va_start(ap, fmt);
vfprintf(out, fmt, ap);
va_end(ap);
}
fprintf(out, "\n");
}
btf: add func_proto support 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>
2018-12-18 23:09:42 +01:00
__attribute ((format (printf, 6, 7)))
static void btf_log_func_param(const struct btf_elf *btfe,
btf: add func_proto support 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>
2018-12-18 23:09:42 +01:00
uint32_t name_off, uint32_t type,
bool err, bool is_last_param,
const char *fmt, ...)
{
FILE *out;
if (!btf_elf__verbose && !err)
btf: add func_proto support 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>
2018-12-18 23:09:42 +01:00
return;
out = err ? stderr : stdout;
if (is_last_param && !type)
fprintf(out, "vararg)\n");
else
fprintf(out, "%u %s%s", type,
btf_elf__name_in_gobuf(btfe, name_off),
btf: add func_proto support 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>
2018-12-18 23:09:42 +01:00
is_last_param ? ")\n" : ", ");
if (fmt && *fmt) {
va_list ap;
fprintf(out, " ");
va_start(ap, fmt);
vfprintf(out, fmt, ap);
va_end(ap);
}
}
int32_t btf_elf__add_base_type(struct btf_elf *btfe, const struct base_type *bt)
{
struct btf_int_type int_type;
struct btf_type *t = &int_type.type;
btf: Generate correct struct bitfield member types 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>
2018-11-30 00:45:49 +01:00
uint8_t encoding = 0;
t->name_off = bt->name;
t->info = BTF_INFO_ENCODE(BTF_KIND_INT, 0, 0);
t->size = BITS_ROUNDUP_BYTES(bt->bit_size);
if (bt->is_signed) {
encoding = BTF_INT_SIGNED;
} else if (bt->is_bool) {
encoding = BTF_INT_BOOL;
} else if (bt->float_type) {
fprintf(stderr, "float_type is not supported\n");
return -1;
}
int_type.data = BTF_INT_ENCODE(encoding, 0, bt->bit_size);
++btfe->type_index;
if (gobuffer__add(&btfe->types, &int_type, sizeof(int_type)) >= 0) {
btf_elf__log_type(btfe, t, false, true,
"size=%u bit_offset=%u nr_bits=%u encoding=%s",
t->size, BTF_INT_OFFSET(int_type.data),
BTF_INT_BITS(int_type.data),
btf_elf__int_encoding_str(BTF_INT_ENCODING(int_type.data)));
return btfe->type_index;
} else {
btf_elf__log_type(btfe, t, true, true,
"size=%u bit_offset=%u nr_bits=%u encoding=%s Error in adding gobuffer",
t->size, BTF_INT_OFFSET(int_type.data),
BTF_INT_BITS(int_type.data),
btf_elf__int_encoding_str(BTF_INT_ENCODING(int_type.data)));
return -1;
}
}
int32_t btf_elf__add_ref_type(struct btf_elf *btfe, uint16_t kind, uint32_t type,
uint32_t name, bool kind_flag)
{
struct btf_type t;
t.name_off = name;
btf: fix struct/union/fwd types with kind_flag 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 b18354f64cc2 ("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>
2018-12-18 23:09:41 +01:00
t.info = BTF_INFO_ENCODE(kind, kind_flag, 0);
t.type = type;
++btfe->type_index;
if (gobuffer__add(&btfe->types, &t, sizeof(t)) >= 0) {
btf: fix struct/union/fwd types with kind_flag 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 b18354f64cc2 ("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>
2018-12-18 23:09:41 +01:00
if (kind == BTF_KIND_FWD)
btf_elf__log_type(btfe, &t, false, true, "%s", kind_flag ? "union" : "struct");
btf: fix struct/union/fwd types with kind_flag 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 b18354f64cc2 ("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>
2018-12-18 23:09:41 +01:00
else
btf_elf__log_type(btfe, &t, false, true, "type_id=%u", t.type);
return btfe->type_index;
} else {
btf_elf__log_type(btfe, &t, true, true,
btf: fix struct/union/fwd types with kind_flag 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 b18354f64cc2 ("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>
2018-12-18 23:09:41 +01:00
"kind_flag=%d type_id=%u Error in adding gobuffer",
kind_flag, t.type);
return -1;
}
}
int32_t btf_elf__add_array(struct btf_elf *btfe, uint32_t type, uint32_t index_type, uint32_t nelems)
{
struct btf_array_type array_type;
struct btf_type *t = &array_type.type;
struct btf_array *array = &array_type.array;
t->name_off = 0;
t->info = BTF_INFO_ENCODE(BTF_KIND_ARRAY, 0, 0);
t->size = 0;
array->type = type;
array->index_type = index_type;
array->nelems = nelems;
++btfe->type_index;
if (gobuffer__add(&btfe->types, &array_type, sizeof(array_type)) >= 0) {
btf_elf__log_type(btfe, t, false, true,
"type_id=%u index_type_id=%u nr_elems=%u",
array->type, array->index_type, array->nelems);
return btfe->type_index;
} else {
btf_elf__log_type(btfe, t, true, true,
"type_id=%u index_type_id=%u nr_elems=%u Error in adding gobuffer",
array->type, array->index_type, array->nelems);
return -1;
}
}
int btf_elf__add_member(struct btf_elf *btfe, uint32_t name, uint32_t type, bool kind_flag,
uint32_t bitfield_size, uint32_t offset)
{
struct btf_member member = {
.name_off = name,
.type = type,
btf: fix struct/union/fwd types with kind_flag 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 b18354f64cc2 ("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>
2018-12-18 23:09:41 +01:00
.offset = kind_flag ? (bitfield_size << 24 | offset) : offset,
};
if (gobuffer__add(&btfe->types, &member, sizeof(member)) >= 0) {
btf_log_member(btfe, &member, kind_flag, false, NULL);
return 0;
} else {
btf_log_member(btfe, &member, kind_flag, true, "Error in adding gobuffer");
return -1;
}
}
int32_t btf_elf__add_struct(struct btf_elf *btfe, uint8_t kind, uint32_t name,
bool kind_flag, uint32_t size, uint16_t nr_members)
{
struct btf_type t;
t.name_off = name;
btf: fix struct/union/fwd types with kind_flag 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 b18354f64cc2 ("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>
2018-12-18 23:09:41 +01:00
t.info = BTF_INFO_ENCODE(kind, kind_flag, nr_members);
t.size = size;
++btfe->type_index;
if (gobuffer__add(&btfe->types, &t, sizeof(t)) >= 0) {
btf_elf__log_type(btfe, &t, false, true, "kind_flag=%d size=%u vlen=%u",
btf: fix struct/union/fwd types with kind_flag 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 b18354f64cc2 ("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>
2018-12-18 23:09:41 +01:00
kind_flag, t.size, BTF_INFO_VLEN(t.info));
return btfe->type_index;
} else {
btf_elf__log_type(btfe, &t, true, true,
btf: fix struct/union/fwd types with kind_flag 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 b18354f64cc2 ("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>
2018-12-18 23:09:41 +01:00
"kind_flag=%d size=%u vlen=%u Error in adding gobuffer",
kind_flag, t.size, BTF_INFO_VLEN(t.info));
return -1;
}
}
int32_t btf_elf__add_enum(struct btf_elf *btfe, uint32_t name, uint32_t bit_size, uint16_t nr_entries)
{
struct btf_type t;
t.name_off = name;
t.info = BTF_INFO_ENCODE(BTF_KIND_ENUM, 0, nr_entries);
t.size = BITS_ROUNDUP_BYTES(bit_size);
++btfe->type_index;
if (gobuffer__add(&btfe->types, &t, sizeof(t)) >= 0) {
btf_elf__log_type(btfe, &t, false, true, "size=%u vlen=%u", t.size, BTF_INFO_VLEN(t.info));
return btfe->type_index;
} else {
btf_elf__log_type(btfe, &t, true, true,
"size=%u vlen=%u Error in adding gobuffer",
t.size, BTF_INFO_VLEN(t.info));
return -1;
}
}
int btf_elf__add_enum_val(struct btf_elf *btfe, uint32_t name, int32_t value)
{
struct btf_enum e = {
.name_off = name,
.val = value,
};
if (gobuffer__add(&btfe->types, &e, sizeof(e)) < 0) {
fprintf(stderr, "\t%s val=%d Error in adding gobuffer\n",
btf_elf__name_in_gobuf(btfe, e.name_off), e.val);
return -1;
} else if (btf_elf__verbose)
printf("\t%s val=%d\n", btf_elf__name_in_gobuf(btfe, e.name_off),
e.val);
return 0;
}
static int32_t btf_elf__add_func_proto_param(struct btf_elf *btfe, uint32_t name,
uint32_t type, bool is_last_param)
btf: add func_proto support 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>
2018-12-18 23:09:42 +01:00
{
struct btf_param param;
param.name_off = name;
param.type = type;
if (gobuffer__add(&btfe->types, &param, sizeof(param)) >= 0) {
btf_log_func_param(btfe, name, type, false, is_last_param, NULL);
btf: add func_proto support 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>
2018-12-18 23:09:42 +01:00
return 0;
} else {
btf_log_func_param(btfe, name, type, true, is_last_param,
btf: add func_proto support 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>
2018-12-18 23:09:42 +01:00
"Error in adding gobuffer");
return -1;
}
}
int32_t btf_elf__add_func_proto(struct btf_elf *btfe, struct ftype *ftype, uint32_t type_id_off)
btf: add func_proto support 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>
2018-12-18 23:09:42 +01:00
{
uint16_t nr_params, param_idx;
struct parameter *param;
struct btf_type t;
int32_t type_id;
/* add btf_type for func_proto */
nr_params = ftype->nr_parms + (ftype->unspec_parms ? 1 : 0);
t.name_off = 0;
t.info = BTF_INFO_ENCODE(BTF_KIND_FUNC_PROTO, 0, nr_params);
t.type = ftype->tag.type == 0 ? 0 : type_id_off + ftype->tag.type;
btf: add func_proto support 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>
2018-12-18 23:09:42 +01:00
++btfe->type_index;
if (gobuffer__add(&btfe->types, &t, sizeof(t)) >= 0) {
btf_elf__log_type(btfe, &t, false, false, "return=%u args=(%s",
btf: add func_proto support 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>
2018-12-18 23:09:42 +01:00
t.type, !nr_params ? "void)\n" : "");
type_id = btfe->type_index;
btf: add func_proto support 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>
2018-12-18 23:09:42 +01:00
} else {
btf_elf__log_type(btfe, &t, true, true,
btf: add func_proto support 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>
2018-12-18 23:09:42 +01:00
"return=%u vlen=%u Error in adding gobuffer",
t.type, BTF_INFO_VLEN(t.info));
return -1;
}
/* add parameters */
param_idx = 0;
ftype__for_each_parameter(ftype, param) {
uint32_t param_type_id = param->tag.type == 0 ? 0 : type_id_off + param->tag.type;
btf: add func_proto support 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>
2018-12-18 23:09:42 +01:00
++param_idx;
if (btf_elf__add_func_proto_param(btfe, param->name, param_type_id, param_idx == nr_params))
btf: add func_proto support 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>
2018-12-18 23:09:42 +01:00
return -1;
}
++param_idx;
if (ftype->unspec_parms)
if (btf_elf__add_func_proto_param(btfe, 0, 0, param_idx == nr_params))
btf: add func_proto support 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>
2018-12-18 23:09:42 +01:00
return -1;
return type_id;
}
btf_encoder: Teach pahole to store percpu variables in vmlinux BTF. 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>
2020-07-08 22:44:10 +02:00
int32_t btf_elf__add_var_type(struct btf_elf *btfe, uint32_t type, uint32_t name_off,
uint32_t linkage)
{
struct btf_var_type t;
t.type.name_off = name_off;
t.type.info = BTF_INFO_ENCODE(BTF_KIND_VAR, 0, 0);
t.type.type = type;
t.var.linkage = linkage;
++btfe->type_index;
if (gobuffer__add(&btfe->types, &t.type, sizeof(t)) < 0) {
btf_elf__log_type(btfe, &t.type, true, true,
"type=%u name=%s Error in adding gobuffer",
t.type.type, btf_elf__name_in_gobuf(btfe, t.type.name_off));
return -1;
}
btf_elf__log_type(btfe, &t.type, false, false, "type=%u name=%s",
t.type.type, btf_elf__name_in_gobuf(btfe, t.type.name_off));
return btfe->type_index;
}
int32_t btf_elf__add_var_secinfo(struct gobuffer *buf, uint32_t type,
uint32_t offset, uint32_t size)
{
struct btf_var_secinfo si = {
.type = type,
.offset = offset,
.size = size,
};
return gobuffer__add(buf, &si, sizeof(si));
}
extern struct strings *strings;
int32_t btf_elf__add_datasec_type(struct btf_elf *btfe, const char *section_name,
struct gobuffer *var_secinfo_buf)
{
struct btf_type type;
size_t sz = gobuffer__size(var_secinfo_buf);
uint16_t nr_var_secinfo = sz / sizeof(struct btf_var_secinfo);
uint32_t name_off;
struct btf_var_secinfo *last_vsi;
qsort(var_secinfo_buf->entries, nr_var_secinfo,
sizeof(struct btf_var_secinfo), btf_var_secinfo_cmp);
last_vsi = (struct btf_var_secinfo *)var_secinfo_buf->entries + nr_var_secinfo - 1;
/*
* dwarves doesn't store section names in its string table,
* so we have to add it by ourselves.
*/
name_off = strings__add(strings, section_name);
type.name_off = name_off;
type.info = BTF_INFO_ENCODE(BTF_KIND_DATASEC, 0, nr_var_secinfo);
type.size = last_vsi->offset + last_vsi->size;
++btfe->type_index;
if (gobuffer__add(&btfe->types, &type, sizeof(type)) < 0) {
btf_elf__log_type(btfe, &type, true, true,
"name=%s vlen=%u Error in adding datasec",
btf_elf__name_in_gobuf(btfe, type.name_off),
nr_var_secinfo);
return -1;
}
if (gobuffer__add(&btfe->types, var_secinfo_buf->entries, sz) < 0) {
btf_elf__log_type(btfe, &type, true, true,
"name=%s vlen=%u Error in adding var_secinfo",
btf_elf__name_in_gobuf(btfe, type.name_off),
nr_var_secinfo);
return -1;
}
btf_elf__log_type(btfe, &type, false, false, "type=datasec name=%s",
btf_elf__name_in_gobuf(btfe, type.name_off));
return btfe->type_index;
}
static int btf_elf__write(const char *filename, struct btf *btf)
{
GElf_Shdr shdr_mem, *shdr;
GElf_Ehdr ehdr_mem, *ehdr;
Elf_Data *btf_elf = NULL;
Elf_Scn *scn = NULL;
Elf *elf = NULL;
const void *btf_data;
uint32_t btf_size;
int fd, err = -1;
size_t strndx;
fd = open(filename, O_RDWR);
if (fd < 0) {
fprintf(stderr, "Cannot open %s\n", filename);
return -1;
}
if (elf_version(EV_CURRENT) == EV_NONE) {
fprintf(stderr, "Cannot set libelf version.\n");
goto out;
}
elf = elf_begin(fd, ELF_C_RDWR, NULL);
if (elf == NULL) {
fprintf(stderr, "Cannot update ELF file.\n");
goto out;
}
elf_flagelf(elf, ELF_C_SET, ELF_F_DIRTY);
ehdr = gelf_getehdr(elf, &ehdr_mem);
if (ehdr == NULL) {
fprintf(stderr, "%s: elf_getehdr failed.\n", __func__);
goto out;
}
/*
* First we look if there was already a .BTF section to overwrite.
*/
elf_getshdrstrndx(elf, &strndx);
while ((scn = elf_nextscn(elf, scn)) != NULL) {
shdr = gelf_getshdr(scn, &shdr_mem);
if (shdr == NULL)
continue;
char *secname = elf_strptr(elf, strndx, shdr->sh_name);
if (strcmp(secname, ".BTF") == 0) {
btf_elf = elf_getdata(scn, btf_elf);
break;
}
}
btf_data = btf__get_raw_data(btf, &btf_size);
if (btf_elf) {
/* Exisiting .BTF section found */
btf_elf->d_buf = (void *)btf_data;
btf_elf->d_size = btf_size;
elf_flagdata(btf_elf, ELF_C_SET, ELF_F_DIRTY);
if (elf_update(elf, ELF_C_NULL) >= 0 &&
elf_update(elf, ELF_C_WRITE) >= 0)
err = 0;
} else {
const char *llvm_objcopy;
char tmp_fn[PATH_MAX];
char cmd[PATH_MAX * 2];
llvm_objcopy = getenv("LLVM_OBJCOPY");
if (!llvm_objcopy)
llvm_objcopy = "llvm-objcopy";
/* Use objcopy to add a .BTF section */
snprintf(tmp_fn, sizeof(tmp_fn), "%s.btf", filename);
close(fd);
fd = creat(tmp_fn, S_IRUSR | S_IWUSR);
if (fd == -1) {
fprintf(stderr, "%s: open(%s) failed!\n", __func__,
tmp_fn);
goto out;
}
snprintf(cmd, sizeof(cmd), "%s --add-section .BTF=%s %s",
llvm_objcopy, tmp_fn, filename);
if (write(fd, btf_data, btf_size) == btf_size && !system(cmd))
err = 0;
unlink(tmp_fn);
}
out:
if (fd != -1)
close(fd);
if (elf)
elf_end(elf);
return err;
}
static int libbpf_log(enum libbpf_print_level level, const char *format, va_list args)
{
return vfprintf(stderr, format, args);
}
int btf_elf__encode(struct btf_elf *btfe, uint8_t flags)
{
struct btf_header *hdr;
struct btf *btf;
/* Empty file, nothing to do, so... done! */
if (gobuffer__size(&btfe->types) == 0)
return 0;
btf_encoder: Teach pahole to store percpu variables in vmlinux BTF. 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>
2020-07-08 22:44:10 +02:00
if (gobuffer__size(&btfe->percpu_secinfo) != 0)
btf_elf__add_datasec_type(btfe, PERCPU_SECTION,
&btfe->percpu_secinfo);
btfe->size = sizeof(*hdr) + (gobuffer__size(&btfe->types) + gobuffer__size(btfe->strings));
btfe->data = zalloc(btfe->size);
if (btfe->data == NULL) {
fprintf(stderr, "%s: malloc failed!\n", __func__);
return -1;
}
hdr = btfe->hdr;
hdr->magic = BTF_MAGIC;
hdr->version = 1;
btf: Allow multiple cu's in dwarf->btf conversion 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>
2018-12-18 23:09:39 +01:00
hdr->flags = flags;
hdr->hdr_len = sizeof(*hdr);
hdr->type_off = 0;
hdr->type_len = gobuffer__size(&btfe->types);
hdr->str_off = hdr->type_len;
hdr->str_len = gobuffer__size(btfe->strings);
gobuffer__copy(&btfe->types, btf_elf__nohdr_data(btfe) + hdr->type_off);
gobuffer__copy(btfe->strings, btf_elf__nohdr_data(btfe) + hdr->str_off);
*(char *)(btf_elf__nohdr_data(btfe) + hdr->str_off) = '\0';
libbpf_set_print(libbpf_log);
btf = btf__new(btfe->data, btfe->size);
if (IS_ERR(btf)) {
fprintf(stderr, "%s: btf__new failed!\n", __func__);
return -1;
}
if (btf__dedup(btf, NULL, NULL)) {
fprintf(stderr, "%s: btf__dedup failed!", __func__);
return -1;
}
return btf_elf__write(btfe->filename, btf);
}