dwarves_fprintf: Show offsets at union members

In complex structs with multiple complex unions figuring out the offset
for a given union member is difficult, as one needs to figure out the
union, go to the end of it to see the offset.

So just turn struct_member__fprintf() into class_member__fprintf() and
pass a 'union_member' boolean to share all the aspects of struct and
union members, just not advancing the offset when processing union
members.

This way, for instance, the Linux kernel's 'struct page' goes from:

struct page {
	long unsigned int          flags;                /*     0     8 */
	union {
		struct address_space * mapping;          /*     8     8 */
		void *             s_mem;                /*     8     8 */
		atomic_t           compound_mapcount;    /*     8     4 */
	};                                               /*     8     8 */
	union {
		long unsigned int  index;                /*    16     8 */
		void *             freelist;             /*    16     8 */
	};                                               /*    16     8 */
	union {
		long unsigned int  counters;             /*    24     8 */
		struct {
			union {
				atomic_t _mapcount;      /*    24     4 */
				unsigned int active;     /*    24     4 */
				struct {
					unsigned int inuse:16; /*    24:16  4 */
					unsigned int objects:15; /*    24: 1  4 */
					unsigned int frozen:1; /*    24: 0  4 */
				};                       /*    24     4 */
				int units;               /*    24     4 */
			};                               /*    24     4 */
			atomic_t   _refcount;            /*    28     4 */
		};                                       /*    24     8 */
	};                                               /*    24     8 */
	union {
		struct list_head   lru;                  /*    32    16 */
		struct dev_pagemap * pgmap;              /*    32     8 */
		struct {
			struct page * next;              /*    32     8 */
			int        pages;                /*    40     4 */
			int        pobjects;             /*    44     4 */
		};                                       /*    32    16 */
		struct callback_head callback_head;      /*    32    16 */
		struct {
			long unsigned int compound_head; /*    32     8 */
			unsigned int compound_dtor;      /*    40     4 */
			unsigned int compound_order;     /*    44     4 */
		};                                       /*    32    16 */
		struct {
			long unsigned int __pad;         /*    32     8 */
			pgtable_t  pmd_huge_pte;         /*    40     8 */
		};                                       /*    32    16 */
	};                                               /*    32    16 */
	union {
		long unsigned int  private;              /*    48     8 */
		spinlock_t         ptl;                  /*    48     4 */
		struct kmem_cache * slab_cache;          /*    48     8 */
	};                                               /*    48     8 */
	struct mem_cgroup *        mem_cgroup;           /*    56     8 */

	/* size: 64, cachelines: 1, members: 7 */
};

To:

struct page {
	long unsigned int          flags;                /*     0     8 */
	union {
		struct address_space * mapping;          /*     8     8 */
		void *             s_mem;                /*     8     8 */
		atomic_t           compound_mapcount;    /*     8     4 */
	};                                               /*     8     8 */
	union {
		long unsigned int  index;                /*    16     8 */
		void *             freelist;             /*    16     8 */
	};                                               /*    16     8 */
	union {
		long unsigned int  counters;             /*    24     8 */
		struct {
			union {
				atomic_t _mapcount;      /*    24     4 */
				unsigned int active;     /*    24     4 */
				struct {
					unsigned int inuse:16; /*    24:16  4 */
					unsigned int objects:15; /*    24: 1  4 */
					unsigned int frozen:1; /*    24: 0  4 */
				};                       /*    24     4 */
				int units;               /*    24     4 */
			};                               /*    24     4 */
			atomic_t   _refcount;            /*    28     4 */
		};                                       /*    24     8 */
	};                                               /*    24     8 */
	union {
		struct list_head   lru;                  /*    32    16 */
		struct dev_pagemap * pgmap;              /*    32     8 */
		struct {
			struct page * next;              /*    32     8 */
			int        pages;                /*    40     4 */
			int        pobjects;             /*    44     4 */
		};                                       /*    32    16 */
		struct callback_head callback_head;      /*    32    16 */
		struct {
			long unsigned int compound_head; /*    32     8 */
			unsigned int compound_dtor;      /*    40     4 */
			unsigned int compound_order;     /*    44     4 */
		};                                       /*    32    16 */
		struct {
			long unsigned int __pad;         /*    32     8 */
			pgtable_t  pmd_huge_pte;         /*    40     8 */
		};                                       /*    32    16 */
	};                                               /*    32    16 */
	union {
		long unsigned int  private;              /*    48     8 */
		spinlock_t         ptl;                  /*    48     4 */
		struct kmem_cache * slab_cache;          /*    48     8 */
	};                                               /*    48     8 */
	struct mem_cgroup *        mem_cgroup;           /*    56     8 */

	/* size: 64, cachelines: 1, members: 7 */
};

Suggested-by: Matthew Wilcox <willy@infradead.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
Arnaldo Carvalho de Melo 2017-12-15 13:33:10 -03:00
parent 66cf3983e1
commit 2dd87be78b
1 changed files with 13 additions and 39 deletions

View File

@ -721,7 +721,7 @@ static size_t class__fprintf_cacheline_boundary(struct conf_fprintf *conf,
uint32_t offset,
FILE *fp);
static size_t struct_member__fprintf(struct class_member *member,
static size_t class_member__fprintf(struct class_member *member, bool union_member,
struct tag *type, const struct cu *cu,
struct conf_fprintf *conf, FILE *fp)
{
@ -733,8 +733,9 @@ static size_t struct_member__fprintf(struct class_member *member,
*name = cm_name;
if (!sconf.rel_offset) {
sconf.base_offset += member->byte_offset;
offset = sconf.base_offset;
offset += sconf.base_offset;
if (!union_member)
sconf.base_offset = offset;
}
if (!conf->suppress_comments)
@ -805,45 +806,18 @@ static size_t struct_member__fprintf(struct class_member *member,
return printed + printed_cacheline;
}
static size_t struct_member__fprintf(struct class_member *member,
struct tag *type, const struct cu *cu,
struct conf_fprintf *conf, FILE *fp)
{
return class_member__fprintf(member, false, type, cu, conf, fp);
}
static size_t union_member__fprintf(struct class_member *member,
struct tag *type, const struct cu *cu,
const struct conf_fprintf *conf, FILE *fp)
struct conf_fprintf *conf, FILE *fp)
{
const size_t size = member->byte_size;
const char *name = class_member__name(member, cu);
size_t printed = type__fprintf(type, cu, name, conf, fp);
if ((tag__is_union(type) || tag__is_struct(type) ||
tag__is_enumeration(type)) &&
/* Look if is a type defined inline */
type__name(tag__type(type), cu) == NULL) {
if (!conf->suppress_offset_comment) {
/* Check if this is a anonymous union */
const int slen = name ? (int)strlen(name) : -1;
/*
* Add the comment with the union size after padding the
* '} member_name;' last line of the type printed in the
* above call to type__fprintf.
*/
printed += fprintf(fp, conf->hex_fmt ?
";%*s/* %#11zx */" :
";%*s/* %11zd */",
(conf->type_spacing +
conf->name_spacing - slen - 3), " ", size);
}
} else {
printed += fprintf(fp, ";");
if (!conf->suppress_offset_comment) {
const int spacing = conf->type_spacing + conf->name_spacing - printed;
printed += fprintf(fp, conf->hex_fmt ?
"%*s/* %#11zx */" :
"%*s/* %11zd */",
spacing > 0 ? spacing : 0, " ", size);
}
}
return printed;
return class_member__fprintf(member, true, type, cu, conf, fp);
}
static size_t union__fprintf(struct type *type, const struct cu *cu,