From 2a82d593be81b5052f9e770ed3fc1dd9b679ee74 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Thu, 20 Dec 2018 15:44:29 -0800 Subject: [PATCH] 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 Tested-by: Arnaldo Carvalho de Melo Cc: Alexei Starovoitov Cc: Martin KaFai Lau Cc: dwarves@vger.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- btf_loader.c | 61 +++++++++++++++++++++++++++++++--------------------- dwarves.h | 1 + 2 files changed, 37 insertions(+), 25 deletions(-) diff --git a/btf_loader.c b/btf_loader.c index dae21d5..eeb0c8b 100644 --- a/btf_loader.c +++ b/btf_loader.c @@ -1,4 +1,4 @@ -/* +/* * btf_loader.c * * Copyright (C) 2018 Arnaldo Carvalho de Melo @@ -101,7 +101,7 @@ static struct base_type *base_type__new(strings_t name, uint32_t attrs, } static void type__init(struct type *type, uint16_t tag, - strings_t name, size_t size) + strings_t name, size_t size, bool kflag) { INIT_LIST_HEAD(&type->node); INIT_LIST_HEAD(&type->namespace.tags); @@ -109,24 +109,26 @@ static void type__init(struct type *type, uint16_t tag, type->namespace.tag.tag = tag; type->namespace.name = name; type->namespace.sname = 0; + type->flag = kflag; } -static struct type *type__new(uint16_t tag, strings_t name, size_t size) +static struct type *type__new(uint16_t tag, strings_t name, size_t size, + bool kflag) { struct type *type = tag__alloc(sizeof(*type)); if (type != NULL) - type__init(type, tag, name, size); + type__init(type, tag, name, size, kflag); return type; } -static struct class *class__new(strings_t name, size_t size) +static struct class *class__new(strings_t name, size_t size, bool kflag) { struct class *class = tag__alloc(sizeof(*class)); if (class != NULL) { - type__init(&class->type, DW_TAG_structure_type, name, size); + type__init(&class->type, DW_TAG_structure_type, name, size, kflag); INIT_LIST_HEAD(&class->vtable); } @@ -177,7 +179,8 @@ static int create_new_array(struct btf *btf, void *ptr, long id) return sizeof(*ap); } -static int create_members(struct btf *btf, void *ptr, int vlen, struct type *class) +static int create_members(struct btf *btf, void *ptr, int vlen, struct type *class, + bool kflag) { struct btf_member *mp = ptr; int i; @@ -193,8 +196,13 @@ static int create_members(struct btf *btf, void *ptr, int vlen, struct type *cla 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); - member->bit_offset = BTF_MEMBER_BIT_OFFSET(offset); - member->bitfield_size = BTF_MEMBER_BITFIELD_SIZE(offset); + 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; + } /* sizes and offsets will be corrected at class__fixup_btf_bitfields */ type__add_member(class, member); } @@ -202,11 +210,13 @@ static int create_members(struct btf *btf, void *ptr, int vlen, struct type *cla return sizeof(*mp); } -static int create_new_class(struct btf *btf, void *ptr, int vlen, struct btf_type *tp, uint64_t size, long id) +static int create_new_class(struct btf *btf, void *ptr, int vlen, + struct btf_type *tp, uint64_t size, long id, + bool kflag) { strings_t name = btf__get32(btf, &tp->name_off); - struct class *class = class__new(name, size); - int member_size = create_members(btf, ptr, vlen, &class->type); + struct class *class = class__new(name, size, kflag); + int member_size = create_members(btf, ptr, vlen, &class->type, kflag); if (member_size < 0) goto out_free; @@ -221,11 +231,12 @@ out_free: static int create_new_union(struct btf *btf, void *ptr, int vlen, struct btf_type *tp, - uint64_t size, long id) + uint64_t size, long id, + bool kflag) { strings_t name = btf__get32(btf, &tp->name_off); - struct type *un = type__new(DW_TAG_union_type, name, size); - int member_size = create_members(btf, ptr, vlen, un); + struct type *un = type__new(DW_TAG_union_type, name, size, kflag); + int member_size = create_members(btf, ptr, vlen, un, kflag); if (member_size < 0) goto out_free; @@ -259,7 +270,7 @@ static int create_new_enumeration(struct btf *btf, void *ptr, uint16_t i; struct type *enumeration = type__new(DW_TAG_enumeration_type, btf__get32(btf, &tp->name_off), - size ?: (sizeof(int) * 8)); + size ?: (sizeof(int) * 8), false); if (enumeration == NULL) return -ENOMEM; @@ -299,10 +310,11 @@ static int create_new_subroutine_type(struct btf *btf, void *ptr, return vlen < 0 ? -ENOMEM : vlen; } -static int create_new_forward_decl(struct btf *btf, struct btf_type *tp, uint64_t size, long id) +static int create_new_forward_decl(struct btf *btf, struct btf_type *tp, + uint64_t size, long id, bool kflag) { strings_t name = btf__get32(btf, &tp->name_off); - struct class *fwd = class__new(name, size); + struct class *fwd = class__new(name, size, kflag); if (fwd == NULL) return -ENOMEM; @@ -315,7 +327,7 @@ static int create_new_typedef(struct btf *btf, struct btf_type *tp, uint64_t siz { strings_t name = btf__get32(btf, &tp->name_off); unsigned int type_id = btf__get32(btf, &tp->type); - struct type *type = type__new(DW_TAG_typedef, name, size); + struct type *type = type__new(DW_TAG_typedef, name, size, false); if (type == NULL) return -ENOMEM; @@ -377,6 +389,7 @@ static int btf__load_types(struct btf *btf) int vlen = BTF_INFO_VLEN(val); void *ptr = type_ptr; uint32_t size = btf__get32(btf, &type_ptr->size); + bool kflag = BTF_INFO_KFLAG(val); ptr += sizeof(struct btf_type); @@ -385,13 +398,13 @@ static int btf__load_types(struct btf *btf) } else if (type == BTF_KIND_ARRAY) { vlen = create_new_array(btf, ptr, type_index); } else if (type == BTF_KIND_STRUCT) { - vlen = create_new_class(btf, ptr, vlen, type_ptr, size, type_index); + vlen = create_new_class(btf, ptr, vlen, type_ptr, size, type_index, kflag); } else if (type == BTF_KIND_UNION) { - vlen = create_new_union(btf, ptr, vlen, type_ptr, size, type_index); + vlen = create_new_union(btf, ptr, vlen, type_ptr, size, type_index, kflag); } else if (type == BTF_KIND_ENUM) { vlen = create_new_enumeration(btf, ptr, vlen, type_ptr, size, type_index); } else if (type == BTF_KIND_FWD) { - vlen = create_new_forward_decl(btf, type_ptr, size, type_index); + vlen = create_new_forward_decl(btf, type_ptr, size, type_index, kflag); } else if (type == BTF_KIND_TYPEDEF) { vlen = create_new_typedef(btf, type_ptr, size, type_index); } else if (type == BTF_KIND_VOLATILE || @@ -442,7 +455,6 @@ static int class__fixup_btf_bitfields(struct tag *tag, struct cu *cu) continue; pos->bitfield_offset = 0; - pos->bitfield_size = 0; pos->byte_offset = pos->bit_offset / 8; uint16_t type_bit_size; @@ -484,13 +496,12 @@ static int class__fixup_btf_bitfields(struct tag *tag, struct cu *cu) */ pos->byte_size = integral_bit_size / 8; - if (integral_bit_size == 0 || type_bit_size == integral_bit_size) { + if (integral_bit_size == 0) { pos->bit_size = integral_bit_size; continue; } pos->bitfield_offset = pos->bit_offset % integral_bit_size; - pos->bitfield_size = type_bit_size; pos->bit_size = type_bit_size; pos->byte_offset = (((pos->bit_offset / integral_bit_size) * integral_bit_size) / 8); diff --git a/dwarves.h b/dwarves.h index 156fa58..f800518 100644 --- a/dwarves.h +++ b/dwarves.h @@ -879,6 +879,7 @@ struct type { uint8_t definition_emitted:1; uint8_t fwd_decl_emitted:1; uint8_t resized:1; + uint8_t flag:1; }; static inline struct class *type__class(const struct type *type)