Union, when loaded, were created as 'struct type', while structs were created as 'struct class', that contained 'struct type' within it. When processing, though, unions and structs were treated the same with assumption that they both are represented by 'struct class'. This patch fixes issue by making sure unions and structs are created the same, modulo DW_TAG_structure_type vs DW_TAG_union_type tag. Without fix: andriin@devvm$ ~/local/pahole/build/pahole -F dwarf -C fpregs_state ~/local/linux/net/ipv4/tcp.o union fpregs_state { struct fxregs_state fxsave; /* 0 512 */ struct swregs_state soft; /* 0 136 */ struct xregs_state xsave; /* 0 576 */ u8 __padding[4096]; /* 0 4096 */ }; andriin@devvm$ ~/local/pahole/build/pahole -F btf -C fpregs_state ~/local/linux/net/ipv4/tcp.o Segmentation fault (core dumped) With fix: andriin@devvm$ ~/local/pahole/build/pahole -F dwarf -C fpregs_state ~/local/linux/net/ipv4/tcp.o union fpregs_state { struct fxregs_state fxsave; /* 0 512 */ struct swregs_state soft; /* 0 136 */ struct xregs_state xsave; /* 0 576 */ u8 __padding[4096]; /* 0 4096 */ }; andriin@devvm$ ~/local/pahole/build/pahole -F btf -C fpregs_state ~/local/linux/net/ipv4/tcp.o union fpregs_state { struct fregs_state fsave; /* 0 112 */ struct fxregs_state fxsave; /* 0 512 */ struct swregs_state soft; /* 0 136 */ struct xregs_state xsave; /* 0 576 */ u8 __padding[4096]; /* 0 4096 */ }; Note that there is a difference between DWARF and BTF loader outputs: DWARF one seems to always skip first member of union type. It's not the case for structs, though. This issue will be investigated and fixed separately. Signed-off-by: Andrii Nakryiko <andriin@xxxxxx> --- btf_loader.c | 39 ++++++++++++--------------------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/btf_loader.c b/btf_loader.c index dae21d5..f04b12a 100644 --- a/btf_loader.c +++ b/btf_loader.c @@ -1,4 +1,4 @@ -/* +/* * btf_loader.c * * Copyright (C) 2018 Arnaldo Carvalho de Melo <acme@xxxxxxxxxx> @@ -121,12 +121,12 @@ static struct type *type__new(uint16_t tag, strings_t name, size_t size) return type; } -static struct class *class__new(strings_t name, size_t size) +static struct class *class__new(strings_t name, size_t size, uint16_t tag) { struct class *class = tag__alloc(sizeof(*class)); if (class != NULL) { - type__init(&class->type, DW_TAG_structure_type, name, size); + type__init(&class->type, tag, name, size); INIT_LIST_HEAD(&class->vtable); } @@ -205,7 +205,10 @@ static int create_members(struct btf *btf, void *ptr, int vlen, struct type *cla static int create_new_class(struct btf *btf, void *ptr, int vlen, struct btf_type *tp, uint64_t size, long id) { strings_t name = btf__get32(btf, &tp->name_off); - struct class *class = class__new(name, size); + uint16_t type_tag = BTF_INFO_KIND(tp->info) == BTF_KIND_STRUCT + ? DW_TAG_structure_type + : DW_TAG_union_type; + struct class *class = class__new(name, size, type_tag); int member_size = create_members(btf, ptr, vlen, &class->type); if (member_size < 0) @@ -219,25 +222,6 @@ out_free: return -ENOMEM; } -static int create_new_union(struct btf *btf, void *ptr, - int vlen, struct btf_type *tp, - uint64_t size, long id) -{ - 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); - - 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)); @@ -302,7 +286,10 @@ static int create_new_subroutine_type(struct btf *btf, void *ptr, static int create_new_forward_decl(struct btf *btf, struct btf_type *tp, uint64_t size, long id) { strings_t name = btf__get32(btf, &tp->name_off); - struct class *fwd = class__new(name, size); + uint16_t type_tag = BTF_INFO_KIND(tp->info) + ? DW_TAG_union_type + : DW_TAG_structure_type; + struct class *fwd = class__new(name, size, type_tag); if (fwd == NULL) return -ENOMEM; @@ -384,10 +371,8 @@ static int btf__load_types(struct btf *btf) 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) { + } else if (type == BTF_KIND_STRUCT || type == BTF_KIND_UNION) { vlen = create_new_class(btf, ptr, vlen, type_ptr, size, type_index); - } else if (type == BTF_KIND_UNION) { - vlen = create_new_union(btf, ptr, vlen, type_ptr, size, type_index); } else if (type == BTF_KIND_ENUM) { vlen = create_new_enumeration(btf, ptr, vlen, type_ptr, size, type_index); } else if (type == BTF_KIND_FWD) { -- 2.17.1