dwarves/libbtf.h

71 lines
2.0 KiB
C
Raw Normal View History

/*
SPDX-License-Identifier: GPL-2.0-only
Copyright (C) 2019 Facebook
*/
#ifndef _LIBBTF_H
#define _LIBBTF_H
#include "gobuffer.h"
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
#include <stdbool.h>
#include <stdint.h>
struct btf_elf {
union {
struct btf_header *hdr;
void *data;
};
void *priv;
Elf *elf;
GElf_Ehdr ehdr;
struct gobuffer types;
struct gobuffer *strings;
char *filename;
size_t size;
int swapped;
int in_fd;
uint8_t wordsize;
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
bool is_big_endian;
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
bool raw_btf; // "/sys/kernel/btf/vmlinux"
uint32_t type_index;
};
extern uint8_t btf_elf__verbose;
#define btf_elf__verbose_log(fmt, ...) { if (btf_elf__verbose) printf(fmt, __VA_ARGS__); }
struct base_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
struct ftype;
struct btf_elf *btf_elf__new(const char *filename, Elf *elf);
void btf_elf__delete(struct btf_elf *btf);
int32_t btf_elf__add_base_type(struct btf_elf *btf, const struct base_type *bt);
int32_t btf_elf__add_ref_type(struct btf_elf *btf, uint16_t kind, uint32_t type,
uint32_t name, bool kind_flag);
int btf_elf__add_member(struct btf_elf *btf, uint32_t name, uint32_t type, bool kind_flag,
uint32_t bitfield_size, uint32_t bit_offset);
int32_t btf_elf__add_struct(struct btf_elf *btf, uint8_t kind, uint32_t name,
bool kind_flag, uint32_t size, uint16_t nr_members);
int32_t btf_elf__add_array(struct btf_elf *btf, uint32_t type, uint32_t index_type,
uint32_t nelems);
int32_t btf_elf__add_enum(struct btf_elf *btf, uint32_t name, uint32_t size,
uint16_t nr_entries);
int btf_elf__add_enum_val(struct btf_elf *btf, uint32_t name, int32_t value);
int32_t btf_elf__add_func_proto(struct btf_elf *btf, struct ftype *ftype,
uint32_t type_id_off);
void btf_elf__set_strings(struct btf_elf *btf, struct gobuffer *strings);
int btf_elf__encode(struct btf_elf *btf, uint8_t flags);
char *btf_elf__string(struct btf_elf *btf, uint32_t ref);
int btf_elf__load(struct btf_elf *btf);
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 btf_elf__get32(struct btf_elf *btf, 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
void *btf_elf__get_buffer(struct btf_elf *btf);
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
size_t btf_elf__get_size(struct btf_elf *btf);
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
#endif /* _LIBBTF_H */