[PATCH pahole] btf_loader: Fix loading union types in BTF loader

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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



[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux