2006-10-29 00:07:45 +02:00
|
|
|
/*
|
|
|
|
Copyright (C) 2006 Mandriva Conectiva S.A.
|
|
|
|
Copyright (C) 2006 Arnaldo Carvalho de Melo <acme@mandriva.com>
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it
|
|
|
|
under the terms of version 2 of the GNU General Public License as
|
|
|
|
published by the Free Software Foundation.
|
|
|
|
*/
|
|
|
|
|
Add getopt support in pfunct, options implemented should be self explaining,
except for --classes, that asks that all non-inlined functions that receive as
one of its parameter a pointer to the specified class be printed, just the name
if --verbose is not used, or its complete prototype and where it is in the
source code:
[acme@newtoy net-2.6]$ pfunct --verbose --class=inode fs/ext3/built-in.o
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 606 */
void ext3_free_blocks(handle_t * handle, struct inode * inode, ext3_fsblk_t block, long unsigned int count);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 1404 */
ext3_fsblk_t ext3_new_blocks(handle_t * handle, struct inode * inode, ext3_fsblk_t goal, long unsigned int * count, int * errp);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 1668 */
ext3_fsblk_t ext3_new_block(handle_t * handle, struct inode * inode, ext3_fsblk_t goal, int * errp);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 346 */
void ext3_init_block_alloc_info(struct inode * inode);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 388 */
void ext3_discard_reservation(struct inode * inode);
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-10-29 04:41:48 +01:00
|
|
|
#include <getopt.h>
|
2006-12-18 18:43:17 +01:00
|
|
|
#include <stdarg.h>
|
Add getopt support in pfunct, options implemented should be self explaining,
except for --classes, that asks that all non-inlined functions that receive as
one of its parameter a pointer to the specified class be printed, just the name
if --verbose is not used, or its complete prototype and where it is in the
source code:
[acme@newtoy net-2.6]$ pfunct --verbose --class=inode fs/ext3/built-in.o
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 606 */
void ext3_free_blocks(handle_t * handle, struct inode * inode, ext3_fsblk_t block, long unsigned int count);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 1404 */
ext3_fsblk_t ext3_new_blocks(handle_t * handle, struct inode * inode, ext3_fsblk_t goal, long unsigned int * count, int * errp);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 1668 */
ext3_fsblk_t ext3_new_block(handle_t * handle, struct inode * inode, ext3_fsblk_t goal, int * errp);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 346 */
void ext3_init_block_alloc_info(struct inode * inode);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 388 */
void ext3_discard_reservation(struct inode * inode);
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-10-29 04:41:48 +01:00
|
|
|
#include <stdio.h>
|
2006-10-29 00:07:45 +02:00
|
|
|
#include <stdlib.h>
|
2006-11-01 14:42:18 +01:00
|
|
|
#include <string.h>
|
2006-10-29 00:07:45 +02:00
|
|
|
|
|
|
|
#include "classes.h"
|
|
|
|
|
Add getopt support in pfunct, options implemented should be self explaining,
except for --classes, that asks that all non-inlined functions that receive as
one of its parameter a pointer to the specified class be printed, just the name
if --verbose is not used, or its complete prototype and where it is in the
source code:
[acme@newtoy net-2.6]$ pfunct --verbose --class=inode fs/ext3/built-in.o
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 606 */
void ext3_free_blocks(handle_t * handle, struct inode * inode, ext3_fsblk_t block, long unsigned int count);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 1404 */
ext3_fsblk_t ext3_new_blocks(handle_t * handle, struct inode * inode, ext3_fsblk_t goal, long unsigned int * count, int * errp);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 1668 */
ext3_fsblk_t ext3_new_block(handle_t * handle, struct inode * inode, ext3_fsblk_t goal, int * errp);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 346 */
void ext3_init_block_alloc_info(struct inode * inode);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 388 */
void ext3_discard_reservation(struct inode * inode);
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-10-29 04:41:48 +01:00
|
|
|
static int verbose;
|
2006-11-03 16:41:19 +01:00
|
|
|
static int show_inline_expansions;
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
static int show_variables;
|
2006-12-18 18:43:17 +01:00
|
|
|
static int show_externals;
|
|
|
|
static int show_cc_inlined;
|
|
|
|
static int show_cc_uninlined;
|
2006-11-03 20:14:25 +01:00
|
|
|
|
2006-12-18 18:43:17 +01:00
|
|
|
struct fn_stats {
|
2006-11-03 20:14:25 +01:00
|
|
|
struct list_head node;
|
2006-12-18 18:43:17 +01:00
|
|
|
const struct function *function;
|
2006-11-03 20:14:25 +01:00
|
|
|
unsigned long nr_expansions;
|
|
|
|
unsigned long size_expansions;
|
|
|
|
unsigned int nr_files;
|
|
|
|
};
|
|
|
|
|
2006-12-19 09:03:31 +01:00
|
|
|
static struct fn_stats *fn_stats__new(const struct function *function)
|
2006-11-03 20:14:25 +01:00
|
|
|
{
|
2006-12-18 18:43:17 +01:00
|
|
|
struct fn_stats *self = malloc(sizeof(*self));
|
2006-11-03 20:14:25 +01:00
|
|
|
|
|
|
|
if (self != NULL) {
|
2006-12-18 18:43:17 +01:00
|
|
|
self->function = function;
|
2006-11-03 20:14:25 +01:00
|
|
|
self->nr_files = 1;
|
2006-11-18 17:33:48 +01:00
|
|
|
self->nr_expansions = function->cu_total_nr_inline_expansions;
|
|
|
|
self->size_expansions = function->cu_total_size_inline_expansions;
|
2006-11-03 20:14:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2006-12-18 18:43:17 +01:00
|
|
|
static LIST_HEAD(fn_stats__list);
|
2006-11-03 20:14:25 +01:00
|
|
|
|
2006-12-18 18:43:17 +01:00
|
|
|
static struct fn_stats *fn_stats__find(const char *name)
|
2006-11-03 20:14:25 +01:00
|
|
|
{
|
2006-12-18 18:43:17 +01:00
|
|
|
struct fn_stats *pos;
|
2006-11-03 20:14:25 +01:00
|
|
|
|
2006-12-18 18:43:17 +01:00
|
|
|
list_for_each_entry(pos, &fn_stats__list, node)
|
|
|
|
if (strcmp(pos->function->name, name) == 0)
|
2006-11-03 20:14:25 +01:00
|
|
|
return pos;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2006-12-18 18:43:17 +01:00
|
|
|
static void fn_stats__add(const struct function *function)
|
2006-11-03 20:14:25 +01:00
|
|
|
{
|
2006-12-18 18:43:17 +01:00
|
|
|
struct fn_stats *inl = fn_stats__new(function);
|
|
|
|
if (inl != NULL)
|
|
|
|
list_add(&inl->node, &fn_stats__list);
|
|
|
|
}
|
2006-11-03 20:14:25 +01:00
|
|
|
|
2006-12-18 18:43:17 +01:00
|
|
|
static void fn_stats_inline_exps_fmtr(const struct fn_stats *self)
|
|
|
|
{
|
|
|
|
if (self->function->lexblock.nr_inline_expansions > 0)
|
|
|
|
printf("%s: %u %u\n", self->function->name,
|
|
|
|
self->function->lexblock.nr_inline_expansions,
|
|
|
|
self->function->lexblock.size_inline_expansions);
|
2006-11-03 20:14:25 +01:00
|
|
|
}
|
|
|
|
|
2006-12-18 18:43:17 +01:00
|
|
|
static void fn_stats_labels_fmtr(const struct fn_stats *self)
|
2006-11-03 20:14:25 +01:00
|
|
|
{
|
2006-12-18 18:43:17 +01:00
|
|
|
if (self->function->lexblock.nr_labels > 0)
|
|
|
|
printf("%s: %u\n", self->function->name,
|
|
|
|
self->function->lexblock.nr_labels);
|
2006-11-03 20:14:25 +01:00
|
|
|
}
|
|
|
|
|
2006-12-18 18:43:17 +01:00
|
|
|
static void fn_stats_variables_fmtr(const struct fn_stats *self)
|
|
|
|
{
|
|
|
|
if (self->function->lexblock.nr_variables > 0)
|
|
|
|
printf("%s: %u\n", self->function->name,
|
|
|
|
self->function->lexblock.nr_variables);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void fn_stats_nr_parms_fmtr(const struct fn_stats *self)
|
|
|
|
{
|
|
|
|
printf("%s: %u\n", self->function->name, self->function->nr_parameters);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void fn_stats_name_len_fmtr(const struct fn_stats *self)
|
|
|
|
{
|
|
|
|
printf("%s: %u\n", self->function->name, strlen(self->function->name));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void fn_stats_size_fmtr(const struct fn_stats *self)
|
|
|
|
{
|
|
|
|
const size_t size = function__size(self->function);
|
|
|
|
if (size != 0)
|
|
|
|
printf("%s: %u\n", self->function->name, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void fn_stats_fmtr(const struct fn_stats *self)
|
|
|
|
{
|
|
|
|
if (verbose) {
|
|
|
|
function__print(self->function, 1, show_variables, show_inline_expansions);
|
|
|
|
printf("/* definitions: %u */\n", self->nr_files);
|
|
|
|
putchar('\n');
|
|
|
|
} else
|
|
|
|
puts(self->function->name);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void print_fn_stats(void (*formatter)(const struct fn_stats *f))
|
2006-11-03 20:14:25 +01:00
|
|
|
{
|
2006-12-18 18:43:17 +01:00
|
|
|
struct fn_stats *pos;
|
2006-11-03 20:14:25 +01:00
|
|
|
|
2006-12-18 18:43:17 +01:00
|
|
|
list_for_each_entry(pos, &fn_stats__list, node)
|
|
|
|
formatter(pos);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void fn_stats_inline_stats_fmtr(const struct fn_stats *self)
|
|
|
|
{
|
|
|
|
if (self->nr_expansions > 1)
|
|
|
|
printf("%-31.31s %6lu %7lu %6lu %6u\n", self->function->name,
|
|
|
|
self->size_expansions, self->nr_expansions,
|
|
|
|
self->size_expansions / self->nr_expansions,
|
|
|
|
self->nr_files);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void print_total_inline_stats(void)
|
|
|
|
{
|
2006-12-19 09:03:31 +01:00
|
|
|
printf("%-32.32s %5.5s / %5.5s = %5.5s %s\n",
|
|
|
|
"name", "totsz", "exp#", "avgsz", "src#");
|
2006-12-18 18:43:17 +01:00
|
|
|
print_fn_stats(fn_stats_inline_stats_fmtr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void fn_stats__dupmsg(const struct function *self,
|
|
|
|
const struct function *dup, char *hdr,
|
|
|
|
const char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
if (!*hdr)
|
|
|
|
printf("function: %s\nfirst: %s\ncurrent: %s\n",
|
|
|
|
self->name, self->cu->name, dup->cu->name);
|
|
|
|
|
|
|
|
va_start(args, fmt);
|
|
|
|
vprintf(fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
*hdr = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void fn_stats__chkdupdef(const struct function *self,
|
|
|
|
const struct function *dup)
|
|
|
|
{
|
|
|
|
char hdr = 0;
|
|
|
|
const size_t self_size = function__size(self);
|
|
|
|
const size_t dup_size = function__size(dup);
|
|
|
|
|
|
|
|
if (self_size != dup_size)
|
|
|
|
fn_stats__dupmsg(self, dup, &hdr, "size: %zd != %zd\n",
|
|
|
|
self_size, dup_size);
|
|
|
|
|
|
|
|
if (self->nr_parameters != dup->nr_parameters)
|
|
|
|
fn_stats__dupmsg(self, dup, &hdr,
|
|
|
|
"nr_parameters: %u != %u\n",
|
|
|
|
self->nr_parameters,
|
|
|
|
dup->nr_parameters);
|
|
|
|
|
|
|
|
/* XXX put more checks here: member types, member ordering, etc */
|
|
|
|
|
|
|
|
if (hdr)
|
|
|
|
putchar('\n');
|
|
|
|
}
|
|
|
|
|
2006-12-20 15:05:29 +01:00
|
|
|
static struct function *function__filter(struct function *function,
|
|
|
|
void *cookie)
|
2006-12-18 18:43:17 +01:00
|
|
|
{
|
|
|
|
struct fn_stats *fstats;
|
|
|
|
|
|
|
|
if (function->name == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (show_externals && !function->external)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (show_cc_uninlined &&
|
|
|
|
function->inlined != DW_INL_declared_not_inlined)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (show_cc_inlined && function->inlined != DW_INL_inlined)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
fstats = fn_stats__find(function->name);
|
|
|
|
if (fstats != NULL && fstats->function->external) {
|
|
|
|
fn_stats__chkdupdef(fstats->function, function);
|
|
|
|
fstats->nr_expansions += function->cu_total_nr_inline_expansions;
|
|
|
|
fstats->size_expansions += function->cu_total_size_inline_expansions;
|
|
|
|
fstats->nr_files++;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return function;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int unique_iterator(struct function *function, void *cookie)
|
|
|
|
{
|
|
|
|
fn_stats__add(function);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cu_unique_iterator(struct cu *cu, void *cookie)
|
|
|
|
{
|
|
|
|
cu__account_inline_expansions(cu);
|
|
|
|
return cu__for_each_function(cu, unique_iterator, cookie,
|
|
|
|
function__filter);
|
2006-11-03 20:14:25 +01:00
|
|
|
}
|
Add getopt support in pfunct, options implemented should be self explaining,
except for --classes, that asks that all non-inlined functions that receive as
one of its parameter a pointer to the specified class be printed, just the name
if --verbose is not used, or its complete prototype and where it is in the
source code:
[acme@newtoy net-2.6]$ pfunct --verbose --class=inode fs/ext3/built-in.o
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 606 */
void ext3_free_blocks(handle_t * handle, struct inode * inode, ext3_fsblk_t block, long unsigned int count);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 1404 */
ext3_fsblk_t ext3_new_blocks(handle_t * handle, struct inode * inode, ext3_fsblk_t goal, long unsigned int * count, int * errp);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 1668 */
ext3_fsblk_t ext3_new_block(handle_t * handle, struct inode * inode, ext3_fsblk_t goal, int * errp);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 346 */
void ext3_init_block_alloc_info(struct inode * inode);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 388 */
void ext3_discard_reservation(struct inode * inode);
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-10-29 04:41:48 +01:00
|
|
|
|
2006-11-18 17:33:48 +01:00
|
|
|
static int class_iterator(struct function *function, void *cookie)
|
Add getopt support in pfunct, options implemented should be self explaining,
except for --classes, that asks that all non-inlined functions that receive as
one of its parameter a pointer to the specified class be printed, just the name
if --verbose is not used, or its complete prototype and where it is in the
source code:
[acme@newtoy net-2.6]$ pfunct --verbose --class=inode fs/ext3/built-in.o
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 606 */
void ext3_free_blocks(handle_t * handle, struct inode * inode, ext3_fsblk_t block, long unsigned int count);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 1404 */
ext3_fsblk_t ext3_new_blocks(handle_t * handle, struct inode * inode, ext3_fsblk_t goal, long unsigned int * count, int * errp);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 1668 */
ext3_fsblk_t ext3_new_block(handle_t * handle, struct inode * inode, ext3_fsblk_t goal, int * errp);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 346 */
void ext3_init_block_alloc_info(struct inode * inode);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 388 */
void ext3_discard_reservation(struct inode * inode);
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-10-29 04:41:48 +01:00
|
|
|
{
|
2006-11-18 17:33:48 +01:00
|
|
|
if (function->inlined)
|
Add getopt support in pfunct, options implemented should be self explaining,
except for --classes, that asks that all non-inlined functions that receive as
one of its parameter a pointer to the specified class be printed, just the name
if --verbose is not used, or its complete prototype and where it is in the
source code:
[acme@newtoy net-2.6]$ pfunct --verbose --class=inode fs/ext3/built-in.o
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 606 */
void ext3_free_blocks(handle_t * handle, struct inode * inode, ext3_fsblk_t block, long unsigned int count);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 1404 */
ext3_fsblk_t ext3_new_blocks(handle_t * handle, struct inode * inode, ext3_fsblk_t goal, long unsigned int * count, int * errp);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 1668 */
ext3_fsblk_t ext3_new_block(handle_t * handle, struct inode * inode, ext3_fsblk_t goal, int * errp);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 346 */
void ext3_init_block_alloc_info(struct inode * inode);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 388 */
void ext3_discard_reservation(struct inode * inode);
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-10-29 04:41:48 +01:00
|
|
|
return 0;
|
|
|
|
|
2006-11-18 17:33:48 +01:00
|
|
|
if (function__has_parameter_of_type(function, cookie)) {
|
Add getopt support in pfunct, options implemented should be self explaining,
except for --classes, that asks that all non-inlined functions that receive as
one of its parameter a pointer to the specified class be printed, just the name
if --verbose is not used, or its complete prototype and where it is in the
source code:
[acme@newtoy net-2.6]$ pfunct --verbose --class=inode fs/ext3/built-in.o
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 606 */
void ext3_free_blocks(handle_t * handle, struct inode * inode, ext3_fsblk_t block, long unsigned int count);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 1404 */
ext3_fsblk_t ext3_new_blocks(handle_t * handle, struct inode * inode, ext3_fsblk_t goal, long unsigned int * count, int * errp);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 1668 */
ext3_fsblk_t ext3_new_block(handle_t * handle, struct inode * inode, ext3_fsblk_t goal, int * errp);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 346 */
void ext3_init_block_alloc_info(struct inode * inode);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 388 */
void ext3_discard_reservation(struct inode * inode);
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-10-29 04:41:48 +01:00
|
|
|
if (verbose)
|
2006-11-20 18:43:39 +01:00
|
|
|
function__print(function, 1, 0, 0);
|
Add getopt support in pfunct, options implemented should be self explaining,
except for --classes, that asks that all non-inlined functions that receive as
one of its parameter a pointer to the specified class be printed, just the name
if --verbose is not used, or its complete prototype and where it is in the
source code:
[acme@newtoy net-2.6]$ pfunct --verbose --class=inode fs/ext3/built-in.o
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 606 */
void ext3_free_blocks(handle_t * handle, struct inode * inode, ext3_fsblk_t block, long unsigned int count);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 1404 */
ext3_fsblk_t ext3_new_blocks(handle_t * handle, struct inode * inode, ext3_fsblk_t goal, long unsigned int * count, int * errp);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 1668 */
ext3_fsblk_t ext3_new_block(handle_t * handle, struct inode * inode, ext3_fsblk_t goal, int * errp);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 346 */
void ext3_init_block_alloc_info(struct inode * inode);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 388 */
void ext3_discard_reservation(struct inode * inode);
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-10-29 04:41:48 +01:00
|
|
|
else
|
2006-11-18 17:33:48 +01:00
|
|
|
printf("%s\n", function->name ?: "");
|
Add getopt support in pfunct, options implemented should be self explaining,
except for --classes, that asks that all non-inlined functions that receive as
one of its parameter a pointer to the specified class be printed, just the name
if --verbose is not used, or its complete prototype and where it is in the
source code:
[acme@newtoy net-2.6]$ pfunct --verbose --class=inode fs/ext3/built-in.o
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 606 */
void ext3_free_blocks(handle_t * handle, struct inode * inode, ext3_fsblk_t block, long unsigned int count);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 1404 */
ext3_fsblk_t ext3_new_blocks(handle_t * handle, struct inode * inode, ext3_fsblk_t goal, long unsigned int * count, int * errp);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 1668 */
ext3_fsblk_t ext3_new_block(handle_t * handle, struct inode * inode, ext3_fsblk_t goal, int * errp);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 346 */
void ext3_init_block_alloc_info(struct inode * inode);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 388 */
void ext3_discard_reservation(struct inode * inode);
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-10-29 04:41:48 +01:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-10-31 21:23:16 +01:00
|
|
|
static int cu_class_iterator(struct cu *cu, void *cookie)
|
|
|
|
{
|
|
|
|
struct class *target = cu__find_class_by_name(cu, cookie);
|
|
|
|
|
|
|
|
if (target == NULL)
|
|
|
|
return 0;
|
|
|
|
|
2006-12-18 18:43:17 +01:00
|
|
|
return cu__for_each_function(cu, class_iterator, target, NULL);
|
2006-11-01 14:18:01 +01:00
|
|
|
}
|
|
|
|
|
2006-11-18 17:33:48 +01:00
|
|
|
static int function_iterator(struct function *function, void *cookie)
|
2006-10-31 21:23:16 +01:00
|
|
|
{
|
2006-12-18 18:43:17 +01:00
|
|
|
if (function->name != NULL &&
|
|
|
|
strcmp(function->name, cookie) == 0) {
|
2006-11-20 18:43:39 +01:00
|
|
|
function__print(function, 1, show_variables,
|
|
|
|
show_inline_expansions);
|
2006-10-31 21:23:16 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cu_function_iterator(struct cu *cu, void *cookie)
|
|
|
|
{
|
2006-12-18 18:43:17 +01:00
|
|
|
return cu__for_each_function(cu, function_iterator, cookie, NULL);
|
2006-11-18 22:08:37 +01:00
|
|
|
}
|
|
|
|
|
2006-12-19 09:03:31 +01:00
|
|
|
static struct option long_options[] = {
|
|
|
|
{ "class", required_argument, NULL, 'c' },
|
|
|
|
{ "externals", no_argument, NULL, 'e' },
|
|
|
|
{ "cc_inlined", no_argument, NULL, 'H' },
|
|
|
|
{ "cc_uninlined", no_argument, NULL, 'G' },
|
|
|
|
{ "function_name_len", no_argument, NULL, 'N' },
|
|
|
|
{ "goto_labels", no_argument, NULL, 'g' },
|
|
|
|
{ "inline_expansions", no_argument, NULL, 'i' },
|
|
|
|
{ "inline_expansions_stats", no_argument, NULL, 'I' },
|
|
|
|
{ "total_inline_stats", no_argument, NULL, 't' },
|
|
|
|
{ "help", no_argument, NULL, 'h' },
|
|
|
|
{ "nr_parameters", no_argument, NULL, 'p' },
|
|
|
|
{ "sizes", no_argument, NULL, 's' },
|
|
|
|
{ "nr_variables", no_argument, NULL, 'S' },
|
|
|
|
{ "variables", no_argument, NULL, 'T' },
|
|
|
|
{ "verbose", no_argument, NULL, 'V' },
|
|
|
|
{ NULL, 0, NULL, 0, }
|
|
|
|
};
|
|
|
|
|
|
|
|
static void usage(void)
|
|
|
|
{
|
|
|
|
fprintf(stdout,
|
|
|
|
"usage: pfunct [options] <file_name> {<function_name>}\n"
|
|
|
|
" where: \n"
|
|
|
|
" -c, --class=<class> functions that have "
|
|
|
|
"<class> pointer "
|
|
|
|
"parameters\n"
|
|
|
|
" -e, --externals show just external "
|
|
|
|
"functions\n"
|
|
|
|
" -g, --goto_labels show number of goto "
|
|
|
|
"labels\n"
|
|
|
|
" -G, --cc_uninlined declared inline, "
|
|
|
|
"uninlined by compiler\n"
|
|
|
|
" -H, --cc_inlined not declared inline, "
|
|
|
|
"inlined by compiler\n"
|
|
|
|
" -i, --inline_expansions show inline expansions\n"
|
|
|
|
" -I, --inline_expansions_stats show inline expansions "
|
|
|
|
"stats\n"
|
|
|
|
" -t, --total_inline_stats show Multi-CU total "
|
|
|
|
"inline expansions "
|
|
|
|
"stats\n"
|
|
|
|
" -s, --sizes show size of functions\n"
|
|
|
|
" -N, --function_name_len show size of functions\n"
|
|
|
|
" -p, --nr_parameters show number of "
|
|
|
|
"parameters\n"
|
|
|
|
" -S, --nr_variables show number of "
|
|
|
|
"variables\n"
|
|
|
|
" -T, --variables show variables\n"
|
|
|
|
" -V, --verbose be verbose\n");
|
|
|
|
}
|
|
|
|
|
2006-10-29 00:07:45 +02:00
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
Add getopt support in pfunct, options implemented should be self explaining,
except for --classes, that asks that all non-inlined functions that receive as
one of its parameter a pointer to the specified class be printed, just the name
if --verbose is not used, or its complete prototype and where it is in the
source code:
[acme@newtoy net-2.6]$ pfunct --verbose --class=inode fs/ext3/built-in.o
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 606 */
void ext3_free_blocks(handle_t * handle, struct inode * inode, ext3_fsblk_t block, long unsigned int count);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 1404 */
ext3_fsblk_t ext3_new_blocks(handle_t * handle, struct inode * inode, ext3_fsblk_t goal, long unsigned int * count, int * errp);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 1668 */
ext3_fsblk_t ext3_new_block(handle_t * handle, struct inode * inode, ext3_fsblk_t goal, int * errp);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 346 */
void ext3_init_block_alloc_info(struct inode * inode);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 388 */
void ext3_discard_reservation(struct inode * inode);
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-10-29 04:41:48 +01:00
|
|
|
int option, option_index;
|
2006-11-11 17:15:50 +01:00
|
|
|
const char *file_name;
|
2006-11-11 19:31:04 +01:00
|
|
|
struct cus *cus;
|
2006-10-31 21:23:16 +01:00
|
|
|
char *class_name = NULL;
|
|
|
|
char *function_name = NULL;
|
2006-11-04 04:11:04 +01:00
|
|
|
int show_total_inline_expansion_stats = 0;
|
2006-12-18 18:43:17 +01:00
|
|
|
void (*formatter)(const struct fn_stats *f) = fn_stats_fmtr;
|
Add getopt support in pfunct, options implemented should be self explaining,
except for --classes, that asks that all non-inlined functions that receive as
one of its parameter a pointer to the specified class be printed, just the name
if --verbose is not used, or its complete prototype and where it is in the
source code:
[acme@newtoy net-2.6]$ pfunct --verbose --class=inode fs/ext3/built-in.o
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 606 */
void ext3_free_blocks(handle_t * handle, struct inode * inode, ext3_fsblk_t block, long unsigned int count);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 1404 */
ext3_fsblk_t ext3_new_blocks(handle_t * handle, struct inode * inode, ext3_fsblk_t goal, long unsigned int * count, int * errp);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 1668 */
ext3_fsblk_t ext3_new_block(handle_t * handle, struct inode * inode, ext3_fsblk_t goal, int * errp);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 346 */
void ext3_init_block_alloc_info(struct inode * inode);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 388 */
void ext3_discard_reservation(struct inode * inode);
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-10-29 04:41:48 +01:00
|
|
|
|
2006-12-18 18:43:17 +01:00
|
|
|
while ((option = getopt_long(argc, argv, "c:egGHiINpsStTV",
|
Add getopt support in pfunct, options implemented should be self explaining,
except for --classes, that asks that all non-inlined functions that receive as
one of its parameter a pointer to the specified class be printed, just the name
if --verbose is not used, or its complete prototype and where it is in the
source code:
[acme@newtoy net-2.6]$ pfunct --verbose --class=inode fs/ext3/built-in.o
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 606 */
void ext3_free_blocks(handle_t * handle, struct inode * inode, ext3_fsblk_t block, long unsigned int count);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 1404 */
ext3_fsblk_t ext3_new_blocks(handle_t * handle, struct inode * inode, ext3_fsblk_t goal, long unsigned int * count, int * errp);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 1668 */
ext3_fsblk_t ext3_new_block(handle_t * handle, struct inode * inode, ext3_fsblk_t goal, int * errp);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 346 */
void ext3_init_block_alloc_info(struct inode * inode);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 388 */
void ext3_discard_reservation(struct inode * inode);
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-10-29 04:41:48 +01:00
|
|
|
long_options, &option_index)) >= 0)
|
|
|
|
switch (option) {
|
2006-11-03 16:41:19 +01:00
|
|
|
case 'c': class_name = optarg; break;
|
2006-11-18 02:43:08 +01:00
|
|
|
case 'e': show_externals = 1; break;
|
2006-12-18 18:43:17 +01:00
|
|
|
case 's': formatter = fn_stats_size_fmtr; break;
|
|
|
|
case 'S': formatter = fn_stats_variables_fmtr; break;
|
|
|
|
case 'p': formatter = fn_stats_nr_parms_fmtr; break;
|
|
|
|
case 'g': formatter = fn_stats_labels_fmtr; break;
|
2006-11-18 22:08:37 +01:00
|
|
|
case 'G': show_cc_uninlined = 1; break;
|
2006-11-18 22:02:55 +01:00
|
|
|
case 'H': show_cc_inlined = 1; break;
|
2006-12-18 18:43:17 +01:00
|
|
|
case 'i': show_inline_expansions = verbose = 1; break;
|
|
|
|
case 'I': formatter = fn_stats_inline_exps_fmtr; break;
|
|
|
|
case 't': show_total_inline_expansion_stats = 1; break;
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
case 'T': show_variables = 1; break;
|
2006-12-18 18:43:17 +01:00
|
|
|
case 'N': formatter = fn_stats_name_len_fmtr; break;
|
2006-11-03 16:41:19 +01:00
|
|
|
case 'V': verbose = 1; break;
|
|
|
|
case 'h': usage(); return EXIT_SUCCESS;
|
|
|
|
default: usage(); return EXIT_FAILURE;
|
Add getopt support in pfunct, options implemented should be self explaining,
except for --classes, that asks that all non-inlined functions that receive as
one of its parameter a pointer to the specified class be printed, just the name
if --verbose is not used, or its complete prototype and where it is in the
source code:
[acme@newtoy net-2.6]$ pfunct --verbose --class=inode fs/ext3/built-in.o
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 606 */
void ext3_free_blocks(handle_t * handle, struct inode * inode, ext3_fsblk_t block, long unsigned int count);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 1404 */
ext3_fsblk_t ext3_new_blocks(handle_t * handle, struct inode * inode, ext3_fsblk_t goal, long unsigned int * count, int * errp);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 1668 */
ext3_fsblk_t ext3_new_block(handle_t * handle, struct inode * inode, ext3_fsblk_t goal, int * errp);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 346 */
void ext3_init_block_alloc_info(struct inode * inode);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 388 */
void ext3_discard_reservation(struct inode * inode);
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-10-29 04:41:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (optind < argc) {
|
|
|
|
switch (argc - optind) {
|
|
|
|
case 1: file_name = argv[optind++]; break;
|
|
|
|
case 2: file_name = argv[optind++];
|
|
|
|
function_name = argv[optind++]; break;
|
|
|
|
default: usage(); return EXIT_FAILURE;
|
|
|
|
}
|
2006-11-11 17:15:50 +01:00
|
|
|
} else {
|
|
|
|
usage();
|
|
|
|
return EXIT_FAILURE;
|
2006-10-29 00:07:45 +02:00
|
|
|
}
|
|
|
|
|
2006-11-11 19:31:04 +01:00
|
|
|
cus = cus__new(file_name);
|
|
|
|
if (cus == NULL) {
|
|
|
|
fputs("pfunct: insufficient memory\n", stderr);
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cus__load(cus) != 0) {
|
2006-10-29 00:07:45 +02:00
|
|
|
fprintf(stderr, "pfunct: couldn't load DWARF info from %s\n",
|
Add getopt support in pfunct, options implemented should be self explaining,
except for --classes, that asks that all non-inlined functions that receive as
one of its parameter a pointer to the specified class be printed, just the name
if --verbose is not used, or its complete prototype and where it is in the
source code:
[acme@newtoy net-2.6]$ pfunct --verbose --class=inode fs/ext3/built-in.o
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 606 */
void ext3_free_blocks(handle_t * handle, struct inode * inode, ext3_fsblk_t block, long unsigned int count);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 1404 */
ext3_fsblk_t ext3_new_blocks(handle_t * handle, struct inode * inode, ext3_fsblk_t goal, long unsigned int * count, int * errp);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 1668 */
ext3_fsblk_t ext3_new_block(handle_t * handle, struct inode * inode, ext3_fsblk_t goal, int * errp);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 346 */
void ext3_init_block_alloc_info(struct inode * inode);
/* /pub/scm/linux/kernel/git/acme/net-2.6/fs/ext3/balloc.c 388 */
void ext3_discard_reservation(struct inode * inode);
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-10-29 04:41:48 +01:00
|
|
|
file_name);
|
2006-10-29 00:07:45 +02:00
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
2006-12-18 18:43:17 +01:00
|
|
|
cus__for_each_cu(cus, cu_unique_iterator, NULL, NULL);
|
|
|
|
|
|
|
|
if (show_total_inline_expansion_stats)
|
2006-11-03 20:14:25 +01:00
|
|
|
print_total_inline_stats();
|
2006-10-31 21:23:16 +01:00
|
|
|
else if (class_name != NULL)
|
2006-12-01 02:48:34 +01:00
|
|
|
cus__for_each_cu(cus, cu_class_iterator, class_name, NULL);
|
2006-12-18 18:43:17 +01:00
|
|
|
else if (function_name != NULL)
|
2006-12-01 02:48:34 +01:00
|
|
|
cus__for_each_cu(cus, cu_function_iterator,
|
|
|
|
function_name, NULL);
|
2006-12-18 18:43:17 +01:00
|
|
|
else
|
|
|
|
print_fn_stats(formatter);
|
2006-10-29 00:07:45 +02:00
|
|
|
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
}
|