[PAHOLE]: Handle anonymous structs
Some are just typedefs, others are inside structs and in some cases its useful to see the statistics for them, so add two new cmd line options: -a, --anon_include include anonymous classes\ -A, --nested_anon_include include nested (inside other structs) anonymous classes Commiter note: I've reworked several aspects of the patch, but mostly to give better names for the new find_first_typedef_of_type function, adding a clarifying comment and introducing --nested_anon_include so that we can select just the typedef'ed anonymous structs. Damn, I had commited just dwarves.c, here is the dwarves.h and pahole.c bits. Signed-off-by: Davi Arnaut <davi@haxent.com.br> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
9241301511
commit
c9bd654d3b
@ -267,10 +267,10 @@ extern void type__emit(struct tag *tag_self, struct cu *cu,
|
||||
|
||||
extern struct tag *cu__find_tag_by_id(const struct cu *self,
|
||||
const Dwarf_Off id);
|
||||
extern struct tag *cu__find_first_typedef_of_type(const struct cu *self,
|
||||
const Dwarf_Off type);
|
||||
extern struct tag *cu__find_struct_by_name(const struct cu *cu,
|
||||
const char *name);
|
||||
extern int tag__is_struct(const struct tag *self, struct tag **typedef_alias,
|
||||
const struct cu *cu);
|
||||
extern void cu__account_inline_expansions(struct cu *self);
|
||||
extern int cu__for_each_tag(struct cu *self,
|
||||
int (*iterator)(struct tag *tag,
|
||||
|
75
pahole.c
75
pahole.c
@ -16,6 +16,9 @@
|
||||
|
||||
#include "dwarves.h"
|
||||
|
||||
static uint8_t class__include_anonymous;
|
||||
static uint8_t class__include_nested_anonymous;
|
||||
|
||||
static char *class__exclude_prefix;
|
||||
static size_t class__exclude_prefix_len;
|
||||
|
||||
@ -59,9 +62,17 @@ static struct structure *structures__find(const char *name)
|
||||
{
|
||||
struct structure *pos;
|
||||
|
||||
list_for_each_entry(pos, &structures__list, node)
|
||||
if (strcmp(class__name(pos->class), name) == 0)
|
||||
if (name == NULL)
|
||||
return NULL;
|
||||
|
||||
list_for_each_entry(pos, &structures__list, node) {
|
||||
const char *class_name = class__name(pos->class);
|
||||
|
||||
if (class_name != NULL &&
|
||||
strcmp(class__name(pos->class), name) == 0)
|
||||
return pos;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -103,7 +114,35 @@ static void class_name_len_formatter(const struct structure *self)
|
||||
|
||||
static void class_formatter(const struct structure *self)
|
||||
{
|
||||
tag__print(class__tag(self->class), self->cu, NULL, NULL);
|
||||
struct tag *typedef_alias = NULL;
|
||||
struct tag *tag = class__tag(self->class);
|
||||
const char *name = class__name(self->class);
|
||||
|
||||
if (name == NULL) {
|
||||
/*
|
||||
* Find the first typedef for this struct, this is enough
|
||||
* as if we optimize the struct all the typedefs will be
|
||||
* affected.
|
||||
*/
|
||||
typedef_alias = cu__find_first_typedef_of_type(self->cu,
|
||||
tag->id);
|
||||
/*
|
||||
* If there is no typedefs for this anonymous struct it is
|
||||
* found just inside another struct, and in this case it'll
|
||||
* be printed when the type it is in is printed, but if
|
||||
* the user still wants to see its statistics, just use
|
||||
* --nested_anon_include.
|
||||
*/
|
||||
if (typedef_alias == NULL && !class__include_nested_anonymous)
|
||||
return;
|
||||
}
|
||||
|
||||
if (typedef_alias != NULL) {
|
||||
const struct type *tdef = tag__type(typedef_alias);
|
||||
tag__print(tag, self->cu, "typedef", tdef->name);
|
||||
} else
|
||||
tag__print(tag, self->cu, NULL, NULL);
|
||||
|
||||
printf(" /* definitions: %u */\n", self->nr_files);
|
||||
putchar('\n');
|
||||
}
|
||||
@ -197,34 +236,25 @@ static void class__chkdupdef(const struct class *self, const struct cu *cu,
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
static struct tag *tag__to_struct(struct tag *tag, const struct cu *cu)
|
||||
{
|
||||
struct tag *typedef_alias;
|
||||
|
||||
if (!tag__is_struct(tag, &typedef_alias, cu))
|
||||
return NULL;
|
||||
return typedef_alias ?: tag;
|
||||
}
|
||||
|
||||
static struct tag *tag__filter(struct tag *tag, struct cu *cu, void *cookie)
|
||||
{
|
||||
struct structure *str;
|
||||
struct class *class;
|
||||
const char *name;
|
||||
|
||||
tag = tag__to_struct(tag, cu);
|
||||
if (tag == NULL) /* Not a structure */
|
||||
if (tag->tag != DW_TAG_structure_type)
|
||||
return NULL;
|
||||
|
||||
class = tag__class(tag);
|
||||
name = class__name(class);
|
||||
if (name == NULL)
|
||||
return NULL;
|
||||
|
||||
if (class__is_declaration(class))
|
||||
return NULL;
|
||||
|
||||
if (class__exclude_prefix != NULL &&
|
||||
if (!class__include_anonymous && name == NULL)
|
||||
return NULL;
|
||||
|
||||
if (class__exclude_prefix != NULL && name &&
|
||||
strncmp(class__exclude_prefix, name,
|
||||
class__exclude_prefix_len) == 0)
|
||||
return NULL;
|
||||
@ -326,6 +356,8 @@ static struct option long_options[] = {
|
||||
{ "exclude", required_argument, NULL, 'x' },
|
||||
{ "cu_exclude", required_argument, NULL, 'X' },
|
||||
{ "decl_exclude", required_argument, NULL, 'D' },
|
||||
{ "anon_include", no_argument, NULL, 'a' },
|
||||
{ "nested_anon_include",no_argument, NULL, 'A' },
|
||||
{ "packable", no_argument, NULL, 'p' },
|
||||
{ "verbose", no_argument, NULL, 'V' },
|
||||
{ NULL, 0, NULL, 0, }
|
||||
@ -349,7 +381,10 @@ static void usage(void)
|
||||
" -D, --decl_exclude <prefix> exclude classes declared in files with prefix\n"
|
||||
" -V, --verbose be verbose\n"
|
||||
" -x, --exclude <prefix> exclude prefixed classes from reports\n"
|
||||
" -X, --cu_exclude <prefix> exclude prefixed compilation units from reports\n");
|
||||
" -X, --cu_exclude <prefix> exclude prefixed compilation units from reports\n"
|
||||
" -a, --anon_include include anonymous classes\n"
|
||||
" -A, --nested_anon_include include nested (inside other structs)\n"
|
||||
" anonymous classes\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
@ -361,7 +396,7 @@ 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, "B:c:D:hH:mnNpstVx:X:",
|
||||
while ((option = getopt_long(argc, argv, "AaB:c:D:hH:mnNpstVx:X:",
|
||||
long_options, &option_index)) >= 0)
|
||||
switch (option) {
|
||||
case 'c': cacheline_size = atoi(optarg); break;
|
||||
@ -373,6 +408,8 @@ int main(int argc, char *argv[])
|
||||
case 'm': formatter = nr_methods_formatter; break;
|
||||
case 'p': show_packable = 1; break;
|
||||
case 't': formatter = nr_definitions_formatter; break;
|
||||
case 'a': class__include_anonymous = 1; break;
|
||||
case 'A': class__include_nested_anonymous = 1; break;
|
||||
case 'D': decl_exclude_prefix = optarg;
|
||||
decl_exclude_prefix_len = strlen(decl_exclude_prefix);
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user