[PAHOLE]: Implement type expansion

What is in a struct...

[acme@filo pahole]$ pahole net/ipv6/tcp_ipv6.o delayed_work
/* <2bc9> /home/acme/git/linux-2.6/include/linux/workqueue.h:37 */
struct delayed_work {
        struct work_struct         work;                 /*     0    16 */
        struct timer_list          timer;                /*    16    24 */
}; /* size: 40, cachelines: 1 */
   /* last cacheline: 40 bytes */
[acme@filo pahole]$

Oh, but what if we want to unfold all the structs?

lo pahole]$ pahole --expand_types /home/acme/git/OUTPUT/qemu/linux-2.6/net/ipv6/tcp_ipv6.o delayed_work
/* <2bc9> /home/acme/git/linux-2.6/include/linux/workqueue.h:37 */
struct delayed_work {
        struct work_struct {
                atomic_long_t      data;                 /*   0   4 */
                struct list_head {
                        struct list_head * next;         /*   0   4 */
                        struct list_head * prev;         /*   4   4 */
                } entry;				 /*   4   8 */
                work_func_t        func;                 /*  12   4 */
        } work;						 /*   0  16 */
        struct timer_list {
                struct list_head {
                        struct list_head * next;         /*   0   4 */
                        struct list_head * prev;         /*   4   4 */
                } entry; /*     0     8 */
                long unsigned int  expires;              /*   8   4 */
                void               (*function)(long unsigned int); /*    12     4 */
                long unsigned int  data;                 /*  16   4 */
                struct tvec_t_base_s * base;             /*  20   4 */
        } timer; /*    16    24 */
}; /* size: 40, cachelines: 1 */
   /* last cacheline: 40 bytes */
[acme@filo pahole]$

Quick hack, as we already had all the needed infrastructure due to anonymous struct
printing inside structs/unions, now for the curious, if you have the kernel-debuginfo
package installed in your FC6 machine:

[acme@filo pahole]$ pahole --expand_types /usr/lib/debug/lib/modules/2.6.19-1.2895.fc6/kernel/net/ipv6/ipv6.ko.debug tcp6_sock

Try struct task_struct too 8-)

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
Arnaldo Carvalho de Melo 2007-01-29 13:12:23 -02:00
parent f426dc12f2
commit 2de67fcaf4
7 changed files with 56 additions and 36 deletions

View File

@ -301,7 +301,7 @@ static void emit_function_defs(const char *fn)
if (f != NULL) {
cus__emit_ftype_definitions(kprobes_cus, cu,
&tag__function(f)->proto);
tag__print(f, cu, NULL, NULL);
tag__print(f, cu, NULL, NULL, 0);
puts(";\n");
}
}

View File

@ -1054,17 +1054,20 @@ static struct label *label__new(Dwarf_Die *die)
static size_t union__snprintf(const struct type *self, const struct cu *cu,
char *bf, size_t len, const char *prefix,
const char *suffix, uint8_t indent,
size_t type_spacing, size_t name_spacing);
const char *suffix, uint8_t expand_types,
uint8_t indent, 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 expand_types,
uint8_t indent, 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 indent,
char *bf, size_t len,
uint8_t expand_types, size_t indent,
size_t type_spacing, size_t name_spacing)
{
char tbf[128];
@ -1094,24 +1097,25 @@ static size_t class_member__snprintf(struct class_member *self,
case DW_TAG_structure_type:
ctype = tag__type(type);
if (ctype->name != NULL)
if (ctype->name != NULL && !expand_types)
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, indent,
NULL, self->name, expand_types, indent,
type_spacing - 8, name_spacing, 0);
case DW_TAG_union_type:
ctype = tag__type(type);
if (ctype->name != NULL)
if (ctype->name != NULL && !expand_types)
return snprintf(bf, len, "union %-*s %s",
type_spacing - 6, ctype->name,
self->name);
return union__snprintf(ctype, cu, bf, len, NULL, self->name,
indent, type_spacing - 8, name_spacing);
expand_types, indent, type_spacing - 8,
name_spacing);
case DW_TAG_enumeration_type:
ctype = tag__type(type);
@ -1131,14 +1135,15 @@ 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, size_t indent,
char *bf, size_t len,
uint8_t expand_types, size_t indent,
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, indent,
type_spacing, name_spacing);
size_t n = class_member__snprintf(self, type, cu, bf, l, expand_types,
indent, type_spacing, name_spacing);
bf += n; l -= n;
if (self->bit_size != 0)
@ -1168,14 +1173,15 @@ static size_t struct_member__snprintf(struct class_member *self,
static size_t union_member__snprintf(struct class_member *self,
struct tag *type, const struct cu *cu,
char *bf, size_t len, size_t indent,
char *bf, size_t len,
uint8_t expand_types, size_t indent,
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, indent,
type_spacing, name_spacing);
size_t n = class_member__snprintf(self, type, cu, bf, l, expand_types,
indent, type_spacing, name_spacing);
bf += n; l -= n;
if ((type->tag == DW_TAG_union_type ||
@ -1197,8 +1203,9 @@ static size_t union_member__snprintf(struct class_member *self,
static size_t union__snprintf(const struct type *self, const struct cu *cu,
char *bf, size_t len, const char *prefix,
const char *suffix, uint8_t indent,
size_t type_spacing, size_t name_spacing)
const char *suffix, uint8_t expand_types,
uint8_t indent, size_t type_spacing,
size_t name_spacing)
{
struct class_member *pos;
char *s = bf;
@ -1220,7 +1227,8 @@ static size_t union__snprintf(const struct type *self, const struct cu *cu,
n = snprintf(s, l, "%.*s", indent + 1, tabs);
s += n; l -= n;
n = union_member__snprintf(pos, type, cu, s, l, indent + 1,
n = union_member__snprintf(pos, type, cu, s, l, expand_types,
indent + 1,
type_spacing, name_spacing);
s += n; l -= n;
n = snprintf(s, l, "\n");
@ -1234,12 +1242,14 @@ static size_t union__snprintf(const struct type *self, const struct cu *cu,
}
static void union__print(const struct tag *tag, const struct cu *cu,
const char *prefix, const char *suffix)
const char *prefix, const char *suffix,
uint8_t expand_types)
{
const struct type *utype = tag__type(tag);
char bf[32768];
union__snprintf(utype, cu, bf, sizeof(bf), prefix, suffix, 0, 26, 23);
union__snprintf(utype, cu, bf, sizeof(bf), prefix, suffix,
expand_types, 0, 26, 23);
fputs(bf, stdout);
}
@ -1762,6 +1772,7 @@ static size_t class__snprintf_cacheline_boundary(char *bf, size_t len,
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 expand_types,
uint8_t indent, size_t type_spacing,
size_t name_spacing, int emit_stats)
{
@ -1855,7 +1866,8 @@ static size_t class__snprintf(const struct class *self, const struct cu *cu,
size = tag__size(type, cu);
n = snprintf(bf, l, "%.*s", indent + 1, tabs);
bf += n; l -= n;
n = struct_member__snprintf(pos, type, cu, bf, l, indent + 1,
n = struct_member__snprintf(pos, type, cu, bf, l,
expand_types, indent + 1,
type_spacing, name_spacing);
bf += n; l -= n;
@ -1983,17 +1995,19 @@ out:
}
static void class__print(const struct tag *tag, const struct cu *cu,
const char *prefix, const char *suffix)
const char *prefix, const char *suffix,
uint8_t expand_types)
{
char bf[32768];
class__snprintf(tag__class(tag), cu, bf, sizeof(bf),
prefix, suffix, 0, 26, 23, 1);
prefix, suffix, expand_types, 0, 26, 23, 1);
fputs(bf, stdout);
}
void tag__print(const struct tag *self, const struct cu *cu,
const char *prefix, const char *suffix)
const char *prefix, const char *suffix,
uint8_t expand_types)
{
tag__print_decl_info(self);
@ -2005,13 +2019,13 @@ void tag__print(const struct tag *self, const struct cu *cu,
typedef__print(self, cu);
break;
case DW_TAG_structure_type:
class__print(self, cu, prefix, suffix);
class__print(self, cu, prefix, suffix, expand_types);
break;
case DW_TAG_subprogram:
function__print(self, cu);
break;
case DW_TAG_union_type:
union__print(self, cu, prefix, suffix);
union__print(self, cu, prefix, suffix, expand_types);
break;
default:
printf("%s: %s tag not supported!\n", __FUNCTION__,
@ -2813,7 +2827,7 @@ void type__emit(struct tag *tag_self, struct cu *cu,
class__find_holes(tag__class(tag_self), cu);
if (ctype->name != NULL || suffix != NULL || prefix != NULL) {
tag__print(tag_self, cu, prefix, suffix);
tag__print(tag_self, cu, prefix, suffix, 0);
if (tag_self->tag != DW_TAG_structure_type)
putchar(';');

View File

@ -240,7 +240,8 @@ extern void dwarves__init(size_t user_cacheline_size);
extern void class__find_holes(struct class *self, const struct cu *cu);
extern void tag__print(const struct tag *self, const struct cu *cu,
const char *prefix, const char *suffix);
const char *prefix, const char *suffix,
uint8_t expand_types);
extern const char *function__name(struct function *self, const struct cu *cu);
extern void function__print_stats(const struct tag *tag_self,

View File

@ -33,6 +33,7 @@ static uint16_t nr_holes;
static uint16_t nr_bit_holes;
static uint8_t show_packable;
static uint8_t verbose;
static uint8_t expand_types;
struct structure {
struct list_head node;
@ -140,9 +141,9 @@ static void class_formatter(const struct structure *self)
if (typedef_alias != NULL) {
const struct type *tdef = tag__type(typedef_alias);
tag__print(tag, self->cu, "typedef", tdef->name);
tag__print(tag, self->cu, "typedef", tdef->name, expand_types);
} else
tag__print(tag, self->cu, NULL, NULL);
tag__print(tag, self->cu, NULL, NULL, expand_types);
printf(" /* definitions: %u */\n", self->nr_files);
putchar('\n');
@ -359,6 +360,7 @@ static struct option long_options[] = {
{ "nr_definitions", no_argument, NULL, 't' },
{ "nr_methods", no_argument, NULL, 'm' },
{ "exclude", required_argument, NULL, 'x' },
{ "expand_types", no_argument, NULL, 'e' },
{ "cu_exclude", required_argument, NULL, 'X' },
{ "decl_exclude", required_argument, NULL, 'D' },
{ "anon_include", no_argument, NULL, 'a' },
@ -381,6 +383,7 @@ static void usage(void)
" -p, --packable show only structs that has "
"holes that can be packed\n"
" -c, --cacheline_size <size> set cacheline size\n"
" -e, --expand_types expand class members\n"
" -n, --nr_members show number of members\n"
" -N, --class_name_len show size of classes\n"
" -m, --nr_methods show number of methods\n"
@ -408,12 +411,13 @@ int main(int argc, char *argv[])
size_t cacheline_size = 0;
void (*formatter)(const struct structure *s) = class_formatter;
while ((option = getopt_long(argc, argv, "AaB:c:D:hH:mnNpstVx:X:",
while ((option = getopt_long(argc, argv, "AaB:c:D:ehH:mnNpstVx:X:",
long_options, &option_index)) >= 0)
switch (option) {
case 'c': cacheline_size = atoi(optarg); break;
case 'H': nr_holes = atoi(optarg); break;
case 'B': nr_bit_holes = atoi(optarg); break;
case 'e': expand_types = 1; break;
case 's': formatter = size_formatter; break;
case 'n': formatter = nr_members_formatter; break;
case 'N': formatter = class_name_len_formatter; break;
@ -473,7 +477,8 @@ int main(int argc, char *argv[])
printf("struct %s not found!\n", class_name);
return EXIT_FAILURE;
}
tag__print(class__tag(s->class), s->cu, NULL, NULL);
tag__print(class__tag(s->class), s->cu, NULL, NULL,
expand_types);
} else
print_classes(formatter);

View File

@ -25,7 +25,7 @@ static int emit_tag(struct tag *self, struct cu *cu, void *cookie __unused)
if (self->tag == DW_TAG_structure_type)
class__find_holes(tag__class(self), cu);
tag__print(self, cu, NULL, NULL);
tag__print(self, cu, NULL, NULL, 0);
if (self->tag == DW_TAG_subprogram) {
const struct function *fn = tag__function(self);

View File

@ -120,7 +120,7 @@ static void fn_stats_size_fmtr(const struct fn_stats *self)
static void fn_stats_fmtr(const struct fn_stats *self)
{
if (verbose) {
tag__print(self->tag, self->cu, NULL, NULL);
tag__print(self->tag, self->cu, NULL, NULL, 0);
putchar('\n');
if (show_variables || show_inline_expansions)
function__print_stats(self->tag, self->cu);
@ -276,7 +276,7 @@ static int class_iterator(struct tag *tag, struct cu *cu, void *cookie)
if (ftype__has_parm_of_type(&function->proto, cookie, cu)) {
if (verbose)
tag__print(tag, cu, NULL, NULL);
tag__print(tag, cu, NULL, NULL, 0);
else
fputs(function__name(function, cu), stdout);
putchar('\n');
@ -303,7 +303,7 @@ static int function_iterator(struct tag *tag, struct cu *cu, void *cookie)
function = tag__function(tag);
if (strcmp(function__name(function, cu), cookie) == 0) {
tag__print(tag, cu, NULL, NULL);
tag__print(tag, cu, NULL, NULL, 0);
putchar('\n');
if (show_variables || show_inline_expansions)
function__print_stats(tag, cu);

View File

@ -141,7 +141,7 @@ static int lost_iterator(struct tag *tag, struct cu *cu,
void *cookie __unused)
{
if (tag->refcnt == 0 && tag->decl_file != NULL)
tag__print(tag, cu, NULL, NULL);
tag__print(tag, cu, NULL, NULL, 0);
return 0;
}