dwarves/btf_loader.c

598 lines
15 KiB
C
Raw Normal View History

btf: Add kind_flag support for btf_loader For struct/union members, the struct/union type info kind_flag is needed to calculate correct bitfield_size and bit_offset. if (kind_flag) { bitfield_size = BTF_MEMBER_BITFIELD_SIZE(member->offset); bit_offset = BTF_MEMBER_BIT_OFFSET(member->offset); } else { bitfield_size = 0; bit_offset = member->offset; } Note that bitfield_size and bit_offset will not depend on the member type. The member type will help calculate correct bitfield_offset, byte_size, byte_offset, bit_size. For example, with the fix, we will be able to display bit offset and bitfield size properly. -bash-4.4$ cat t.c struct t { int a:2; int b:3; int c:2; } g; -bash-4.4$ gcc -c -O2 -g t.c -bash-4.4$ pahole -JV t.o File t.o: [1] STRUCT t kind_flag=1 size=4 vlen=3 a type_id=2 bitfield_size=2 bits_offset=0 b type_id=2 bitfield_size=3 bits_offset=2 c type_id=2 bitfield_size=2 bits_offset=5 [2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED -bash-4.4$ pahole -F btf t.o struct t { int a:2; /* 0: 0 4 */ int b:3; /* 0: 2 4 */ int c:2; /* 0: 5 4 */ /* size: 4, cachelines: 1, members: 3 */ /* bit_padding: 25 bits */ /* last cacheline: 4 bytes */ }; Note that the above offset showing is different from the below dwarf as BTF bitfield_offset is always the offset from the start of structure, kindly like big endian encoding. This may need adjustment to be conforming to the dwarf dump format. -bash-4.4$ pahole -F dwarf t.o struct t { int a:2; /* 0:30 4 */ int b:3; /* 0:27 4 */ int c:2; /* 0:25 4 */ /* size: 4, cachelines: 1, members: 3 */ /* bit_padding: 25 bits */ /* last cacheline: 4 bytes */ }; Signed-off-by: Yonghong Song <yhs@fb.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Alexei Starovoitov <ast@fb.com> Cc: Martin KaFai Lau <kafai@fb.com> Cc: dwarves@vger.kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-21 00:44:29 +01:00
/*
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.c
*
* Copyright (C) 2018 Arnaldo Carvalho de Melo <acme@kernel.org>
*
* Based on ctf_loader.c that, in turn, was based on ctfdump.c: CTF dumper.
*
* Copyright (C) 2008 David S. Miller <davem@davemloft.net>
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stddef.h>
#include <malloc.h>
#include <string.h>
#include <limits.h>
#include <libgen.h>
#include <zlib.h>
#include <gelf.h>
#include "libbtf.h"
#include "btf.h"
#include "dutil.h"
#include "dwarves.h"
/*
* FIXME: We should just get the table from the BTF ELF section
* and use it directly
*/
extern struct strings *strings;
static void *tag__alloc(const size_t size)
{
struct tag *tag = zalloc(size);
if (tag != NULL)
tag->top_level = 1;
return tag;
}
static int btf__load_ftype(struct btf *btf, struct ftype *proto, uint16_t tag,
uint32_t type, uint16_t vlen, struct btf_param *args, long id)
{
int i;
proto->tag.tag = tag;
proto->tag.type = type;
INIT_LIST_HEAD(&proto->parms);
for (i = 0; i < vlen; ++i) {
struct btf_param param = {
.name_off = btf__get32(btf, &args[i].name_off),
.type = btf__get32(btf, &args[i].type),
};
if (param.type == 0)
proto->unspec_parms = 1;
else {
struct parameter *p = tag__alloc(sizeof(*p));
if (p == NULL)
goto out_free_parameters;
p->tag.tag = DW_TAG_formal_parameter;
p->tag.type = param.type;
p->name = param.name_off;
ftype__add_parameter(proto, p);
}
}
vlen *= sizeof(*args);
cu__add_tag(btf->priv, &proto->tag, &id);
return vlen;
out_free_parameters:
ftype__delete(proto, btf->priv);
return -ENOMEM;
}
static struct base_type *base_type__new(strings_t name, uint32_t attrs,
uint8_t float_type, size_t size)
{
struct base_type *bt = tag__alloc(sizeof(*bt));
if (bt != NULL) {
bt->name = name;
bt->bit_size = size;
bt->is_signed = attrs & BTF_INT_SIGNED;
bt->is_bool = attrs & BTF_INT_BOOL;
bt->name_has_encoding = false;
bt->float_type = float_type;
}
return bt;
}
static void type__init(struct type *type, uint16_t tag,
strings_t name, size_t 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
{
INIT_LIST_HEAD(&type->node);
INIT_LIST_HEAD(&type->namespace.tags);
type->size = size;
type->namespace.tag.tag = tag;
type->namespace.name = name;
type->namespace.sname = 0;
}
static struct type *type__new(uint16_t tag, strings_t name, size_t 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
{
struct type *type = tag__alloc(sizeof(*type));
if (type != NULL)
type__init(type, tag, name, 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 type;
}
static struct class *class__new(strings_t name, size_t 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
{
struct class *class = tag__alloc(sizeof(*class));
if (class != NULL) {
type__init(&class->type, DW_TAG_structure_type, name, 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
INIT_LIST_HEAD(&class->vtable);
}
return class;
}
static int create_new_base_type(struct btf *btf, void *ptr, struct btf_type *tp, long id)
{
uint32_t *enc = ptr;
uint32_t eval = btf__get32(btf, enc);
uint32_t attrs = BTF_INT_ENCODING(eval);
strings_t name = btf__get32(btf, &tp->name_off);
struct base_type *base = base_type__new(name, attrs, 0,
BTF_INT_BITS(eval));
if (base == NULL)
return -ENOMEM;
base->tag.tag = DW_TAG_base_type;
cu__add_tag(btf->priv, &base->tag, &id);
return sizeof(*enc);
}
static int create_new_array(struct btf *btf, void *ptr, long id)
{
struct btf_array *ap = ptr;
struct array_type *array = tag__alloc(sizeof(*array));
if (array == NULL)
return -ENOMEM;
/* FIXME: where to get the number of dimensions?
* it it flattened? */
array->dimensions = 1;
array->nr_entries = malloc(sizeof(uint32_t));
if (array->nr_entries == NULL) {
free(array);
return -ENOMEM;
}
array->nr_entries[0] = btf__get32(btf, &ap->nelems);
array->tag.tag = DW_TAG_array_type;
array->tag.type = btf__get32(btf, &ap->type);
cu__add_tag(btf->priv, &array->tag, &id);
return sizeof(*ap);
}
btf: Add kind_flag support for btf_loader For struct/union members, the struct/union type info kind_flag is needed to calculate correct bitfield_size and bit_offset. if (kind_flag) { bitfield_size = BTF_MEMBER_BITFIELD_SIZE(member->offset); bit_offset = BTF_MEMBER_BIT_OFFSET(member->offset); } else { bitfield_size = 0; bit_offset = member->offset; } Note that bitfield_size and bit_offset will not depend on the member type. The member type will help calculate correct bitfield_offset, byte_size, byte_offset, bit_size. For example, with the fix, we will be able to display bit offset and bitfield size properly. -bash-4.4$ cat t.c struct t { int a:2; int b:3; int c:2; } g; -bash-4.4$ gcc -c -O2 -g t.c -bash-4.4$ pahole -JV t.o File t.o: [1] STRUCT t kind_flag=1 size=4 vlen=3 a type_id=2 bitfield_size=2 bits_offset=0 b type_id=2 bitfield_size=3 bits_offset=2 c type_id=2 bitfield_size=2 bits_offset=5 [2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED -bash-4.4$ pahole -F btf t.o struct t { int a:2; /* 0: 0 4 */ int b:3; /* 0: 2 4 */ int c:2; /* 0: 5 4 */ /* size: 4, cachelines: 1, members: 3 */ /* bit_padding: 25 bits */ /* last cacheline: 4 bytes */ }; Note that the above offset showing is different from the below dwarf as BTF bitfield_offset is always the offset from the start of structure, kindly like big endian encoding. This may need adjustment to be conforming to the dwarf dump format. -bash-4.4$ pahole -F dwarf t.o struct t { int a:2; /* 0:30 4 */ int b:3; /* 0:27 4 */ int c:2; /* 0:25 4 */ /* size: 4, cachelines: 1, members: 3 */ /* bit_padding: 25 bits */ /* last cacheline: 4 bytes */ }; Signed-off-by: Yonghong Song <yhs@fb.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Alexei Starovoitov <ast@fb.com> Cc: Martin KaFai Lau <kafai@fb.com> Cc: dwarves@vger.kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-21 00:44:29 +01:00
static int create_members(struct btf *btf, void *ptr, int vlen, struct type *class,
bool kflag)
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_member *mp = ptr;
int i;
for (i = 0; i < vlen; i++) {
struct class_member *member = zalloc(sizeof(*member));
uint32_t offset;
if (member == NULL)
return -ENOMEM;
member->tag.tag = DW_TAG_member;
member->tag.type = btf__get32(btf, &mp[i].type);
member->name = btf__get32(btf, &mp[i].name_off);
offset = btf__get32(btf, &mp[i].offset);
btf: Add kind_flag support for btf_loader For struct/union members, the struct/union type info kind_flag is needed to calculate correct bitfield_size and bit_offset. if (kind_flag) { bitfield_size = BTF_MEMBER_BITFIELD_SIZE(member->offset); bit_offset = BTF_MEMBER_BIT_OFFSET(member->offset); } else { bitfield_size = 0; bit_offset = member->offset; } Note that bitfield_size and bit_offset will not depend on the member type. The member type will help calculate correct bitfield_offset, byte_size, byte_offset, bit_size. For example, with the fix, we will be able to display bit offset and bitfield size properly. -bash-4.4$ cat t.c struct t { int a:2; int b:3; int c:2; } g; -bash-4.4$ gcc -c -O2 -g t.c -bash-4.4$ pahole -JV t.o File t.o: [1] STRUCT t kind_flag=1 size=4 vlen=3 a type_id=2 bitfield_size=2 bits_offset=0 b type_id=2 bitfield_size=3 bits_offset=2 c type_id=2 bitfield_size=2 bits_offset=5 [2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED -bash-4.4$ pahole -F btf t.o struct t { int a:2; /* 0: 0 4 */ int b:3; /* 0: 2 4 */ int c:2; /* 0: 5 4 */ /* size: 4, cachelines: 1, members: 3 */ /* bit_padding: 25 bits */ /* last cacheline: 4 bytes */ }; Note that the above offset showing is different from the below dwarf as BTF bitfield_offset is always the offset from the start of structure, kindly like big endian encoding. This may need adjustment to be conforming to the dwarf dump format. -bash-4.4$ pahole -F dwarf t.o struct t { int a:2; /* 0:30 4 */ int b:3; /* 0:27 4 */ int c:2; /* 0:25 4 */ /* size: 4, cachelines: 1, members: 3 */ /* bit_padding: 25 bits */ /* last cacheline: 4 bytes */ }; Signed-off-by: Yonghong Song <yhs@fb.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Alexei Starovoitov <ast@fb.com> Cc: Martin KaFai Lau <kafai@fb.com> Cc: dwarves@vger.kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-21 00:44:29 +01:00
if (kflag) {
member->bit_offset = BTF_MEMBER_BIT_OFFSET(offset);
member->bitfield_size = BTF_MEMBER_BITFIELD_SIZE(offset);
} else {
member->bit_offset = offset;
member->bitfield_size = 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
/* sizes and offsets will be corrected at class__fixup_btf_bitfields */
type__add_member(class, member);
}
return sizeof(*mp);
}
btf: Add kind_flag support for btf_loader For struct/union members, the struct/union type info kind_flag is needed to calculate correct bitfield_size and bit_offset. if (kind_flag) { bitfield_size = BTF_MEMBER_BITFIELD_SIZE(member->offset); bit_offset = BTF_MEMBER_BIT_OFFSET(member->offset); } else { bitfield_size = 0; bit_offset = member->offset; } Note that bitfield_size and bit_offset will not depend on the member type. The member type will help calculate correct bitfield_offset, byte_size, byte_offset, bit_size. For example, with the fix, we will be able to display bit offset and bitfield size properly. -bash-4.4$ cat t.c struct t { int a:2; int b:3; int c:2; } g; -bash-4.4$ gcc -c -O2 -g t.c -bash-4.4$ pahole -JV t.o File t.o: [1] STRUCT t kind_flag=1 size=4 vlen=3 a type_id=2 bitfield_size=2 bits_offset=0 b type_id=2 bitfield_size=3 bits_offset=2 c type_id=2 bitfield_size=2 bits_offset=5 [2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED -bash-4.4$ pahole -F btf t.o struct t { int a:2; /* 0: 0 4 */ int b:3; /* 0: 2 4 */ int c:2; /* 0: 5 4 */ /* size: 4, cachelines: 1, members: 3 */ /* bit_padding: 25 bits */ /* last cacheline: 4 bytes */ }; Note that the above offset showing is different from the below dwarf as BTF bitfield_offset is always the offset from the start of structure, kindly like big endian encoding. This may need adjustment to be conforming to the dwarf dump format. -bash-4.4$ pahole -F dwarf t.o struct t { int a:2; /* 0:30 4 */ int b:3; /* 0:27 4 */ int c:2; /* 0:25 4 */ /* size: 4, cachelines: 1, members: 3 */ /* bit_padding: 25 bits */ /* last cacheline: 4 bytes */ }; Signed-off-by: Yonghong Song <yhs@fb.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Alexei Starovoitov <ast@fb.com> Cc: Martin KaFai Lau <kafai@fb.com> Cc: dwarves@vger.kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-21 00:44:29 +01:00
static int create_new_class(struct btf *btf, void *ptr, int vlen,
struct btf_type *tp, uint64_t size, long id,
bool kflag)
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
{
strings_t name = btf__get32(btf, &tp->name_off);
struct class *class = class__new(name, size);
btf: Add kind_flag support for btf_loader For struct/union members, the struct/union type info kind_flag is needed to calculate correct bitfield_size and bit_offset. if (kind_flag) { bitfield_size = BTF_MEMBER_BITFIELD_SIZE(member->offset); bit_offset = BTF_MEMBER_BIT_OFFSET(member->offset); } else { bitfield_size = 0; bit_offset = member->offset; } Note that bitfield_size and bit_offset will not depend on the member type. The member type will help calculate correct bitfield_offset, byte_size, byte_offset, bit_size. For example, with the fix, we will be able to display bit offset and bitfield size properly. -bash-4.4$ cat t.c struct t { int a:2; int b:3; int c:2; } g; -bash-4.4$ gcc -c -O2 -g t.c -bash-4.4$ pahole -JV t.o File t.o: [1] STRUCT t kind_flag=1 size=4 vlen=3 a type_id=2 bitfield_size=2 bits_offset=0 b type_id=2 bitfield_size=3 bits_offset=2 c type_id=2 bitfield_size=2 bits_offset=5 [2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED -bash-4.4$ pahole -F btf t.o struct t { int a:2; /* 0: 0 4 */ int b:3; /* 0: 2 4 */ int c:2; /* 0: 5 4 */ /* size: 4, cachelines: 1, members: 3 */ /* bit_padding: 25 bits */ /* last cacheline: 4 bytes */ }; Note that the above offset showing is different from the below dwarf as BTF bitfield_offset is always the offset from the start of structure, kindly like big endian encoding. This may need adjustment to be conforming to the dwarf dump format. -bash-4.4$ pahole -F dwarf t.o struct t { int a:2; /* 0:30 4 */ int b:3; /* 0:27 4 */ int c:2; /* 0:25 4 */ /* size: 4, cachelines: 1, members: 3 */ /* bit_padding: 25 bits */ /* last cacheline: 4 bytes */ }; Signed-off-by: Yonghong Song <yhs@fb.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Alexei Starovoitov <ast@fb.com> Cc: Martin KaFai Lau <kafai@fb.com> Cc: dwarves@vger.kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-21 00:44:29 +01:00
int member_size = create_members(btf, ptr, vlen, &class->type, kflag);
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 (member_size < 0)
goto out_free;
cu__add_tag(btf->priv, &class->type.namespace.tag, &id);
return (vlen * member_size);
out_free:
class__delete(class, btf->priv);
return -ENOMEM;
}
static int create_new_union(struct btf *btf, void *ptr,
int vlen, struct btf_type *tp,
btf: Add kind_flag support for btf_loader For struct/union members, the struct/union type info kind_flag is needed to calculate correct bitfield_size and bit_offset. if (kind_flag) { bitfield_size = BTF_MEMBER_BITFIELD_SIZE(member->offset); bit_offset = BTF_MEMBER_BIT_OFFSET(member->offset); } else { bitfield_size = 0; bit_offset = member->offset; } Note that bitfield_size and bit_offset will not depend on the member type. The member type will help calculate correct bitfield_offset, byte_size, byte_offset, bit_size. For example, with the fix, we will be able to display bit offset and bitfield size properly. -bash-4.4$ cat t.c struct t { int a:2; int b:3; int c:2; } g; -bash-4.4$ gcc -c -O2 -g t.c -bash-4.4$ pahole -JV t.o File t.o: [1] STRUCT t kind_flag=1 size=4 vlen=3 a type_id=2 bitfield_size=2 bits_offset=0 b type_id=2 bitfield_size=3 bits_offset=2 c type_id=2 bitfield_size=2 bits_offset=5 [2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED -bash-4.4$ pahole -F btf t.o struct t { int a:2; /* 0: 0 4 */ int b:3; /* 0: 2 4 */ int c:2; /* 0: 5 4 */ /* size: 4, cachelines: 1, members: 3 */ /* bit_padding: 25 bits */ /* last cacheline: 4 bytes */ }; Note that the above offset showing is different from the below dwarf as BTF bitfield_offset is always the offset from the start of structure, kindly like big endian encoding. This may need adjustment to be conforming to the dwarf dump format. -bash-4.4$ pahole -F dwarf t.o struct t { int a:2; /* 0:30 4 */ int b:3; /* 0:27 4 */ int c:2; /* 0:25 4 */ /* size: 4, cachelines: 1, members: 3 */ /* bit_padding: 25 bits */ /* last cacheline: 4 bytes */ }; Signed-off-by: Yonghong Song <yhs@fb.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Alexei Starovoitov <ast@fb.com> Cc: Martin KaFai Lau <kafai@fb.com> Cc: dwarves@vger.kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-21 00:44:29 +01:00
uint64_t size, long id,
bool kflag)
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
{
strings_t name = btf__get32(btf, &tp->name_off);
struct type *un = type__new(DW_TAG_union_type, name, size);
btf: Add kind_flag support for btf_loader For struct/union members, the struct/union type info kind_flag is needed to calculate correct bitfield_size and bit_offset. if (kind_flag) { bitfield_size = BTF_MEMBER_BITFIELD_SIZE(member->offset); bit_offset = BTF_MEMBER_BIT_OFFSET(member->offset); } else { bitfield_size = 0; bit_offset = member->offset; } Note that bitfield_size and bit_offset will not depend on the member type. The member type will help calculate correct bitfield_offset, byte_size, byte_offset, bit_size. For example, with the fix, we will be able to display bit offset and bitfield size properly. -bash-4.4$ cat t.c struct t { int a:2; int b:3; int c:2; } g; -bash-4.4$ gcc -c -O2 -g t.c -bash-4.4$ pahole -JV t.o File t.o: [1] STRUCT t kind_flag=1 size=4 vlen=3 a type_id=2 bitfield_size=2 bits_offset=0 b type_id=2 bitfield_size=3 bits_offset=2 c type_id=2 bitfield_size=2 bits_offset=5 [2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED -bash-4.4$ pahole -F btf t.o struct t { int a:2; /* 0: 0 4 */ int b:3; /* 0: 2 4 */ int c:2; /* 0: 5 4 */ /* size: 4, cachelines: 1, members: 3 */ /* bit_padding: 25 bits */ /* last cacheline: 4 bytes */ }; Note that the above offset showing is different from the below dwarf as BTF bitfield_offset is always the offset from the start of structure, kindly like big endian encoding. This may need adjustment to be conforming to the dwarf dump format. -bash-4.4$ pahole -F dwarf t.o struct t { int a:2; /* 0:30 4 */ int b:3; /* 0:27 4 */ int c:2; /* 0:25 4 */ /* size: 4, cachelines: 1, members: 3 */ /* bit_padding: 25 bits */ /* last cacheline: 4 bytes */ }; Signed-off-by: Yonghong Song <yhs@fb.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Alexei Starovoitov <ast@fb.com> Cc: Martin KaFai Lau <kafai@fb.com> Cc: dwarves@vger.kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-21 00:44:29 +01:00
int member_size = create_members(btf, ptr, vlen, un, kflag);
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 (member_size < 0)
goto out_free;
cu__add_tag(btf->priv, &un->namespace.tag, &id);
return (vlen * member_size);
out_free:
type__delete(un, btf->priv);
return -ENOMEM;
}
static struct enumerator *enumerator__new(strings_t name, uint32_t value)
{
struct enumerator *en = tag__alloc(sizeof(*en));
if (en != NULL) {
en->name = name;
en->value = value;
en->tag.tag = DW_TAG_enumerator;
}
return en;
}
static int create_new_enumeration(struct btf *btf, void *ptr,
int vlen, struct btf_type *tp,
uint16_t size, long id)
{
struct btf_enum *ep = ptr;
uint16_t i;
struct type *enumeration = type__new(DW_TAG_enumeration_type,
btf__get32(btf, &tp->name_off),
size ? size * 8 : (sizeof(int) * 8));
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 (enumeration == NULL)
return -ENOMEM;
for (i = 0; i < vlen; i++) {
strings_t name = btf__get32(btf, &ep[i].name_off);
uint32_t value = btf__get32(btf, &ep[i].val);
struct enumerator *enumerator = enumerator__new(name, value);
if (enumerator == NULL)
goto out_free;
enumeration__add(enumeration, enumerator);
}
cu__add_tag(btf->priv, &enumeration->namespace.tag, &id);
return (vlen * sizeof(*ep));
out_free:
enumeration__delete(enumeration, btf->priv);
return -ENOMEM;
}
static int create_new_subroutine_type(struct btf *btf, void *ptr,
int vlen, struct btf_type *tp,
long id)
{
struct btf_param *args = ptr;
unsigned int type = btf__get32(btf, &tp->type);
struct ftype *proto = tag__alloc(sizeof(*proto));
if (proto == NULL)
return -ENOMEM;
vlen = btf__load_ftype(btf, proto, DW_TAG_subroutine_type,
type, vlen, args, id);
return vlen < 0 ? -ENOMEM : vlen;
}
btf: Add kind_flag support for btf_loader For struct/union members, the struct/union type info kind_flag is needed to calculate correct bitfield_size and bit_offset. if (kind_flag) { bitfield_size = BTF_MEMBER_BITFIELD_SIZE(member->offset); bit_offset = BTF_MEMBER_BIT_OFFSET(member->offset); } else { bitfield_size = 0; bit_offset = member->offset; } Note that bitfield_size and bit_offset will not depend on the member type. The member type will help calculate correct bitfield_offset, byte_size, byte_offset, bit_size. For example, with the fix, we will be able to display bit offset and bitfield size properly. -bash-4.4$ cat t.c struct t { int a:2; int b:3; int c:2; } g; -bash-4.4$ gcc -c -O2 -g t.c -bash-4.4$ pahole -JV t.o File t.o: [1] STRUCT t kind_flag=1 size=4 vlen=3 a type_id=2 bitfield_size=2 bits_offset=0 b type_id=2 bitfield_size=3 bits_offset=2 c type_id=2 bitfield_size=2 bits_offset=5 [2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED -bash-4.4$ pahole -F btf t.o struct t { int a:2; /* 0: 0 4 */ int b:3; /* 0: 2 4 */ int c:2; /* 0: 5 4 */ /* size: 4, cachelines: 1, members: 3 */ /* bit_padding: 25 bits */ /* last cacheline: 4 bytes */ }; Note that the above offset showing is different from the below dwarf as BTF bitfield_offset is always the offset from the start of structure, kindly like big endian encoding. This may need adjustment to be conforming to the dwarf dump format. -bash-4.4$ pahole -F dwarf t.o struct t { int a:2; /* 0:30 4 */ int b:3; /* 0:27 4 */ int c:2; /* 0:25 4 */ /* size: 4, cachelines: 1, members: 3 */ /* bit_padding: 25 bits */ /* last cacheline: 4 bytes */ }; Signed-off-by: Yonghong Song <yhs@fb.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Alexei Starovoitov <ast@fb.com> Cc: Martin KaFai Lau <kafai@fb.com> Cc: dwarves@vger.kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-21 00:44:29 +01:00
static int create_new_forward_decl(struct btf *btf, struct btf_type *tp,
uint64_t size, long id)
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
{
strings_t name = btf__get32(btf, &tp->name_off);
struct class *fwd = class__new(name, 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
if (fwd == NULL)
return -ENOMEM;
fwd->type.declaration = 1;
cu__add_tag(btf->priv, &fwd->type.namespace.tag, &id);
return 0;
}
static int create_new_typedef(struct btf *btf, struct btf_type *tp, uint64_t size, long id)
{
strings_t name = btf__get32(btf, &tp->name_off);
unsigned int type_id = btf__get32(btf, &tp->type);
struct type *type = type__new(DW_TAG_typedef, name, 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
if (type == NULL)
return -ENOMEM;
type->namespace.tag.type = type_id;
cu__add_tag(btf->priv, &type->namespace.tag, &id);
return 0;
}
static int create_new_tag(struct btf *btf, int type, struct btf_type *tp, long id)
{
unsigned int type_id = btf__get32(btf, &tp->type);
struct tag *tag = zalloc(sizeof(*tag));
if (tag == NULL)
return -ENOMEM;
switch (type) {
case BTF_KIND_CONST: tag->tag = DW_TAG_const_type; break;
case BTF_KIND_PTR: tag->tag = DW_TAG_pointer_type; break;
case BTF_KIND_RESTRICT: tag->tag = DW_TAG_restrict_type; break;
case BTF_KIND_VOLATILE: tag->tag = DW_TAG_volatile_type; break;
default:
printf("%s: FOO %d\n\n", __func__, type);
return 0;
}
tag->type = type_id;
cu__add_tag(btf->priv, tag, &id);
return 0;
}
void *btf__get_buffer(struct btf *btf)
{
return btf->data;
}
size_t btf__get_size(struct btf *btf)
{
return btf->size;
}
static int btf__load_types(struct btf *btf)
{
void *btf_buffer = btf__get_buffer(btf);
struct btf_header *hp = btf_buffer;
void *btf_contents = btf_buffer + sizeof(*hp),
*type_section = (btf_contents + btf__get32(btf, &hp->type_off)),
*strings_section = (btf_contents + btf__get32(btf, &hp->str_off));
struct btf_type *type_ptr = type_section,
*end = strings_section;
unsigned int type_index = 0x0001;
while (type_ptr < end) {
uint32_t val = btf__get32(btf, &type_ptr->info);
uint32_t type = BTF_INFO_KIND(val);
int vlen = BTF_INFO_VLEN(val);
void *ptr = type_ptr;
uint32_t size = btf__get32(btf, &type_ptr->size);
btf: Add kind_flag support for btf_loader For struct/union members, the struct/union type info kind_flag is needed to calculate correct bitfield_size and bit_offset. if (kind_flag) { bitfield_size = BTF_MEMBER_BITFIELD_SIZE(member->offset); bit_offset = BTF_MEMBER_BIT_OFFSET(member->offset); } else { bitfield_size = 0; bit_offset = member->offset; } Note that bitfield_size and bit_offset will not depend on the member type. The member type will help calculate correct bitfield_offset, byte_size, byte_offset, bit_size. For example, with the fix, we will be able to display bit offset and bitfield size properly. -bash-4.4$ cat t.c struct t { int a:2; int b:3; int c:2; } g; -bash-4.4$ gcc -c -O2 -g t.c -bash-4.4$ pahole -JV t.o File t.o: [1] STRUCT t kind_flag=1 size=4 vlen=3 a type_id=2 bitfield_size=2 bits_offset=0 b type_id=2 bitfield_size=3 bits_offset=2 c type_id=2 bitfield_size=2 bits_offset=5 [2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED -bash-4.4$ pahole -F btf t.o struct t { int a:2; /* 0: 0 4 */ int b:3; /* 0: 2 4 */ int c:2; /* 0: 5 4 */ /* size: 4, cachelines: 1, members: 3 */ /* bit_padding: 25 bits */ /* last cacheline: 4 bytes */ }; Note that the above offset showing is different from the below dwarf as BTF bitfield_offset is always the offset from the start of structure, kindly like big endian encoding. This may need adjustment to be conforming to the dwarf dump format. -bash-4.4$ pahole -F dwarf t.o struct t { int a:2; /* 0:30 4 */ int b:3; /* 0:27 4 */ int c:2; /* 0:25 4 */ /* size: 4, cachelines: 1, members: 3 */ /* bit_padding: 25 bits */ /* last cacheline: 4 bytes */ }; Signed-off-by: Yonghong Song <yhs@fb.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Alexei Starovoitov <ast@fb.com> Cc: Martin KaFai Lau <kafai@fb.com> Cc: dwarves@vger.kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-21 00:44:29 +01:00
bool kflag = BTF_INFO_KFLAG(val);
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
ptr += sizeof(struct btf_type);
if (type == BTF_KIND_INT) {
vlen = create_new_base_type(btf, ptr, type_ptr, type_index);
} else if (type == BTF_KIND_ARRAY) {
vlen = create_new_array(btf, ptr, type_index);
} else if (type == BTF_KIND_STRUCT) {
btf: Add kind_flag support for btf_loader For struct/union members, the struct/union type info kind_flag is needed to calculate correct bitfield_size and bit_offset. if (kind_flag) { bitfield_size = BTF_MEMBER_BITFIELD_SIZE(member->offset); bit_offset = BTF_MEMBER_BIT_OFFSET(member->offset); } else { bitfield_size = 0; bit_offset = member->offset; } Note that bitfield_size and bit_offset will not depend on the member type. The member type will help calculate correct bitfield_offset, byte_size, byte_offset, bit_size. For example, with the fix, we will be able to display bit offset and bitfield size properly. -bash-4.4$ cat t.c struct t { int a:2; int b:3; int c:2; } g; -bash-4.4$ gcc -c -O2 -g t.c -bash-4.4$ pahole -JV t.o File t.o: [1] STRUCT t kind_flag=1 size=4 vlen=3 a type_id=2 bitfield_size=2 bits_offset=0 b type_id=2 bitfield_size=3 bits_offset=2 c type_id=2 bitfield_size=2 bits_offset=5 [2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED -bash-4.4$ pahole -F btf t.o struct t { int a:2; /* 0: 0 4 */ int b:3; /* 0: 2 4 */ int c:2; /* 0: 5 4 */ /* size: 4, cachelines: 1, members: 3 */ /* bit_padding: 25 bits */ /* last cacheline: 4 bytes */ }; Note that the above offset showing is different from the below dwarf as BTF bitfield_offset is always the offset from the start of structure, kindly like big endian encoding. This may need adjustment to be conforming to the dwarf dump format. -bash-4.4$ pahole -F dwarf t.o struct t { int a:2; /* 0:30 4 */ int b:3; /* 0:27 4 */ int c:2; /* 0:25 4 */ /* size: 4, cachelines: 1, members: 3 */ /* bit_padding: 25 bits */ /* last cacheline: 4 bytes */ }; Signed-off-by: Yonghong Song <yhs@fb.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Alexei Starovoitov <ast@fb.com> Cc: Martin KaFai Lau <kafai@fb.com> Cc: dwarves@vger.kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-21 00:44:29 +01:00
vlen = create_new_class(btf, ptr, vlen, type_ptr, size, type_index, kflag);
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 if (type == BTF_KIND_UNION) {
btf: Add kind_flag support for btf_loader For struct/union members, the struct/union type info kind_flag is needed to calculate correct bitfield_size and bit_offset. if (kind_flag) { bitfield_size = BTF_MEMBER_BITFIELD_SIZE(member->offset); bit_offset = BTF_MEMBER_BIT_OFFSET(member->offset); } else { bitfield_size = 0; bit_offset = member->offset; } Note that bitfield_size and bit_offset will not depend on the member type. The member type will help calculate correct bitfield_offset, byte_size, byte_offset, bit_size. For example, with the fix, we will be able to display bit offset and bitfield size properly. -bash-4.4$ cat t.c struct t { int a:2; int b:3; int c:2; } g; -bash-4.4$ gcc -c -O2 -g t.c -bash-4.4$ pahole -JV t.o File t.o: [1] STRUCT t kind_flag=1 size=4 vlen=3 a type_id=2 bitfield_size=2 bits_offset=0 b type_id=2 bitfield_size=3 bits_offset=2 c type_id=2 bitfield_size=2 bits_offset=5 [2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED -bash-4.4$ pahole -F btf t.o struct t { int a:2; /* 0: 0 4 */ int b:3; /* 0: 2 4 */ int c:2; /* 0: 5 4 */ /* size: 4, cachelines: 1, members: 3 */ /* bit_padding: 25 bits */ /* last cacheline: 4 bytes */ }; Note that the above offset showing is different from the below dwarf as BTF bitfield_offset is always the offset from the start of structure, kindly like big endian encoding. This may need adjustment to be conforming to the dwarf dump format. -bash-4.4$ pahole -F dwarf t.o struct t { int a:2; /* 0:30 4 */ int b:3; /* 0:27 4 */ int c:2; /* 0:25 4 */ /* size: 4, cachelines: 1, members: 3 */ /* bit_padding: 25 bits */ /* last cacheline: 4 bytes */ }; Signed-off-by: Yonghong Song <yhs@fb.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Alexei Starovoitov <ast@fb.com> Cc: Martin KaFai Lau <kafai@fb.com> Cc: dwarves@vger.kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-21 00:44:29 +01:00
vlen = create_new_union(btf, ptr, vlen, type_ptr, size, type_index, kflag);
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 if (type == BTF_KIND_ENUM) {
vlen = create_new_enumeration(btf, ptr, vlen, type_ptr, size, type_index);
} else if (type == BTF_KIND_FWD) {
vlen = create_new_forward_decl(btf, type_ptr, size, type_index);
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 if (type == BTF_KIND_TYPEDEF) {
vlen = create_new_typedef(btf, type_ptr, size, type_index);
} else if (type == BTF_KIND_VOLATILE ||
type == BTF_KIND_PTR ||
type == BTF_KIND_CONST ||
type == BTF_KIND_RESTRICT) {
vlen = create_new_tag(btf, type, type_ptr, type_index);
} else if (type == BTF_KIND_UNKN) {
cu__table_nullify_type_entry(btf->priv, type_index);
fprintf(stderr,
"BTF: idx: %d, off: %zd, Unknown\n",
type_index, ((void *)type_ptr) - type_section);
fflush(stderr);
vlen = 0;
} else if (type == BTF_KIND_FUNC_PROTO) {
vlen = create_new_subroutine_type(btf, ptr, vlen, type_ptr, type_index);
btf: recognize BTF_KIND_FUNC in btf_loader BTF_KIND_FUNC is generated by llvm (latest trunk, 8.0 or later). Without BTF_KIND_FUNC support, we will see the following errors, -bash-4.4$ cat t.c struct t { int a; char b1:1; char b2:3; int c; } g; int main() { return 0; } -bash-4.4$ clang -O2 -target bpf -g -c t.c -Xclang -target-feature -Xclang +dwarfris -bash-4.4$ pahole -F btf t.o BTF: idx: 3, off: 28, Unknown struct t { int a; /* 0 4 */ /* Bitfield combined with previous fields */ <ERROR(__class__fprintf:1342): 5 not found!> /* Bitfield combined with previous fields */ <ERROR(__class__fprintf:1342): 5 not found!> int c; /* 8 4 */ /* size: 12, cachelines: 1, members: 4 */ /* last cacheline: 12 bytes */ /* BRAIN FART ALERT! 12 != 8 + 0(holes), diff = 4 */ }; -bash-4.4$ The reason is that llvm generates BTF_KIND_FUNC which btf_loader does not recognize. This patch added support for BTF_KIND_FUNC. Since BTF_KIND_FUNC represents a defined subprogram and not a real type. A null type is used to represent BTF_KIND_FUNC to avoid skipping type index. With this fix: -bash-4.4$ pahole -F btf t.o struct t { int a; /* 0 4 */ char b1:1; /* 4: 0 1 */ char b2:3; /* 4: 1 1 */ int c; /* 8 4 */ /* size: 12, cachelines: 1, members: 4 */ /* last cacheline: 12 bytes */ /* BRAIN FART ALERT! 12 != 9 + 0(holes), diff = 3 */ }; Signed-off-by: Yonghong Song <yhs@fb.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Alexei Starovoitov <ast@fb.com> Cc: Martin KaFai Lau <kafai@fb.com> Cc: dwarves@vger.kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-23 08:16:49 +01:00
} else if (type == BTF_KIND_FUNC) {
/* BTF_KIND_FUNC corresponding to a defined subprogram.
* This is not really a type and it won't be referred by any other types
* either. Since types cannot be skipped, let us replace it with
* a nullify_type_entry.
*
* No warning here since BTF_KIND_FUNC is a legal entry in BTF.
*/
cu__table_nullify_type_entry(btf->priv, type_index);
vlen = 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 {
fprintf(stderr,
"BTF: idx: %d, off: %zd, Unknown\n",
type_index, ((void *)type_ptr) - type_section);
fflush(stderr);
vlen = 0;
}
if (vlen < 0)
return vlen;
type_ptr = ptr + vlen;
type_index++;
}
return 0;
}
static int btf__load_sections(struct btf *btf)
{
return btf__load_types(btf);
}
static int class__fixup_btf_bitfields(struct tag *tag, struct cu *cu, struct btf *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
{
struct class_member *pos;
struct type *tag_type = tag__type(tag);
type__for_each_data_member(tag_type, pos) {
struct tag *type = tag__follow_typedef(&pos->tag, cu);
if (type == NULL) /* FIXME: C++ BTF... */
continue;
pos->bitfield_offset = 0;
pos->byte_offset = pos->bit_offset / 8;
uint16_t type_bit_size;
size_t integral_bit_size;
switch (type->tag) {
case DW_TAG_enumeration_type:
type_bit_size = tag__type(type)->size;
/* Best we can do to check if this is a packed enum */
if (is_power_of_2(type_bit_size))
integral_bit_size = roundup(type_bit_size, 8);
else
integral_bit_size = sizeof(int) * 8;
break;
case DW_TAG_base_type: {
struct base_type *bt = tag__base_type(type);
char name[256];
type_bit_size = bt->bit_size;
integral_bit_size = base_type__name_to_size(bt, cu);
if (integral_bit_size == 0) {
fprintf(stderr, "%s: unknown base type name \"%s\"!\n",
__func__, base_type__name(bt, cu, name,
sizeof(name)));
}
}
break;
default:
pos->byte_size = tag__size(type, cu);
pos->bit_size = pos->byte_size * 8;
continue;
}
/*
* XXX: integral_bit_size can be zero if base_type__name_to_size doesn't
* know about the base_type name, so one has to add there when
* such base_type isn't found. pahole will put zero on the
* struct output so it should be easy to spot the name when
* such unlikely thing happens.
*/
pos->byte_size = integral_bit_size / 8;
btf: Add kind_flag support for btf_loader For struct/union members, the struct/union type info kind_flag is needed to calculate correct bitfield_size and bit_offset. if (kind_flag) { bitfield_size = BTF_MEMBER_BITFIELD_SIZE(member->offset); bit_offset = BTF_MEMBER_BIT_OFFSET(member->offset); } else { bitfield_size = 0; bit_offset = member->offset; } Note that bitfield_size and bit_offset will not depend on the member type. The member type will help calculate correct bitfield_offset, byte_size, byte_offset, bit_size. For example, with the fix, we will be able to display bit offset and bitfield size properly. -bash-4.4$ cat t.c struct t { int a:2; int b:3; int c:2; } g; -bash-4.4$ gcc -c -O2 -g t.c -bash-4.4$ pahole -JV t.o File t.o: [1] STRUCT t kind_flag=1 size=4 vlen=3 a type_id=2 bitfield_size=2 bits_offset=0 b type_id=2 bitfield_size=3 bits_offset=2 c type_id=2 bitfield_size=2 bits_offset=5 [2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED -bash-4.4$ pahole -F btf t.o struct t { int a:2; /* 0: 0 4 */ int b:3; /* 0: 2 4 */ int c:2; /* 0: 5 4 */ /* size: 4, cachelines: 1, members: 3 */ /* bit_padding: 25 bits */ /* last cacheline: 4 bytes */ }; Note that the above offset showing is different from the below dwarf as BTF bitfield_offset is always the offset from the start of structure, kindly like big endian encoding. This may need adjustment to be conforming to the dwarf dump format. -bash-4.4$ pahole -F dwarf t.o struct t { int a:2; /* 0:30 4 */ int b:3; /* 0:27 4 */ int c:2; /* 0:25 4 */ /* size: 4, cachelines: 1, members: 3 */ /* bit_padding: 25 bits */ /* last cacheline: 4 bytes */ }; Signed-off-by: Yonghong Song <yhs@fb.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Alexei Starovoitov <ast@fb.com> Cc: Martin KaFai Lau <kafai@fb.com> Cc: dwarves@vger.kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-21 00:44:29 +01:00
if (integral_bit_size == 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
pos->bit_size = integral_bit_size;
continue;
}
pos->bitfield_offset = pos->bit_offset % integral_bit_size;
if (!btf->is_big_endian)
pos->bitfield_offset = integral_bit_size - pos->bitfield_offset - pos->bitfield_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
pos->bit_size = type_bit_size;
pos->byte_offset = (((pos->bit_offset / integral_bit_size) *
integral_bit_size) / 8);
}
return 0;
}
static int cu__fixup_btf_bitfields(struct cu *cu, struct btf *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
{
int err = 0;
struct tag *pos;
list_for_each_entry(pos, &cu->tags, node)
if (tag__is_struct(pos) || tag__is_union(pos)) {
err = class__fixup_btf_bitfields(pos, cu, 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
if (err)
break;
}
return err;
}
static void btf__cu_delete(struct cu *cu)
{
btf__free(cu->priv);
cu->priv = NULL;
}
static const char *btf__strings_ptr(const struct cu *cu, strings_t s)
{
return btf__string(cu->priv, s);
}
struct debug_fmt_ops btf__ops;
int btf__load_file(struct cus *cus, struct conf_load *conf,
const char *filename)
{
int err;
struct btf *state = btf__new(filename, NULL);
if (state == NULL)
return -1;
struct cu *cu = cu__new(filename, state->wordsize, NULL, 0, filename);
if (cu == NULL)
return -1;
cu->language = LANG_C;
cu->uses_global_strings = false;
cu->dfops = &btf__ops;
cu->priv = state;
state->priv = cu;
if (btf__load(state) != 0)
return -1;
err = btf__load_sections(state);
if (err != 0) {
cu__delete(cu);
return err;
}
err = cu__fixup_btf_bitfields(cu, state);
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
/*
* The app stole this cu, possibly deleting it,
* so forget about it
*/
if (conf && conf->steal && conf->steal(cu, conf))
return 0;
cus__add(cus, cu);
return err;
}
struct debug_fmt_ops btf__ops = {
.name = "btf",
.load_file = btf__load_file,
.strings__ptr = btf__strings_ptr,
.cu__delete = btf__cu_delete,
};