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,
|
2018-12-23 08:16:49 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-12-23 08:16:49 +01:00
|
|
|
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)
|
2018-12-23 08:16:49 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-12-23 08:16:49 +01:00
|
|
|
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) {
|
2018-12-23 08:16:49 +01:00
|
|
|
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);
|
2018-12-23 08:16:49 +01:00
|
|
|
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);
|
2018-12-23 08:16:49 +01:00
|
|
|
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),
|
2019-01-10 19:09:57 +01:00
|
|
|
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,
|
2018-12-23 08:16:49 +01:00
|
|
|
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);
|
2018-12-23 08:16:49 +01:00
|
|
|
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);
|
2018-12-23 08:16:49 +01:00
|
|
|
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) {
|
2018-12-23 08:16:49 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2018-12-21 19:01:11 +01:00
|
|
|
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;
|
2018-12-21 19:01:11 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-12-21 19:01:11 +01:00
|
|
|
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)) {
|
2018-12-21 19:01:11 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-12-21 19:01:11 +01:00
|
|
|
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,
|
|
|
|
};
|