[CLASSES]: Fully support nested classes

Example:

[acme@newtoy pahole]$ pahole net/ipv4/tcp.o flowi
/* include/net/flow.h:13 */
struct flowi {
	int                        oif;                  /*     0     4 */
	int                        iif;                  /*     4     4 */
	__u32                      mark;                 /*     8     4 */
	union {
		struct {
			__be32     daddr;                /*     0     4 */
			__be32     saddr;                /*     4     4 */
			__u8       tos;                  /*     8     1 */
			__u8       scope;                /*     9     1 */
		} ip4_u;                                 /*          12 */
		struct {
			struct in6_addr daddr;           /*     0    16 */
			struct in6_addr saddr;           /*    16    16 */
			/* --- cacheline 1 boundary (32 bytes) --- */
			__be32     flowlabel;            /*    32     4 */
		} ip6_u;                                 /*          36 */
		struct {
			__le16     daddr;                /*     0     2 */
			__le16     saddr;                /*     2     2 */
			__u8       scope;                /*     4     1 */
		} dn_u;                                  /*           6 */
	} nl_u;                                          /*    12    36 */
	/* --- cacheline 1 boundary (32 bytes) was 16 bytes ago --- */
	__u8                       proto;                /*    48     1 */
	__u8                       flags;                /*    49     1 */

	/* XXX 2 bytes hole, try to pack */

	union {
		struct {
			__be16     sport;                /*     0     2 */
			__be16     dport;                /*     2     2 */
		} ports;                                 /*           4 */
		struct {
			__u8       type;                 /*     0     1 */
			__u8       code;                 /*     1     1 */
		} icmpt;                                 /*           2 */
		struct {
			__le16     sport;                /*     0     2 */
			__le16     dport;                /*     2     2 */
		} dnports;                               /*           4 */
		__be32             spi;                  /*           4 */
	} uli_u;                                         /*    52     4 */
	__u32                      secid;                /*    56     4 */
}; /* size: 60, cachelines: 2 */
   /* sum members: 58, holes: 1, sum holes: 2 */
   /* last cacheline: 28 bytes */

Supporting anonymous structs and unions just fine, even combinations of both,
like in struct page, in the Linux kernel:

[acme@newtoy pahole]$ pahole mm/mmap.o page
/* include/linux/mmzone.h:391 */
struct page {
	long unsigned int          flags;                /*     0     4 */
	atomic_t                   _count;               /*     4     4 */
	atomic_t                   _mapcount;            /*     8     4 */
	union {
		struct {
			long unsigned int private;       /*     0     4 */
			struct address_space * mapping;  /*     4     4 */
		};                                       /*           8 */
	};                                               /*    12     8 */
	long unsigned int          index;                /*    20     4 */
	struct list_head           lru;                  /*    24     8 */
	/* --- cacheline 1 boundary (32 bytes) --- */
}; /* size: 32, cachelines: 1 */

Or struct freebsd_sys_getdents_args in the OpenBSD kernel:

/* /usr/home/leonardo/openbsd/src/sys/compat/freebsd/freebsd_syscallargs.h:231 */
struct freebsd_sys_getdents_args {
	union {
		register_t         pad;                  /*           4 */
		struct {
			int        datum;                /*     0     4 */
		} le;                                    /*           4 */
		struct {
			int8_t     pad[0];               /*     0     0 */
			int        datum;                /*     0     4 */
		} be;                                    /*           4 */
	} fd;                                            /*     0     4 */
	union {
		register_t         pad;                  /*           4 */
		struct {
			void *     datum;                /*     0     4 */
		} le;                                    /*           4 */
		struct {
			int8_t     pad[0];               /*     0     0 */
			void *     datum;                /*     0     4 */
		} be;                                    /*           4 */
	} dirent;                                        /*     4     4 */
	union {
		register_t         pad;                  /*           4 */
		struct {
			unsigned int datum;              /*     0     4 */
		} le;                                    /*           4 */
		struct {
			int8_t     pad[0];               /*     0     0 */
			unsigned int datum;              /*     0     4 */
		} be;                                    /*           4 */
	} count;                                         /*     8     4 */
}; /* size: 12, cachelines: 1 */
   /* last cacheline: 12 bytes */
   /* definitions: 7 */

One more from the OpenBSD kernel:

/* /usr/home/leonardo/openbsd/src/sys/nfs/nfs.h:344 */
struct nfssvc_sock {
	struct {
		struct nfssvc_sock * tqe_next;           /*     0     4 */
		struct nfssvc_sock * * tqe_prev;         /*     4     4 */
	} ns_chain;                                      /*     0     8 */
	struct {
		struct nfsuid *    tqh_first;            /*     0     4 */
		struct nfsuid * *  tqh_last;             /*     4     4 */
	} ns_uidlruhead;                                 /*     8     8 */
	struct file *              ns_fp;                /*    16     4 */
	struct socket *            ns_so;                /*    20     4 */
	struct mbuf *              ns_nam;               /*    24     4 */
	struct mbuf *              ns_raw;               /*    28     4 */
	/* --- cacheline 1 boundary (32 bytes) --- */
	struct mbuf *              ns_rawend;            /*    32     4 */
	struct mbuf *              ns_rec;               /*    36     4 */
	struct mbuf *              ns_recend;            /*    40     4 */
	struct mbuf *              ns_frag;              /*    44     4 */
	int                        ns_flag;              /*    48     4 */
	int                        ns_solock;            /*    52     4 */
	int                        ns_cc;                /*    56     4 */
	int                        ns_reclen;            /*    60     4 */
	/* --- cacheline 2 boundary (64 bytes) --- */
	int                        ns_numuids;           /*    64     4 */
	u_int32_t                  ns_sref;              /*    68     4 */
	struct {
		struct nfsrv_descript * lh_first;        /*     0     4 */
	} ns_tq;                                         /*    72     4 */
	struct                     ns_uidhashtbl[29];    /*    76   116 */
	/* --- cacheline 6 boundary (192 bytes) --- */
	struct nfsrvw_delayhash    ns_wdelayhashtbl[16]; /*   192    64 */
	/* --- cacheline 8 boundary (256 bytes) --- */
}; /* size: 256, cachelines: 8 */
   /* definitions: 12 */

Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
This commit is contained in:
Arnaldo Carvalho de Melo 2007-01-10 19:46:47 -02:00
parent 63edfc24e0
commit 465c4978b7
1 changed files with 121 additions and 56 deletions

177
classes.c
View File

@ -923,13 +923,16 @@ static size_t union__snprintf(const struct type *self, const struct cu *cu,
char *bf, size_t len, const char *suffix,
uint8_t ntabs, size_t type_spacing,
size_t name_spacing);
static size_t class__snprintf(const struct class *self, const struct cu *cu,
char *bf, size_t len,
const char *prefix, const char *suffix,
uint8_t ntabs, size_t type_spacing,
size_t name_spacing, int emit_stats);
static size_t class_member__snprintf(struct class_member *self,
struct tag *type,
const struct cu *cu,
char *bf, size_t len,
size_t type_spacing,
size_t name_spacing)
struct tag *type, const struct cu *cu,
char *bf, size_t len, size_t ntabs,
size_t type_spacing, size_t name_spacing)
{
char tbf[128];
@ -952,7 +955,18 @@ static size_t class_member__snprintf(struct class_member *self,
else if (type->tag == DW_TAG_array_type)
return array_type__snprintf(type, cu, bf, len, self->name,
type_spacing);
else if (type->tag == DW_TAG_union_type) {
else if (type->tag == DW_TAG_structure_type) {
struct type *ctype = tag__type(type);
if (ctype->name != NULL)
return snprintf(bf, len, "struct %-*s %s",
type_spacing - 7, ctype->name,
self->name);
return class__snprintf(tag__class(type), cu, bf, len,
NULL, self->name, ntabs,
type_spacing - 8, name_spacing, 0);
} else if (type->tag == DW_TAG_union_type) {
struct type *ctype = tag__type(type);
if (ctype->name != NULL)
@ -960,7 +974,7 @@ static size_t class_member__snprintf(struct class_member *self,
type_spacing - 6, ctype->name,
self->name);
return union__snprintf(ctype, cu, bf, len, self->name, 1,
return union__snprintf(ctype, cu, bf, len, self->name, ntabs,
type_spacing - 8, name_spacing);
} else if (type->tag == DW_TAG_enumeration_type) {
struct type *ctype = tag__type(type);
@ -970,7 +984,7 @@ static size_t class_member__snprintf(struct class_member *self,
type_spacing - 5, ctype->name,
self->name);
return enumeration__snprintf(type, bf, len, self->name, 1);
return enumeration__snprintf(type, bf, len, self->name, ntabs);
}
return snprintf(bf, len, "%-*s %s", type_spacing,
tag__name(type, cu, tbf, sizeof(tbf)),
@ -979,12 +993,13 @@ static size_t class_member__snprintf(struct class_member *self,
static size_t struct_member__snprintf(struct class_member *self,
struct tag *type, const struct cu *cu,
char *bf, size_t len,
char *bf, size_t len, size_t ntabs,
size_t type_spacing, size_t name_spacing)
{
size_t l = len;
ssize_t spacing;
const size_t size = tag__size(type, cu);
size_t n = class_member__snprintf(self, type, cu, bf, l,
size_t n = class_member__snprintf(self, type, cu, bf, l, ntabs,
type_spacing, name_spacing);
bf += n; l -= n;
@ -995,22 +1010,51 @@ static size_t struct_member__snprintf(struct class_member *self,
bf += n; l -= n;
if ((type->tag == DW_TAG_union_type ||
type->tag == DW_TAG_enumeration_type) &&
/* Look if is a type defined inline */
type->tag == DW_TAG_enumeration_type ||
type->tag == DW_TAG_structure_type) &&
/* Look if is a type defined inline */
tag__type(type)->name == NULL) {
/* Check if this is a anonymous union */
const size_t slen = self->name != NULL ?
strlen(self->name) : 0;
n = snprintf(bf, l, "%*s/* %5u %5u */",
type_spacing + name_spacing - slen - 3, " ",
self->offset, size);
} else {
int spacing = type_spacing + name_spacing - (len - l);
n = snprintf(bf, l, "%*s/* %5u %5u */",
spacing > 0 ? spacing : 0, " ",
self->offset, size);
strlen(self->name) : -1;
return len -
(l - snprintf(bf, l, "%*s/* %5u %5u */",
type_spacing + name_spacing - slen - 3,
" ", self->offset, size));
}
return len - (l - n);
spacing = type_spacing + name_spacing - (len - l);
return len - (l - snprintf(bf, l, "%*s/* %5u %5u */",
spacing > 0 ? spacing : 0, " ",
self->offset, size));
}
static size_t union_member__snprintf(struct class_member *self,
struct tag *type, const struct cu *cu,
char *bf, size_t len, size_t ntabs,
size_t type_spacing, size_t name_spacing)
{
size_t l = len;
ssize_t spacing;
const size_t size = tag__size(type, cu);
size_t n = class_member__snprintf(self, type, cu, bf, l, ntabs,
type_spacing, name_spacing);
bf += n; l -= n;
if ((type->tag == DW_TAG_union_type ||
type->tag == DW_TAG_enumeration_type ||
type->tag == DW_TAG_structure_type) &&
/* Look if is a type defined inline */
tag__type(type)->name == NULL) {
/* Check if this is a anonymous union */
const size_t slen = self->name != NULL ?
strlen(self->name) : -1;
return n + snprintf(bf, l, ";%*s/* %11u */",
type_spacing + name_spacing - slen - 3, " ",
size);
}
spacing = type_spacing + name_spacing - (len - (l - 1));
return n + snprintf(bf, l, ";%*s/* %11u */",
spacing > 0 ? spacing : 0, " ", size);
}
static size_t union__snprintf(const struct type *self, const struct cu *cu,
@ -1034,12 +1078,10 @@ static size_t union__snprintf(const struct type *self, const struct cu *cu,
n = snprintf(s, l, "%.*s", ntabs + 1, tabs);
s += n; l -= n;
n = class_member__snprintf(pos, type, cu, s, l, type_spacing,
name_spacing + 1);
n = union_member__snprintf(pos, type, cu, s, l, ntabs + 1,
type_spacing, name_spacing);
s += n; l -= n;
n = snprintf(s, l, ";%*s /* %11u */\n",
type_spacing + name_spacing - (n + 2), " ",
tag__size(type, cu));
n = snprintf(s, l, "\n");
s += n; l -= n;
}
@ -1550,7 +1592,8 @@ static size_t class__snprintf_cacheline_boundary(char *bf, size_t len,
uint32_t last_cacheline,
size_t sum, size_t sum_holes,
uint8_t *newline,
uint32_t *cacheline)
uint32_t *cacheline,
size_t ntabs)
{
size_t l = len;
const size_t real_sum = sum + sum_holes;
@ -1568,12 +1611,15 @@ static size_t class__snprintf_cacheline_boundary(char *bf, size_t len,
*newline = 0;
}
n = snprintf(bf, l, "%.*s", ntabs, tabs);
bf += n; l -= n;
if (cacheline_pos == 0)
n = snprintf(bf, len, " /* --- cacheline "
n = snprintf(bf, len, "/* --- cacheline "
"%u boundary (%u bytes) --- */\n",
*cacheline, cacheline_in_bytes);
else
n = snprintf(bf, len, " /* --- cacheline "
n = snprintf(bf, len, "/* --- cacheline "
"%u boundary (%u bytes) was %u "
"bytes ago --- */\n",
*cacheline, cacheline_in_bytes,
@ -1588,8 +1634,9 @@ static size_t class__snprintf(const struct class *self, const struct cu *cu,
char *bf, size_t len,
const char *prefix, const char *suffix,
uint8_t ntabs, size_t type_spacing,
size_t name_spacing)
size_t name_spacing, int emit_stats)
{
const char *orig_bf = bf;
const struct type *tself = &self->type;
size_t last_size = 0, size;
size_t last_bit_size = 0;
@ -1607,6 +1654,9 @@ static size_t class__snprintf(const struct class *self, const struct cu *cu,
bf += n; l -= n;
if (ntabs >= sizeof(tabs))
ntabs = sizeof(tabs) - 1;
list_for_each_entry(pos, &tself->members, tag.node) {
struct tag *type;
const ssize_t cc_last_size = pos->offset - last_offset;
@ -1614,16 +1664,20 @@ static size_t class__snprintf(const struct class *self, const struct cu *cu,
n = class__snprintf_cacheline_boundary(bf, l, last_cacheline,
sum, sum_holes,
&newline,
&last_cacheline);
&last_cacheline,
ntabs + 1);
bf += n; l -= n;
if (last_offset != -1) {
if (cc_last_size < last_size && cc_last_size > 0) {
if (!newline++)
putchar('\n');
n = snprintf(bf, l, " /* Bitfield "
if (!newline++) {
n = snprintf(bf, l, "\n");
bf += n; l -= n;
}
n = snprintf(bf, l, "%.*s/* Bitfield "
"WARNING: DWARF "
"size=%u, real size=%u */\n",
ntabs + 1, tabs,
last_size, cc_last_size);
bf += n; l -= n;
sum -= last_size - cc_last_size;
@ -1657,12 +1711,11 @@ static size_t class__snprintf(const struct class *self, const struct cu *cu,
newline = 0;
}
n = snprintf(bf, l, " ");
bf += n; l -= n;
type = cu__find_tag_by_id(cu, pos->tag.type);
size = tag__size(type, cu);
n = struct_member__snprintf(pos, type, cu, bf, l,
n = snprintf(bf, l, "%.*s", ntabs + 1, tabs);
bf += n; l -= n;
n = struct_member__snprintf(pos, type, cu, bf, l, ntabs + 1,
type_spacing, name_spacing);
bf += n; l -= n;
@ -1671,8 +1724,9 @@ static size_t class__snprintf(const struct class *self, const struct cu *cu,
n = snprintf(bf, l, "\n");
bf += n; l -= n;
}
n = snprintf(bf, l, "\n /* XXX %d bit%s hole, "
"try to pack */", pos->bit_hole,
n = snprintf(bf, l, "\n%.*s/* XXX %d bit%s hole, "
"try to pack */", ntabs + 1, tabs,
pos->bit_hole,
pos->bit_hole != 1 ? "s" : "");
bf += n; l -= n;
sum_bit_holes += pos->bit_hole;
@ -1683,8 +1737,9 @@ static size_t class__snprintf(const struct class *self, const struct cu *cu,
n = snprintf(bf, l, "\n");
bf += n; l -= n;
}
n = snprintf(bf, l, "\n /* XXX %d byte%s "
"hole, try to pack */",
n = snprintf(bf, l, "\n%.*s/* XXX %d byte%s "
"hole, try to pack */", ntabs + 1, tabs,
pos->hole, pos->hole != 1 ? "s" : "");
bf += n; l -= n;
sum_holes += pos->hole;
@ -1711,45 +1766,55 @@ static size_t class__snprintf(const struct class *self, const struct cu *cu,
n = class__snprintf_cacheline_boundary(bf, l, last_cacheline, sum,
sum_holes, &newline,
&last_cacheline);
&last_cacheline, ntabs + 1);
bf += n; l -= n;
n = snprintf(bf, l, "}%s%s; /* size: %u, cachelines: %u */\n",
suffix ? " ": "", suffix ?: "", tself->size,
n = snprintf(bf, l, "%.*s}%s%s",
ntabs, tabs, suffix ? " ": "", suffix ?: "");
bf += n; l -= n;
if (!emit_stats)
goto out;
n = snprintf(bf, l, "; /* size: %u, cachelines: %u */\n", tself->size,
(tself->size + cacheline_size - 1) / cacheline_size);
bf += n; l -= n;
if (sum_holes > 0) {
n = snprintf(bf, l, " /* sum members: %lu, "
"holes: %d, sum holes: %lu */\n",
n = snprintf(bf, l, "%.*s /* sum members: %lu, "
"holes: %d, sum holes: %lu */\n", ntabs, tabs,
sum, self->nr_holes, sum_holes);
bf += n; l -= n;
}
if (sum_bit_holes > 0) {
n = snprintf(bf, l, " /* bit holes: %d, sum bit holes: %u bits */\n",
n = snprintf(bf, l, "%.*s /* bit holes: %d, sum "
"bit holes: %u bits */\n", ntabs, tabs,
self->nr_bit_holes, sum_bit_holes);
bf += n; l -= n;
}
if (self->padding > 0) {
n = snprintf(bf, l, " /* padding: %u */\n", self->padding);
n = snprintf(bf, l, "%.*s /* padding: %u */\n", ntabs, tabs,
self->padding);
bf += n; l -= n;
}
if (self->bit_padding > 0) {
n = snprintf(bf, l, " /* bit_padding: %u bits */\n", self->bit_padding);
n = snprintf(bf, l, "%.*s /* bit_padding: %u bits */\n",
ntabs, tabs, self->bit_padding);
bf += n; l -= n;
}
last_cacheline = tself->size % cacheline_size;
if (last_cacheline != 0) {
n = snprintf(bf, l, " /* last cacheline: %u bytes */\n", last_cacheline);
n = snprintf(bf, l, "%.*s /* last cacheline: %u bytes */\n",
ntabs, tabs, last_cacheline);
bf += n; l -= n;
}
if (sum + sum_holes != tself->size - self->padding) {
n = snprintf(bf, l, "\n/* BRAIN FART ALERT! %u != "
"%u + %u(holes), diff = %u */\n\n",
n = snprintf(bf, l, "\n%.*s/* BRAIN FART ALERT! %u != "
"%u + %u(holes), diff = %u */\n\n", ntabs, tabs,
tself->size, sum, sum_holes,
tself->size - (sum + sum_holes));
bf += n; l -= n;
}
out:
return len - l;
}
@ -1759,7 +1824,7 @@ static void class__print(const struct tag *tag, const struct cu *cu,
char bf[32768];
class__snprintf(tag__class(tag), cu, bf, sizeof(bf),
NULL, NULL, 1, 26, 23);
NULL, NULL, 0, 26, 23, 1);
fputs(bf, stdout);
}