2007-01-29 14:15:33 +01:00
|
|
|
/*
|
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>
|
2007-01-29 14:15:33 +01:00
|
|
|
Copyright (C) 2007 Arnaldo Carvalho de Melo <acme@redhat.com>
|
2006-10-29 00:07:45 +02:00
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
|
2007-03-30 15:24:13 +02:00
|
|
|
#include <argp.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
|
|
|
|
2007-01-11 19:07:05 +01:00
|
|
|
#include "dwarves.h"
|
pfunct: Implement --expand_types
So that one can get an skeleton from where a function can be
reimplemented, or a probe can be written to attach to a tracepoint.
Right now it will only expand the types for
struct/union/typedef/enumeration types, but it is a good start.
[acme@doppio pahole]$ pfunct --expand_types --function inet6_ioctl ipv6.ko > a.c
[acme@doppio pahole]$ echo "int main(void) { return 0; }" >> a.c
[acme@doppio pahole]$ gcc -Wall -g a.c -o a
[acme@doppio pahole]$ grep ^#include a.c
[acme@doppio pahole]$
No errors, no includes.
This is present in ctracer, where we don't want to _require_ any header
files, just the object file with the function we want to probe. From
there we get the function signature, and reconstruct the types needed to
access members of structs passed as parameters.
We still need to add padding to reconstruct __attribute__ alignment
effects.
Also, if we can detect what are the exact members accessed in the probe,
we can reconstruct just what is needed to access those members,
hopefully reducing the time needed for gcc to digest the resulting
source code. And also reducing the size of the output, which can
hopefully be interesting to help focus on what the probe is doing.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2008-09-30 22:30:42 +02:00
|
|
|
#include "dwarves_emit.h"
|
2007-12-16 17:47:59 +01:00
|
|
|
#include "dutil.h"
|
2006-10-29 00:07:45 +02: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
|
|
|
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;
|
pfunct: Implement --expand_types
So that one can get an skeleton from where a function can be
reimplemented, or a probe can be written to attach to a tracepoint.
Right now it will only expand the types for
struct/union/typedef/enumeration types, but it is a good start.
[acme@doppio pahole]$ pfunct --expand_types --function inet6_ioctl ipv6.ko > a.c
[acme@doppio pahole]$ echo "int main(void) { return 0; }" >> a.c
[acme@doppio pahole]$ gcc -Wall -g a.c -o a
[acme@doppio pahole]$ grep ^#include a.c
[acme@doppio pahole]$
No errors, no includes.
This is present in ctracer, where we don't want to _require_ any header
files, just the object file with the function we want to probe. From
there we get the function signature, and reconstruct the types needed to
access members of structs passed as parameters.
We still need to add padding to reconstruct __attribute__ alignment
effects.
Also, if we can detect what are the exact members accessed in the probe,
we can reconstruct just what is needed to access those members,
hopefully reducing the time needed for gcc to digest the resulting
source code. And also reducing the size of the output, which can
hopefully be interesting to help focus on what the probe is doing.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2008-09-30 22:30:42 +02:00
|
|
|
static bool expand_types;
|
2008-10-01 17:43:01 +02:00
|
|
|
static struct type_emissions emissions;
|
2006-11-03 20:14:25 +01:00
|
|
|
|
pfunct: Implement --expand_types
So that one can get an skeleton from where a function can be
reimplemented, or a probe can be written to attach to a tracepoint.
Right now it will only expand the types for
struct/union/typedef/enumeration types, but it is a good start.
[acme@doppio pahole]$ pfunct --expand_types --function inet6_ioctl ipv6.ko > a.c
[acme@doppio pahole]$ echo "int main(void) { return 0; }" >> a.c
[acme@doppio pahole]$ gcc -Wall -g a.c -o a
[acme@doppio pahole]$ grep ^#include a.c
[acme@doppio pahole]$
No errors, no includes.
This is present in ctracer, where we don't want to _require_ any header
files, just the object file with the function we want to probe. From
there we get the function signature, and reconstruct the types needed to
access members of structs passed as parameters.
We still need to add padding to reconstruct __attribute__ alignment
effects.
Also, if we can detect what are the exact members accessed in the probe,
we can reconstruct just what is needed to access those members,
hopefully reducing the time needed for gcc to digest the resulting
source code. And also reducing the size of the output, which can
hopefully be interesting to help focus on what the probe is doing.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2008-09-30 22:30:42 +02:00
|
|
|
struct cus *cus;
|
2007-11-16 16:09:59 +01:00
|
|
|
static struct conf_fprintf conf;
|
|
|
|
|
2006-12-18 18:43:17 +01:00
|
|
|
struct fn_stats {
|
2007-01-07 20:13:39 +01:00
|
|
|
struct list_head node;
|
2007-01-12 18:47:26 +01:00
|
|
|
struct tag *tag;
|
2007-01-07 20:13:39 +01:00
|
|
|
const struct cu *cu;
|
|
|
|
uint32_t nr_expansions;
|
|
|
|
uint32_t size_expansions;
|
|
|
|
uint32_t nr_files;
|
2006-11-03 20:14:25 +01:00
|
|
|
};
|
|
|
|
|
2007-01-12 18:47:26 +01:00
|
|
|
static struct fn_stats *fn_stats__new(struct tag *tag, const struct cu *cu)
|
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) {
|
2007-01-12 18:47:26 +01:00
|
|
|
const struct function *fn = tag__function(tag);
|
|
|
|
|
|
|
|
self->tag = tag;
|
2007-01-04 00:57:35 +01:00
|
|
|
self->cu = cu;
|
2006-11-03 20:14:25 +01:00
|
|
|
self->nr_files = 1;
|
2007-01-12 18:47:26 +01:00
|
|
|
self->nr_expansions = fn->cu_total_nr_inline_expansions;
|
|
|
|
self->size_expansions = fn->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)
|
2007-01-12 18:47:26 +01:00
|
|
|
if (strcmp(function__name(tag__function(pos->tag), pos->cu),
|
|
|
|
name) == 0)
|
2006-11-03 20:14:25 +01:00
|
|
|
return pos;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-01-12 18:47:26 +01:00
|
|
|
static void fn_stats__add(struct tag *tag, const struct cu *cu)
|
2006-11-03 20:14:25 +01:00
|
|
|
{
|
2007-01-12 18:47:26 +01:00
|
|
|
struct fn_stats *fns = fn_stats__new(tag, cu);
|
|
|
|
if (fns != NULL)
|
|
|
|
list_add(&fns->node, &fn_stats__list);
|
2006-12-18 18:43:17 +01:00
|
|
|
}
|
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)
|
|
|
|
{
|
2007-01-12 18:47:26 +01:00
|
|
|
struct function *fn = tag__function(self->tag);
|
|
|
|
if (fn->lexblock.nr_inline_expansions > 0)
|
2007-03-28 16:38:32 +02:00
|
|
|
printf("%s: %u %zd\n", function__name(fn, self->cu),
|
2007-01-12 18:47:26 +01:00
|
|
|
fn->lexblock.nr_inline_expansions,
|
|
|
|
fn->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
|
|
|
{
|
2007-01-12 18:47:26 +01:00
|
|
|
struct function *fn = tag__function(self->tag);
|
|
|
|
if (fn->lexblock.nr_labels > 0)
|
|
|
|
printf("%s: %u\n", function__name(fn, self->cu),
|
|
|
|
fn->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)
|
|
|
|
{
|
2007-01-12 18:47:26 +01:00
|
|
|
struct function *fn = tag__function(self->tag);
|
|
|
|
if (fn->lexblock.nr_variables > 0)
|
|
|
|
printf("%s: %u\n", function__name(fn, self->cu),
|
|
|
|
fn->lexblock.nr_variables);
|
2006-12-18 18:43:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void fn_stats_nr_parms_fmtr(const struct fn_stats *self)
|
|
|
|
{
|
2007-01-12 18:47:26 +01:00
|
|
|
struct function *fn = tag__function(self->tag);
|
|
|
|
printf("%s: %u\n", function__name(fn, self->cu),
|
|
|
|
fn->proto.nr_parms);
|
2006-12-18 18:43:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void fn_stats_name_len_fmtr(const struct fn_stats *self)
|
|
|
|
{
|
2007-01-12 18:47:26 +01:00
|
|
|
struct function *fn = tag__function(self->tag);
|
|
|
|
const char *name = function__name(fn, self->cu);
|
2007-03-28 16:38:32 +02:00
|
|
|
printf("%s: %zd\n", name, strlen(name));
|
2006-12-18 18:43:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void fn_stats_size_fmtr(const struct fn_stats *self)
|
|
|
|
{
|
2007-01-12 18:47:26 +01:00
|
|
|
struct function *fn = tag__function(self->tag);
|
|
|
|
const size_t size = function__size(fn);
|
|
|
|
|
2006-12-18 18:43:17 +01:00
|
|
|
if (size != 0)
|
2007-03-28 16:38:32 +02:00
|
|
|
printf("%s: %zd\n", function__name(fn, self->cu), size);
|
2006-12-18 18:43:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void fn_stats_fmtr(const struct fn_stats *self)
|
|
|
|
{
|
|
|
|
if (verbose) {
|
2007-11-16 16:09:59 +01:00
|
|
|
tag__fprintf(self->tag, self->cu, &conf, stdout);
|
2007-01-12 19:00:07 +01:00
|
|
|
putchar('\n');
|
|
|
|
if (show_variables || show_inline_expansions)
|
2007-02-15 15:01:01 +01:00
|
|
|
function__fprintf_stats(self->tag, self->cu, stdout);
|
2006-12-18 18:43:17 +01:00
|
|
|
printf("/* definitions: %u */\n", self->nr_files);
|
|
|
|
putchar('\n');
|
2007-01-12 18:47:26 +01:00
|
|
|
} else {
|
|
|
|
struct function *fn = tag__function(self->tag);
|
|
|
|
puts(function__name(fn, self->cu));
|
|
|
|
}
|
2006-12-18 18:43:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
2007-11-16 16:09:59 +01:00
|
|
|
printf("%-31.31s %6u %7u %6u %6u\n",
|
2007-01-12 18:47:26 +01:00
|
|
|
function__name(tag__function(self->tag), self->cu),
|
2006-12-18 18:43:17 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2007-01-07 20:13:39 +01:00
|
|
|
static void fn_stats__dupmsg(struct function *self,
|
2007-01-04 00:57:35 +01:00
|
|
|
const struct cu *self_cu,
|
2007-01-29 13:42:03 +01:00
|
|
|
struct function *dup __unused,
|
2007-01-04 00:57:35 +01:00
|
|
|
const struct cu *dup_cu,
|
|
|
|
char *hdr, const char *fmt, ...)
|
2006-12-18 18:43:17 +01:00
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
if (!*hdr)
|
|
|
|
printf("function: %s\nfirst: %s\ncurrent: %s\n",
|
2007-01-07 20:13:39 +01:00
|
|
|
function__name(self, self_cu),
|
|
|
|
self_cu->name,
|
2007-01-07 20:57:00 +01:00
|
|
|
dup_cu->name);
|
2006-12-18 18:43:17 +01:00
|
|
|
|
|
|
|
va_start(args, fmt);
|
|
|
|
vprintf(fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
*hdr = 1;
|
|
|
|
}
|
|
|
|
|
2007-01-07 20:13:39 +01:00
|
|
|
static void fn_stats__chkdupdef(struct function *self,
|
2007-01-04 00:57:35 +01:00
|
|
|
const struct cu *self_cu,
|
2007-01-07 20:13:39 +01:00
|
|
|
struct function *dup,
|
2007-01-04 00:57:35 +01:00
|
|
|
const struct cu *dup_cu)
|
2006-12-18 18:43:17 +01:00
|
|
|
{
|
|
|
|
char hdr = 0;
|
|
|
|
const size_t self_size = function__size(self);
|
|
|
|
const size_t dup_size = function__size(dup);
|
|
|
|
|
|
|
|
if (self_size != dup_size)
|
2007-01-04 00:57:35 +01:00
|
|
|
fn_stats__dupmsg(self, self_cu, dup, dup_cu,
|
|
|
|
&hdr, "size: %zd != %zd\n",
|
|
|
|
self_size, dup_size);
|
2006-12-18 18:43:17 +01:00
|
|
|
|
2006-12-30 19:34:20 +01:00
|
|
|
if (self->proto.nr_parms != dup->proto.nr_parms)
|
2007-01-04 00:57:35 +01:00
|
|
|
fn_stats__dupmsg(self, self_cu, dup, dup_cu,
|
|
|
|
&hdr, "nr_parms: %u != %u\n",
|
2006-12-30 19:34:20 +01:00
|
|
|
self->proto.nr_parms, dup->proto.nr_parms);
|
2006-12-18 18:43:17 +01:00
|
|
|
|
|
|
|
/* XXX put more checks here: member types, member ordering, etc */
|
|
|
|
|
|
|
|
if (hdr)
|
|
|
|
putchar('\n');
|
|
|
|
}
|
|
|
|
|
2007-01-04 00:29:24 +01:00
|
|
|
static struct tag *function__filter(struct tag *tag, struct cu *cu,
|
2007-01-29 13:42:03 +01:00
|
|
|
void *cookie __unused)
|
2006-12-18 18:43:17 +01:00
|
|
|
{
|
2007-01-04 00:29:24 +01:00
|
|
|
struct function *function;
|
2006-12-18 18:43:17 +01:00
|
|
|
struct fn_stats *fstats;
|
2007-01-07 20:13:39 +01:00
|
|
|
const char *name;
|
2006-12-18 18:43:17 +01:00
|
|
|
|
2007-01-04 00:29:24 +01:00
|
|
|
if (tag->tag != DW_TAG_subprogram)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
function = tag__function(tag);
|
2007-01-07 20:57:00 +01:00
|
|
|
/*
|
|
|
|
* FIXME: remove this check and try to fix the parameter abstract
|
|
|
|
* origin code someday...
|
|
|
|
*/
|
|
|
|
if (function->name == NULL)
|
2006-12-18 18:43:17 +01:00
|
|
|
return NULL;
|
|
|
|
|
2007-01-07 20:57:00 +01:00
|
|
|
name = function__name(function, cu);
|
2006-12-18 18:43:17 +01:00
|
|
|
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;
|
|
|
|
|
2007-01-07 20:13:39 +01:00
|
|
|
fstats = fn_stats__find(name);
|
2007-01-12 18:47:26 +01:00
|
|
|
if (fstats != NULL) {
|
|
|
|
struct function *fn = tag__function(fstats->tag);
|
|
|
|
|
|
|
|
if (!fn->external)
|
|
|
|
return tag;
|
|
|
|
|
2007-01-08 14:42:52 +01:00
|
|
|
if (verbose)
|
2007-01-12 18:47:26 +01:00
|
|
|
fn_stats__chkdupdef(fn, fstats->cu, function, cu);
|
2006-12-18 18:43:17 +01:00
|
|
|
fstats->nr_expansions += function->cu_total_nr_inline_expansions;
|
|
|
|
fstats->size_expansions += function->cu_total_size_inline_expansions;
|
|
|
|
fstats->nr_files++;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-01-04 00:29:24 +01:00
|
|
|
return tag;
|
2006-12-18 18:43:17 +01:00
|
|
|
}
|
|
|
|
|
2007-01-29 13:42:03 +01:00
|
|
|
static int unique_iterator(struct tag *tag, struct cu *cu,
|
|
|
|
void *cookie __unused)
|
2006-12-18 18:43:17 +01:00
|
|
|
{
|
2007-01-04 00:29:24 +01:00
|
|
|
if (tag->tag == DW_TAG_subprogram)
|
2007-01-12 18:47:26 +01:00
|
|
|
fn_stats__add(tag, cu);
|
2006-12-18 18:43:17 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cu_unique_iterator(struct cu *cu, void *cookie)
|
|
|
|
{
|
|
|
|
cu__account_inline_expansions(cu);
|
2007-01-04 00:29:24 +01:00
|
|
|
return cu__for_each_tag(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
|
|
|
|
2007-01-04 00:29:24 +01:00
|
|
|
static int class_iterator(struct tag *tag, struct cu *cu, 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
|
|
|
{
|
2007-01-04 00:29:24 +01:00
|
|
|
struct function *function;
|
|
|
|
|
|
|
|
if (tag->tag != DW_TAG_subprogram)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
function = tag__function(tag);
|
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;
|
|
|
|
|
2007-01-04 00:29:24 +01:00
|
|
|
if (ftype__has_parm_of_type(&function->proto, cookie, cu)) {
|
2007-01-12 19:25:20 +01:00
|
|
|
if (verbose)
|
2007-11-16 16:09:59 +01:00
|
|
|
tag__fprintf(tag, cu, &conf, stdout);
|
2007-01-12 19:25:20 +01:00
|
|
|
else
|
|
|
|
fputs(function__name(function, cu), stdout);
|
|
|
|
putchar('\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
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-10-31 21:23:16 +01:00
|
|
|
static int cu_class_iterator(struct cu *cu, void *cookie)
|
|
|
|
{
|
2007-11-16 21:16:56 +01:00
|
|
|
struct tag *target = cu__find_struct_by_name(cu, cookie, 0);
|
2006-10-31 21:23:16 +01:00
|
|
|
|
|
|
|
if (target == NULL)
|
|
|
|
return 0;
|
|
|
|
|
2007-01-04 00:29:24 +01:00
|
|
|
return cu__for_each_tag(cu, class_iterator, target, NULL);
|
2006-11-01 14:18:01 +01:00
|
|
|
}
|
|
|
|
|
pfunct: Implement --expand_types
So that one can get an skeleton from where a function can be
reimplemented, or a probe can be written to attach to a tracepoint.
Right now it will only expand the types for
struct/union/typedef/enumeration types, but it is a good start.
[acme@doppio pahole]$ pfunct --expand_types --function inet6_ioctl ipv6.ko > a.c
[acme@doppio pahole]$ echo "int main(void) { return 0; }" >> a.c
[acme@doppio pahole]$ gcc -Wall -g a.c -o a
[acme@doppio pahole]$ grep ^#include a.c
[acme@doppio pahole]$
No errors, no includes.
This is present in ctracer, where we don't want to _require_ any header
files, just the object file with the function we want to probe. From
there we get the function signature, and reconstruct the types needed to
access members of structs passed as parameters.
We still need to add padding to reconstruct __attribute__ alignment
effects.
Also, if we can detect what are the exact members accessed in the probe,
we can reconstruct just what is needed to access those members,
hopefully reducing the time needed for gcc to digest the resulting
source code. And also reducing the size of the output, which can
hopefully be interesting to help focus on what the probe is doing.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2008-09-30 22:30:42 +02:00
|
|
|
static int function__emit_type_definitions(struct function *self,
|
2008-10-01 17:43:01 +02:00
|
|
|
struct cu *cu, FILE *fp)
|
pfunct: Implement --expand_types
So that one can get an skeleton from where a function can be
reimplemented, or a probe can be written to attach to a tracepoint.
Right now it will only expand the types for
struct/union/typedef/enumeration types, but it is a good start.
[acme@doppio pahole]$ pfunct --expand_types --function inet6_ioctl ipv6.ko > a.c
[acme@doppio pahole]$ echo "int main(void) { return 0; }" >> a.c
[acme@doppio pahole]$ gcc -Wall -g a.c -o a
[acme@doppio pahole]$ grep ^#include a.c
[acme@doppio pahole]$
No errors, no includes.
This is present in ctracer, where we don't want to _require_ any header
files, just the object file with the function we want to probe. From
there we get the function signature, and reconstruct the types needed to
access members of structs passed as parameters.
We still need to add padding to reconstruct __attribute__ alignment
effects.
Also, if we can detect what are the exact members accessed in the probe,
we can reconstruct just what is needed to access those members,
hopefully reducing the time needed for gcc to digest the resulting
source code. And also reducing the size of the output, which can
hopefully be interesting to help focus on what the probe is doing.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2008-09-30 22:30:42 +02:00
|
|
|
{
|
|
|
|
struct parameter *pos;
|
|
|
|
|
|
|
|
function__for_each_parameter(self, pos) {
|
|
|
|
struct tag *type = cu__find_tag_by_id(cu, parameter__type(pos, cu));
|
|
|
|
try_again:
|
|
|
|
if (type == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (type->tag == DW_TAG_pointer_type) {
|
|
|
|
type = cu__find_tag_by_id(cu, type->type);
|
|
|
|
goto try_again;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tag__is_type(type)) {
|
2008-10-01 17:43:01 +02:00
|
|
|
type__emit_definitions(type, cu, &emissions, fp);
|
pfunct: Implement --expand_types
So that one can get an skeleton from where a function can be
reimplemented, or a probe can be written to attach to a tracepoint.
Right now it will only expand the types for
struct/union/typedef/enumeration types, but it is a good start.
[acme@doppio pahole]$ pfunct --expand_types --function inet6_ioctl ipv6.ko > a.c
[acme@doppio pahole]$ echo "int main(void) { return 0; }" >> a.c
[acme@doppio pahole]$ gcc -Wall -g a.c -o a
[acme@doppio pahole]$ grep ^#include a.c
[acme@doppio pahole]$
No errors, no includes.
This is present in ctracer, where we don't want to _require_ any header
files, just the object file with the function we want to probe. From
there we get the function signature, and reconstruct the types needed to
access members of structs passed as parameters.
We still need to add padding to reconstruct __attribute__ alignment
effects.
Also, if we can detect what are the exact members accessed in the probe,
we can reconstruct just what is needed to access those members,
hopefully reducing the time needed for gcc to digest the resulting
source code. And also reducing the size of the output, which can
hopefully be interesting to help focus on what the probe is doing.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2008-09-30 22:30:42 +02:00
|
|
|
type__emit(type, cu, NULL, NULL, fp);
|
|
|
|
putchar('\n');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-01-04 00:29:24 +01:00
|
|
|
static int function_iterator(struct tag *tag, struct cu *cu, void *cookie)
|
2006-10-31 21:23:16 +01:00
|
|
|
{
|
2007-01-04 00:29:24 +01:00
|
|
|
struct function *function;
|
|
|
|
|
|
|
|
if (tag->tag != DW_TAG_subprogram)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
function = tag__function(tag);
|
2007-01-07 20:13:39 +01:00
|
|
|
if (strcmp(function__name(function, cu), cookie) == 0) {
|
pfunct: Implement --expand_types
So that one can get an skeleton from where a function can be
reimplemented, or a probe can be written to attach to a tracepoint.
Right now it will only expand the types for
struct/union/typedef/enumeration types, but it is a good start.
[acme@doppio pahole]$ pfunct --expand_types --function inet6_ioctl ipv6.ko > a.c
[acme@doppio pahole]$ echo "int main(void) { return 0; }" >> a.c
[acme@doppio pahole]$ gcc -Wall -g a.c -o a
[acme@doppio pahole]$ grep ^#include a.c
[acme@doppio pahole]$
No errors, no includes.
This is present in ctracer, where we don't want to _require_ any header
files, just the object file with the function we want to probe. From
there we get the function signature, and reconstruct the types needed to
access members of structs passed as parameters.
We still need to add padding to reconstruct __attribute__ alignment
effects.
Also, if we can detect what are the exact members accessed in the probe,
we can reconstruct just what is needed to access those members,
hopefully reducing the time needed for gcc to digest the resulting
source code. And also reducing the size of the output, which can
hopefully be interesting to help focus on what the probe is doing.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2008-09-30 22:30:42 +02:00
|
|
|
if (expand_types)
|
2008-10-01 17:43:01 +02:00
|
|
|
function__emit_type_definitions(function, cu, stdout);
|
2007-11-16 16:09:59 +01:00
|
|
|
tag__fprintf(tag, cu, &conf, stdout);
|
2007-01-12 19:00:07 +01:00
|
|
|
putchar('\n');
|
|
|
|
if (show_variables || show_inline_expansions)
|
2007-02-15 15:01:01 +01:00
|
|
|
function__fprintf_stats(tag, cu, stdout);
|
2006-10-31 21:23:16 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cu_function_iterator(struct cu *cu, void *cookie)
|
|
|
|
{
|
2007-01-04 00:29:24 +01:00
|
|
|
return cu__for_each_tag(cu, function_iterator, cookie, NULL);
|
2006-11-18 22:08:37 +01:00
|
|
|
}
|
|
|
|
|
2007-03-30 15:24:13 +02:00
|
|
|
static const struct argp_option pfunct__options[] = {
|
pfunct: Implement --expand_types
So that one can get an skeleton from where a function can be
reimplemented, or a probe can be written to attach to a tracepoint.
Right now it will only expand the types for
struct/union/typedef/enumeration types, but it is a good start.
[acme@doppio pahole]$ pfunct --expand_types --function inet6_ioctl ipv6.ko > a.c
[acme@doppio pahole]$ echo "int main(void) { return 0; }" >> a.c
[acme@doppio pahole]$ gcc -Wall -g a.c -o a
[acme@doppio pahole]$ grep ^#include a.c
[acme@doppio pahole]$
No errors, no includes.
This is present in ctracer, where we don't want to _require_ any header
files, just the object file with the function we want to probe. From
there we get the function signature, and reconstruct the types needed to
access members of structs passed as parameters.
We still need to add padding to reconstruct __attribute__ alignment
effects.
Also, if we can detect what are the exact members accessed in the probe,
we can reconstruct just what is needed to access those members,
hopefully reducing the time needed for gcc to digest the resulting
source code. And also reducing the size of the output, which can
hopefully be interesting to help focus on what the probe is doing.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2008-09-30 22:30:42 +02:00
|
|
|
{
|
|
|
|
.key = 'b',
|
|
|
|
.name = "expand_types",
|
|
|
|
.doc = "Expand types needed by the prototype",
|
|
|
|
},
|
2007-03-30 15:24:13 +02:00
|
|
|
{
|
|
|
|
.key = 'c',
|
|
|
|
.name = "class",
|
|
|
|
.arg = "CLASS",
|
|
|
|
.doc = "functions that have CLASS pointer parameters",
|
|
|
|
},
|
|
|
|
{
|
2007-03-30 18:45:57 +02:00
|
|
|
.key = 'E',
|
2007-03-30 15:24:13 +02:00
|
|
|
.name = "externals",
|
|
|
|
.doc = "show just external functions",
|
|
|
|
},
|
2007-04-24 21:09:34 +02:00
|
|
|
{
|
|
|
|
.key = 'f',
|
|
|
|
.name = "function",
|
|
|
|
.arg = "FUNCTION",
|
|
|
|
.doc = "show just FUNCTION",
|
|
|
|
},
|
2007-03-30 15:24:13 +02:00
|
|
|
{
|
|
|
|
.key = 'g',
|
|
|
|
.name = "goto_labels",
|
|
|
|
.doc = "show number of goto labels",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.key = 'G',
|
|
|
|
.name = "cc_uninlined",
|
|
|
|
.doc = "declared inline, uninlined by compiler",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.key = 'H',
|
|
|
|
.name = "cc_inlined",
|
|
|
|
.doc = "not declared inline, inlined by compiler",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.key = 'i',
|
|
|
|
.name = "inline_expansions",
|
|
|
|
.doc = "show inline expansions",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.key = 'I',
|
|
|
|
.name = "inline_expansions_stats",
|
|
|
|
.doc = "show inline expansions stats",
|
|
|
|
},
|
2007-11-16 16:09:59 +01:00
|
|
|
{
|
|
|
|
.key = 'l',
|
|
|
|
.name = "decl_info",
|
|
|
|
.doc = "show source code info",
|
|
|
|
},
|
2007-03-30 15:24:13 +02:00
|
|
|
{
|
|
|
|
.key = 't',
|
|
|
|
.name = "total_inline_stats",
|
|
|
|
.doc = "show Multi-CU total inline expansions stats",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.key = 's',
|
|
|
|
.name = "sizes",
|
|
|
|
.doc = "show size of functions",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.key = 'N',
|
|
|
|
.name = "function_name_len",
|
|
|
|
.doc = "show size of functions names",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.key = 'p',
|
|
|
|
.name = "nr_parms",
|
|
|
|
.doc = "show number of parameters",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.key = 'S',
|
|
|
|
.name = "nr_variables",
|
|
|
|
.doc = "show number of variables",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.key = 'T',
|
|
|
|
.name = "variables",
|
|
|
|
.doc = "show variables",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.key = 'V',
|
|
|
|
.name = "verbose",
|
|
|
|
.doc = "be verbose",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = NULL,
|
|
|
|
}
|
2006-12-19 09:03:31 +01:00
|
|
|
};
|
|
|
|
|
2007-03-30 15:24:13 +02:00
|
|
|
static void (*formatter)(const struct fn_stats *f) = fn_stats_fmtr;
|
|
|
|
static char *class_name;
|
|
|
|
static char *function_name;
|
|
|
|
static int show_total_inline_expansion_stats;
|
|
|
|
|
|
|
|
static error_t pfunct__options_parser(int key, char *arg,
|
2007-03-30 18:45:57 +02:00
|
|
|
struct argp_state *state)
|
2006-12-19 09:03:31 +01:00
|
|
|
{
|
2007-03-30 15:24:13 +02:00
|
|
|
switch (key) {
|
2007-03-30 18:45:57 +02:00
|
|
|
case ARGP_KEY_INIT: state->child_inputs[0] = state->input; break;
|
2008-10-01 17:43:01 +02:00
|
|
|
case 'b': expand_types = true;
|
|
|
|
type_emissions__init(&emissions); break;
|
2007-03-30 15:24:13 +02:00
|
|
|
case 'c': class_name = arg; break;
|
2007-04-24 21:09:34 +02:00
|
|
|
case 'f': function_name = arg; break;
|
2007-03-30 18:45:57 +02:00
|
|
|
case 'E': show_externals = 1; break;
|
2007-03-30 15:24:13 +02: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;
|
|
|
|
case 'G': show_cc_uninlined = 1; break;
|
|
|
|
case 'H': show_cc_inlined = 1; break;
|
|
|
|
case 'i': show_inline_expansions = verbose = 1; break;
|
|
|
|
case 'I': formatter = fn_stats_inline_exps_fmtr; break;
|
2007-11-16 16:09:59 +01:00
|
|
|
case 'l': conf.show_decl_info = 1; break;
|
2007-03-30 15:24:13 +02:00
|
|
|
case 't': show_total_inline_expansion_stats = 1; break;
|
|
|
|
case 'T': show_variables = 1; break;
|
|
|
|
case 'N': formatter = fn_stats_name_len_fmtr; break;
|
|
|
|
case 'V': verbose = 1; break;
|
|
|
|
default: return ARGP_ERR_UNKNOWN;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2006-12-19 09:03:31 +01:00
|
|
|
}
|
|
|
|
|
2008-01-31 12:30:55 +01:00
|
|
|
static const char pfunct__args_doc[] = "FILE";
|
2007-03-30 15:24:13 +02:00
|
|
|
|
|
|
|
static struct argp pfunct__argp = {
|
|
|
|
.options = pfunct__options,
|
|
|
|
.parser = pfunct__options_parser,
|
|
|
|
.args_doc = pfunct__args_doc,
|
|
|
|
};
|
|
|
|
|
2006-10-29 00:07:45 +02:00
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
2007-04-24 21:09:34 +02:00
|
|
|
int err;
|
2007-01-19 00:41:25 +01:00
|
|
|
|
2008-10-01 16:26:51 +02:00
|
|
|
cus = cus__new(NULL);
|
2006-11-11 19:31:04 +01:00
|
|
|
if (cus == NULL) {
|
|
|
|
fputs("pfunct: insufficient memory\n", stderr);
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
2007-04-24 21:09:34 +02:00
|
|
|
err = cus__loadfl(cus, &pfunct__argp, argc, argv);
|
2007-03-30 18:45:57 +02:00
|
|
|
if (err != 0)
|
2006-10-29 00:07:45 +02:00
|
|
|
return EXIT_FAILURE;
|
2007-03-30 18:45:57 +02:00
|
|
|
|
|
|
|
dwarves__init(0);
|
|
|
|
|
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);
|
2007-01-29 14:15:33 +01:00
|
|
|
else
|
2006-12-18 18:43:17 +01:00
|
|
|
print_fn_stats(formatter);
|
2006-10-29 00:07:45 +02:00
|
|
|
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
}
|