2007-01-29 14:15:33 +01:00
|
|
|
/*
|
2019-01-15 18:28:24 +01:00
|
|
|
SPDX-License-Identifier: GPL-2.0-only
|
|
|
|
|
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
|
|
|
*/
|
|
|
|
|
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>
|
2009-03-25 22:03:28 +01:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <unistd.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"
|
2009-03-25 22:03:28 +01:00
|
|
|
#include "elf_symtab.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;
|
2009-03-25 22:03:28 +01:00
|
|
|
static char *symtab_name;
|
2010-05-04 18:33:08 +02:00
|
|
|
static bool show_prototypes;
|
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;
|
2019-04-04 21:03:33 +02:00
|
|
|
static bool compilable_output;
|
2008-10-01 17:43:01 +02:00
|
|
|
static struct type_emissions emissions;
|
2009-06-04 19:56:44 +02:00
|
|
|
static uint64_t addr;
|
2006-11-03 20:14:25 +01:00
|
|
|
|
2007-11-16 16:09:59 +01:00
|
|
|
static struct conf_fprintf conf;
|
|
|
|
|
2019-04-15 18:51:28 +02:00
|
|
|
static struct conf_load conf_load = {
|
|
|
|
.conf_fprintf = &conf,
|
|
|
|
};
|
2009-03-09 18:43:47 +01:00
|
|
|
|
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
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
struct fn_stats *stats = malloc(sizeof(*stats));
|
2006-11-03 20:14:25 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
if (stats != NULL) {
|
2007-01-12 18:47:26 +01:00
|
|
|
const struct function *fn = tag__function(tag);
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
stats->tag = tag;
|
|
|
|
stats->cu = cu;
|
|
|
|
stats->nr_files = 1;
|
|
|
|
stats->nr_expansions = fn->cu_total_nr_inline_expansions;
|
|
|
|
stats->size_expansions = fn->cu_total_size_inline_expansions;
|
2006-11-03 20:14:25 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
return stats;
|
2006-11-03 20:14:25 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void fn_stats__delete(struct fn_stats *stats)
|
2009-03-11 16:31:17 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
free(stats);
|
2009-03-11 16:31:17 +01:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-03-11 16:31:17 +01:00
|
|
|
static void fn_stats__delete_list(void)
|
|
|
|
{
|
|
|
|
struct fn_stats *pos, *n;
|
|
|
|
|
|
|
|
list_for_each_entry_safe(pos, n, &fn_stats__list, node) {
|
|
|
|
list_del_init(&pos->node);
|
|
|
|
fn_stats__delete(pos);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void fn_stats_inline_exps_fmtr(const struct fn_stats *stats)
|
2006-12-18 18:43:17 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
struct function *fn = tag__function(stats->tag);
|
2007-01-12 18:47:26 +01:00
|
|
|
if (fn->lexblock.nr_inline_expansions > 0)
|
2012-08-17 23:47:15 +02:00
|
|
|
printf("%s: %u %d\n", function__name(fn, stats->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
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void fn_stats_labels_fmtr(const struct fn_stats *stats)
|
2006-11-03 20:14:25 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
struct function *fn = tag__function(stats->tag);
|
2007-01-12 18:47:26 +01:00
|
|
|
if (fn->lexblock.nr_labels > 0)
|
2012-08-17 23:47:15 +02:00
|
|
|
printf("%s: %u\n", function__name(fn, stats->cu),
|
2007-01-12 18:47:26 +01:00
|
|
|
fn->lexblock.nr_labels);
|
2006-11-03 20:14:25 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void fn_stats_variables_fmtr(const struct fn_stats *stats)
|
2006-12-18 18:43:17 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
struct function *fn = tag__function(stats->tag);
|
2007-01-12 18:47:26 +01:00
|
|
|
if (fn->lexblock.nr_variables > 0)
|
2012-08-17 23:47:15 +02:00
|
|
|
printf("%s: %u\n", function__name(fn, stats->cu),
|
2007-01-12 18:47:26 +01:00
|
|
|
fn->lexblock.nr_variables);
|
2006-12-18 18:43:17 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void fn_stats_nr_parms_fmtr(const struct fn_stats *stats)
|
2006-12-18 18:43:17 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
struct function *fn = tag__function(stats->tag);
|
|
|
|
printf("%s: %u\n", function__name(fn, stats->cu),
|
2007-01-12 18:47:26 +01:00
|
|
|
fn->proto.nr_parms);
|
2006-12-18 18:43:17 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void fn_stats_name_len_fmtr(const struct fn_stats *stats)
|
2006-12-18 18:43:17 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
struct function *fn = tag__function(stats->tag);
|
|
|
|
const char *name = function__name(fn, stats->cu);
|
2007-03-28 16:38:32 +02:00
|
|
|
printf("%s: %zd\n", name, strlen(name));
|
2006-12-18 18:43:17 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void fn_stats_size_fmtr(const struct fn_stats *stats)
|
2006-12-18 18:43:17 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
struct function *fn = tag__function(stats->tag);
|
2007-01-12 18:47:26 +01:00
|
|
|
const size_t size = function__size(fn);
|
|
|
|
|
2006-12-18 18:43:17 +01:00
|
|
|
if (size != 0)
|
2012-08-17 23:47:15 +02:00
|
|
|
printf("%s: %zd\n", function__name(fn, stats->cu), size);
|
2006-12-18 18:43:17 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void fn_stats_fmtr(const struct fn_stats *stats)
|
2006-12-18 18:43:17 +01:00
|
|
|
{
|
2010-05-04 18:33:08 +02:00
|
|
|
if (verbose || show_prototypes) {
|
2012-08-17 23:47:15 +02:00
|
|
|
tag__fprintf(stats->tag, stats->cu, &conf, stdout);
|
2007-01-12 19:00:07 +01:00
|
|
|
putchar('\n');
|
2010-05-04 18:33:08 +02:00
|
|
|
if (show_prototypes)
|
|
|
|
return;
|
2007-01-12 19:00:07 +01:00
|
|
|
if (show_variables || show_inline_expansions)
|
2012-08-17 23:47:15 +02:00
|
|
|
function__fprintf_stats(stats->tag, stats->cu, &conf, stdout);
|
|
|
|
printf("/* definitions: %u */\n", stats->nr_files);
|
2006-12-18 18:43:17 +01:00
|
|
|
putchar('\n');
|
2007-01-12 18:47:26 +01:00
|
|
|
} else {
|
2012-08-17 23:47:15 +02:00
|
|
|
struct function *fn = tag__function(stats->tag);
|
|
|
|
puts(function__name(fn, stats->cu));
|
2007-01-12 18:47:26 +01:00
|
|
|
}
|
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);
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void fn_stats_inline_stats_fmtr(const struct fn_stats *stats)
|
2006-12-18 18:43:17 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
if (stats->nr_expansions > 1)
|
2007-11-16 16:09:59 +01:00
|
|
|
printf("%-31.31s %6u %7u %6u %6u\n",
|
2012-08-17 23:47:15 +02:00
|
|
|
function__name(tag__function(stats->tag), stats->cu),
|
|
|
|
stats->size_expansions, stats->nr_expansions,
|
|
|
|
stats->size_expansions / stats->nr_expansions,
|
|
|
|
stats->nr_files);
|
2006-12-18 18:43:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void fn_stats__dupmsg(struct function *func,
|
|
|
|
const struct cu *func_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",
|
2012-08-17 23:47:15 +02:00
|
|
|
function__name(func, func_cu),
|
|
|
|
func_cu->name,
|
2007-01-07 20:57:00 +01:00
|
|
|
dup_cu->name);
|
2009-03-14 17:50:36 +01:00
|
|
|
|
2006-12-18 18:43:17 +01:00
|
|
|
va_start(args, fmt);
|
|
|
|
vprintf(fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
*hdr = 1;
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void fn_stats__chkdupdef(struct function *func,
|
|
|
|
const struct cu *func_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;
|
2012-08-17 23:47:15 +02:00
|
|
|
const size_t func_size = function__size(func);
|
2006-12-18 18:43:17 +01:00
|
|
|
const size_t dup_size = function__size(dup);
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
if (func_size != dup_size)
|
|
|
|
fn_stats__dupmsg(func, func_cu, dup, dup_cu,
|
2007-01-04 00:57:35 +01:00
|
|
|
&hdr, "size: %zd != %zd\n",
|
2012-08-17 23:47:15 +02:00
|
|
|
func_size, dup_size);
|
2006-12-18 18:43:17 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
if (func->proto.nr_parms != dup->proto.nr_parms)
|
|
|
|
fn_stats__dupmsg(func, func_cu, dup, dup_cu,
|
2007-01-04 00:57:35 +01:00
|
|
|
&hdr, "nr_parms: %u != %u\n",
|
2012-08-17 23:47:15 +02:00
|
|
|
func->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');
|
|
|
|
}
|
|
|
|
|
2009-04-01 16:55:49 +02:00
|
|
|
static bool function__filter(struct function *function, struct cu *cu)
|
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
|
|
|
|
2009-04-01 16:55:49 +02:00
|
|
|
if (!function__tag(function)->top_level)
|
|
|
|
return true;
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
|
2007-01-07 20:57:00 +01:00
|
|
|
/*
|
|
|
|
* FIXME: remove this check and try to fix the parameter abstract
|
|
|
|
* origin code someday...
|
|
|
|
*/
|
2008-10-02 19:34:42 +02:00
|
|
|
if (!function->name)
|
2009-04-01 16:55:49 +02:00
|
|
|
return true;
|
2006-12-18 18:43:17 +01:00
|
|
|
|
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)
|
2009-04-01 16:55:49 +02:00
|
|
|
return true;
|
2006-12-18 18:43:17 +01:00
|
|
|
|
|
|
|
if (show_cc_uninlined &&
|
|
|
|
function->inlined != DW_INL_declared_not_inlined)
|
2009-04-01 16:55:49 +02:00
|
|
|
return true;
|
2006-12-18 18:43:17 +01:00
|
|
|
|
|
|
|
if (show_cc_inlined && function->inlined != DW_INL_inlined)
|
2009-04-01 16:55:49 +02:00
|
|
|
return true;
|
2006-12-18 18:43:17 +01:00
|
|
|
|
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)
|
2009-04-01 16:55:49 +02:00
|
|
|
return false;
|
2007-01-12 18:47:26 +01:00
|
|
|
|
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++;
|
2009-04-01 16:55:49 +02:00
|
|
|
return true;
|
2006-12-18 18:43:17 +01:00
|
|
|
}
|
|
|
|
|
2009-04-01 16:55:49 +02:00
|
|
|
return false;
|
2006-12-18 18:43:17 +01:00
|
|
|
}
|
|
|
|
|
2009-04-01 16:55:49 +02:00
|
|
|
static int cu_unique_iterator(struct cu *cu, void *cookie __unused)
|
2006-12-18 18:43:17 +01:00
|
|
|
{
|
|
|
|
cu__account_inline_expansions(cu);
|
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
|
|
|
|
2009-04-01 16:55:49 +02:00
|
|
|
struct function *pos;
|
|
|
|
uint32_t id;
|
2007-01-04 00:29:24 +01:00
|
|
|
|
2009-04-01 16:55:49 +02:00
|
|
|
cu__for_each_function(cu, id, pos)
|
|
|
|
if (!function__filter(pos, cu))
|
|
|
|
fn_stats__add(function__tag(pos), cu);
|
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)
|
|
|
|
{
|
2019-03-07 22:04:20 +01:00
|
|
|
type_id_t target_id;
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
struct tag *target = cu__find_struct_by_name(cu, cookie, 0, &target_id);
|
2006-10-31 21:23:16 +01:00
|
|
|
|
|
|
|
if (target == NULL)
|
|
|
|
return 0;
|
|
|
|
|
2009-04-01 16:55:49 +02:00
|
|
|
struct function *pos;
|
|
|
|
uint32_t id;
|
|
|
|
|
|
|
|
cu__for_each_function(cu, id, pos) {
|
|
|
|
if (pos->inlined ||
|
|
|
|
!ftype__has_parm_of_type(&pos->proto, target_id, cu))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (verbose)
|
|
|
|
tag__fprintf(function__tag(pos), cu, &conf, stdout);
|
|
|
|
else
|
|
|
|
fputs(function__name(pos, cu), stdout);
|
|
|
|
putchar('\n');
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2006-11-01 14:18:01 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static int function__emit_type_definitions(struct function *func,
|
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;
|
btf_loader: Add support for BTF_KIND_FUNC
Some changes to the fprintf routines were needed, as BTF has as the
function type just a BTF_KIND_FUNC_PROTO, while DWARF has as the type
for a function its return value type. With a function->btf flag this was
overcome and all the other goodies in pfunct are present, for instance:
$ pahole -JV examples/tcp.o | grep -w FUNC | head
[4068] FUNC tcp_init type_id=4067
[4070] FUNC tcp_abort type_id=4069
[4072] FUNC tcp_done type_id=4071
[4074] FUNC tcp_md5_hash_key type_id=4073
[4076] FUNC tcp_md5_hash_skb_data type_id=4075
[4078] FUNC tcp_get_md5sig_pool type_id=4077
[4080] FUNC tcp_alloc_md5sig_pool type_id=4079
[4082] FUNC compat_tcp_getsockopt type_id=4081
[4084] FUNC tcp_getsockopt type_id=4083
[4086] FUNC tcp_get_timestamping_opt_stats type_id=4085
$
$ pfunct -F btf examples/tcp.o | head
memset
memcpy
tcp_enter_memory_pressure
tcp_leave_memory_pressure
tcp_init_sock
tcp_init_transfer
tcp_poll
tcp_ioctl
tcp_splice_read
sk_stream_alloc_skb
$
$ pfunct --prototype -F btf examples/tcp.o | head
void * memset(void * p, int c, __kernel_size_t size);
void * memcpy(void * p, const void * q, __kernel_size_t size);
void tcp_enter_memory_pressure(struct sock * sk);
void tcp_leave_memory_pressure(struct sock * sk);
void tcp_init_sock(struct sock * sk);
void tcp_init_transfer(struct sock * sk, int bpf_op);
__poll_t tcp_poll(struct file * file, struct socket * sock, poll_table * wait);
int tcp_ioctl(struct sock * sk, int cmd, long unsigned int arg);
ssize_t tcp_splice_read(struct socket * sock, loff_t * ppos, struct pipe_inode_info * pipe, size_t len, unsigned int flags);
struct sk_buff * sk_stream_alloc_skb(struct sock * sk, int size, gfp_t gfp, bool force_schedule);
$
Now to ask just for the 'struct sock' 'methods', i.e. functions that
have as one of its arguments a pointer to the given 'class' name:
$ pfunct --class sock -F btf examples/tcp.o | head
tcp_abort
tcp_done
compat_tcp_getsockopt
tcp_getsockopt
tcp_get_info
compat_tcp_setsockopt
tcp_setsockopt
tcp_disconnect
tcp_write_queue_purge
tcp_close
$
Then ask for the prototypes, which requires -V, should have that fixed:
$ pfunct -V --prototypes --class sock -F btf examples/tcp.o | head
int tcp_abort(struct sock * sk, int err);
void tcp_done(struct sock * sk);
int compat_tcp_getsockopt(struct sock * sk, int level, int optname, char * optval, int * optlen);
int tcp_getsockopt(struct sock * sk, int level, int optname, char * optval, int * optlen);
void tcp_get_info(struct sock * sk, struct tcp_info * info);
int compat_tcp_setsockopt(struct sock * sk, int level, int optname, char * optval, unsigned int optlen);
int tcp_setsockopt(struct sock * sk, int level, int optname, char * optval, unsigned int optlen);
int tcp_disconnect(struct sock * sk, int flags);
void tcp_write_queue_purge(struct sock * sk);
void tcp_close(struct sock * sk, long int timeout);
$
Don't like prototypes with parm names, got you covered:
$ pfunct --no_parm_names -V --prototypes --class sock -F btf examples/tcp.o | head
int tcp_abort(struct sock *, int);
void tcp_done(struct sock *);
int compat_tcp_getsockopt(struct sock *, int, int, char *, int *);
int tcp_getsockopt(struct sock *, int, int, char *, int *);
void tcp_get_info(struct sock *, struct tcp_info *);
int compat_tcp_setsockopt(struct sock *, int, int, char *, unsigned int);
int tcp_setsockopt(struct sock *, int, int, char *, unsigned int);
int tcp_disconnect(struct sock *, int);
void tcp_write_queue_purge(struct sock *);
void tcp_close(struct sock *, long int);
$
Don't like long options and want just one function?
$ pfunct -f tcp_setsockopt -F btf examples/tcp.o
int tcp_setsockopt(struct sock * sk, int level, int optname, char * optval, unsigned int optlen);
$
Want to generate compileable code for all of those functions, full with
the necessary types, etc?
$ pfunct -F btf --compile examples/tcp.o > a.c
$ gcc -c -o a.o a.c
$ pfunct -F dwarf --prototypes --class sock a.o | head
pfunct: a.o: No debugging information found
$ gcc -g -c -o a.o a.c
$ pfunct -V -F dwarf --prototypes --class sock a.o | head
void tcp_enter_memory_pressure(struct sock * sk);
void tcp_leave_memory_pressure(struct sock * sk);
void tcp_init_sock(struct sock * sk);
void tcp_init_transfer(struct sock * sk, int bpf_op);
int tcp_ioctl(struct sock * sk, int cmd, long unsigned int arg);
struct sk_buff * sk_stream_alloc_skb(struct sock * sk, int size, gfp_t gfp, bool force_schedule);
ssize_t do_tcp_sendpages(struct sock * sk, struct page * page, int offset, size_t size, int flags);
int tcp_sendpage_locked(struct sock * sk, struct page * page, int offset, size_t size, int flags);
int tcp_sendpage(struct sock * sk, struct page * page, int offset, size_t size, int flags);
int tcp_sendmsg_locked(struct sock * sk, struct msghdr * msg, size_t size);
$
Now lets go full circle and encode BTF for this a.o generated from
source code generated from the original BTF info in that examples/tcp.o
file:
$ pahole -JV a.o | tail
[465] FUNC_PROTO (anon) return=35 args=(392 hp, 393 skb, 5 header_len)
[466] FUNC tcp_md5_hash_skb_data type_id=465
[467] FUNC_PROTO (anon) return=35 args=(392 hp, 394 key)
[468] FUNC tcp_md5_hash_key type_id=467
[469] FUNC_PROTO (anon) return=0 args=(49 sk)
[470] FUNC tcp_done type_id=469
[471] FUNC_PROTO (anon) return=35 args=(49 sk, 35 err)
[472] FUNC tcp_abort type_id=471
[473] FUNC_PROTO (anon) return=0 args=(void)
[474] FUNC tcp_init type_id=473
$
$ pfunct -F btf -V --prototypes --class=sock a.o | head
void tcp_enter_memory_pressure(struct sock * sk);
void tcp_leave_memory_pressure(struct sock * sk);
void tcp_init_sock(struct sock * sk);
void tcp_init_transfer(struct sock * sk, int bpf_op);
int tcp_ioctl(struct sock * sk, int cmd, long unsigned int arg);
struct sk_buff * sk_stream_alloc_skb(struct sock * sk, int size, gfp_t gfp, bool force_schedule);
ssize_t do_tcp_sendpages(struct sock * sk, struct page * page, int offset, size_t size, int flags);
int tcp_sendpage_locked(struct sock * sk, struct page * page, int offset, size_t size, int flags);
int tcp_sendpage(struct sock * sk, struct page * page, int offset, size_t size, int flags);
int tcp_sendmsg_locked(struct sock * sk, struct msghdr * msg, size_t size);
$
Curious about the code generated by 'pfunct -F btf --compile examples/tcp.o?
http://vger.kernel.org/~acme/pahole/pfunct-F-BTF--compile-examples-tcp.o.txt
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Andrii Nakryiko <andrii.nakryiko@gmail.com>
Cc: Andrii Nakryiko <andriin@fb.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Yonghong Song <yhs@fb.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-11-05 15:30:51 +01:00
|
|
|
struct ftype *proto = func->btf ? tag__ftype(cu__type(cu, func->proto.tag.type)) : &func->proto;
|
|
|
|
struct tag *type = cu__type(cu, proto->tag.type);
|
2019-04-04 20:39:26 +02:00
|
|
|
|
2019-04-16 01:17:22 +02:00
|
|
|
retry_return_type:
|
2019-04-04 22:07:19 +02:00
|
|
|
/* type == NULL means the return is void */
|
2019-04-16 01:17:22 +02:00
|
|
|
if (type == NULL)
|
|
|
|
goto do_parameters;
|
|
|
|
|
|
|
|
if (tag__is_pointer(type) || tag__is_modifier(type)) {
|
|
|
|
type = cu__type(cu, type->type);
|
|
|
|
goto retry_return_type;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tag__is_type(type) && !tag__type(type)->definition_emitted) {
|
2019-04-04 20:39:26 +02:00
|
|
|
type__emit_definitions(type, cu, &emissions, fp);
|
|
|
|
type__emit(type, cu, NULL, NULL, fp);
|
|
|
|
}
|
2019-04-16 01:17:22 +02:00
|
|
|
do_parameters:
|
btf_loader: Add support for BTF_KIND_FUNC
Some changes to the fprintf routines were needed, as BTF has as the
function type just a BTF_KIND_FUNC_PROTO, while DWARF has as the type
for a function its return value type. With a function->btf flag this was
overcome and all the other goodies in pfunct are present, for instance:
$ pahole -JV examples/tcp.o | grep -w FUNC | head
[4068] FUNC tcp_init type_id=4067
[4070] FUNC tcp_abort type_id=4069
[4072] FUNC tcp_done type_id=4071
[4074] FUNC tcp_md5_hash_key type_id=4073
[4076] FUNC tcp_md5_hash_skb_data type_id=4075
[4078] FUNC tcp_get_md5sig_pool type_id=4077
[4080] FUNC tcp_alloc_md5sig_pool type_id=4079
[4082] FUNC compat_tcp_getsockopt type_id=4081
[4084] FUNC tcp_getsockopt type_id=4083
[4086] FUNC tcp_get_timestamping_opt_stats type_id=4085
$
$ pfunct -F btf examples/tcp.o | head
memset
memcpy
tcp_enter_memory_pressure
tcp_leave_memory_pressure
tcp_init_sock
tcp_init_transfer
tcp_poll
tcp_ioctl
tcp_splice_read
sk_stream_alloc_skb
$
$ pfunct --prototype -F btf examples/tcp.o | head
void * memset(void * p, int c, __kernel_size_t size);
void * memcpy(void * p, const void * q, __kernel_size_t size);
void tcp_enter_memory_pressure(struct sock * sk);
void tcp_leave_memory_pressure(struct sock * sk);
void tcp_init_sock(struct sock * sk);
void tcp_init_transfer(struct sock * sk, int bpf_op);
__poll_t tcp_poll(struct file * file, struct socket * sock, poll_table * wait);
int tcp_ioctl(struct sock * sk, int cmd, long unsigned int arg);
ssize_t tcp_splice_read(struct socket * sock, loff_t * ppos, struct pipe_inode_info * pipe, size_t len, unsigned int flags);
struct sk_buff * sk_stream_alloc_skb(struct sock * sk, int size, gfp_t gfp, bool force_schedule);
$
Now to ask just for the 'struct sock' 'methods', i.e. functions that
have as one of its arguments a pointer to the given 'class' name:
$ pfunct --class sock -F btf examples/tcp.o | head
tcp_abort
tcp_done
compat_tcp_getsockopt
tcp_getsockopt
tcp_get_info
compat_tcp_setsockopt
tcp_setsockopt
tcp_disconnect
tcp_write_queue_purge
tcp_close
$
Then ask for the prototypes, which requires -V, should have that fixed:
$ pfunct -V --prototypes --class sock -F btf examples/tcp.o | head
int tcp_abort(struct sock * sk, int err);
void tcp_done(struct sock * sk);
int compat_tcp_getsockopt(struct sock * sk, int level, int optname, char * optval, int * optlen);
int tcp_getsockopt(struct sock * sk, int level, int optname, char * optval, int * optlen);
void tcp_get_info(struct sock * sk, struct tcp_info * info);
int compat_tcp_setsockopt(struct sock * sk, int level, int optname, char * optval, unsigned int optlen);
int tcp_setsockopt(struct sock * sk, int level, int optname, char * optval, unsigned int optlen);
int tcp_disconnect(struct sock * sk, int flags);
void tcp_write_queue_purge(struct sock * sk);
void tcp_close(struct sock * sk, long int timeout);
$
Don't like prototypes with parm names, got you covered:
$ pfunct --no_parm_names -V --prototypes --class sock -F btf examples/tcp.o | head
int tcp_abort(struct sock *, int);
void tcp_done(struct sock *);
int compat_tcp_getsockopt(struct sock *, int, int, char *, int *);
int tcp_getsockopt(struct sock *, int, int, char *, int *);
void tcp_get_info(struct sock *, struct tcp_info *);
int compat_tcp_setsockopt(struct sock *, int, int, char *, unsigned int);
int tcp_setsockopt(struct sock *, int, int, char *, unsigned int);
int tcp_disconnect(struct sock *, int);
void tcp_write_queue_purge(struct sock *);
void tcp_close(struct sock *, long int);
$
Don't like long options and want just one function?
$ pfunct -f tcp_setsockopt -F btf examples/tcp.o
int tcp_setsockopt(struct sock * sk, int level, int optname, char * optval, unsigned int optlen);
$
Want to generate compileable code for all of those functions, full with
the necessary types, etc?
$ pfunct -F btf --compile examples/tcp.o > a.c
$ gcc -c -o a.o a.c
$ pfunct -F dwarf --prototypes --class sock a.o | head
pfunct: a.o: No debugging information found
$ gcc -g -c -o a.o a.c
$ pfunct -V -F dwarf --prototypes --class sock a.o | head
void tcp_enter_memory_pressure(struct sock * sk);
void tcp_leave_memory_pressure(struct sock * sk);
void tcp_init_sock(struct sock * sk);
void tcp_init_transfer(struct sock * sk, int bpf_op);
int tcp_ioctl(struct sock * sk, int cmd, long unsigned int arg);
struct sk_buff * sk_stream_alloc_skb(struct sock * sk, int size, gfp_t gfp, bool force_schedule);
ssize_t do_tcp_sendpages(struct sock * sk, struct page * page, int offset, size_t size, int flags);
int tcp_sendpage_locked(struct sock * sk, struct page * page, int offset, size_t size, int flags);
int tcp_sendpage(struct sock * sk, struct page * page, int offset, size_t size, int flags);
int tcp_sendmsg_locked(struct sock * sk, struct msghdr * msg, size_t size);
$
Now lets go full circle and encode BTF for this a.o generated from
source code generated from the original BTF info in that examples/tcp.o
file:
$ pahole -JV a.o | tail
[465] FUNC_PROTO (anon) return=35 args=(392 hp, 393 skb, 5 header_len)
[466] FUNC tcp_md5_hash_skb_data type_id=465
[467] FUNC_PROTO (anon) return=35 args=(392 hp, 394 key)
[468] FUNC tcp_md5_hash_key type_id=467
[469] FUNC_PROTO (anon) return=0 args=(49 sk)
[470] FUNC tcp_done type_id=469
[471] FUNC_PROTO (anon) return=35 args=(49 sk, 35 err)
[472] FUNC tcp_abort type_id=471
[473] FUNC_PROTO (anon) return=0 args=(void)
[474] FUNC tcp_init type_id=473
$
$ pfunct -F btf -V --prototypes --class=sock a.o | head
void tcp_enter_memory_pressure(struct sock * sk);
void tcp_leave_memory_pressure(struct sock * sk);
void tcp_init_sock(struct sock * sk);
void tcp_init_transfer(struct sock * sk, int bpf_op);
int tcp_ioctl(struct sock * sk, int cmd, long unsigned int arg);
struct sk_buff * sk_stream_alloc_skb(struct sock * sk, int size, gfp_t gfp, bool force_schedule);
ssize_t do_tcp_sendpages(struct sock * sk, struct page * page, int offset, size_t size, int flags);
int tcp_sendpage_locked(struct sock * sk, struct page * page, int offset, size_t size, int flags);
int tcp_sendpage(struct sock * sk, struct page * page, int offset, size_t size, int flags);
int tcp_sendmsg_locked(struct sock * sk, struct msghdr * msg, size_t size);
$
Curious about the code generated by 'pfunct -F btf --compile examples/tcp.o?
http://vger.kernel.org/~acme/pahole/pfunct-F-BTF--compile-examples-tcp.o.txt
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Andrii Nakryiko <andrii.nakryiko@gmail.com>
Cc: Andrii Nakryiko <andriin@fb.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Yonghong Song <yhs@fb.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-11-05 15:30:51 +01:00
|
|
|
ftype__for_each_parameter(proto, pos) {
|
2019-04-04 20:39:26 +02:00
|
|
|
type = cu__type(cu, pos->tag.type);
|
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
|
|
|
try_again:
|
|
|
|
if (type == NULL)
|
|
|
|
continue;
|
|
|
|
|
2019-04-05 20:21:55 +02:00
|
|
|
if (tag__is_pointer(type) || tag__is_modifier(type)) {
|
2009-03-18 16:17:07 +01:00
|
|
|
type = cu__type(cu, type->type);
|
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
|
|
|
goto try_again;
|
|
|
|
}
|
|
|
|
|
pfunct: Emit definitions for pointers inside pointer to function args
When using --compile we were missing emitting the types for function
arguments in function pointers arguments, i.e.:
Before:
/home/acme/git/build/v5.1-rc4+/kernel/events/core.o
/tmp/fullcircle.CZeLch.c:3770:141: warning: ‘struct perf_output_handle’ declared inside parameter list will not be visible outside of this definition or declaration
inline int __perf_event_output(struct perf_event * event, struct perf_sample_data * data, struct pt_regs * regs, int (*output_begin)(struct perf_output_handle *, struct perf_event *, unsigned int))
^~~~~~~~~~~~~~~~~~
After:
$ pfunct --compile /home/acme/git/build/v5.1-rc4+/kernel/events/core.o > a.c
$ gcc -g -c a.c
$ grep -w perf_output_handle -m1 -A5 a.c
struct perf_output_handle;
inline int __perf_event_output(struct perf_event * event, struct perf_sample_data * data, struct pt_regs * regs, int (*output_begin)(struct perf_output_handle *, struct perf_event *, unsigned int))
{
return 0;
}
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-16 19:05:01 +02:00
|
|
|
if (type->tag == DW_TAG_subroutine_type) {
|
|
|
|
ftype__emit_definitions(tag__ftype(type), cu, &emissions, fp);
|
|
|
|
} else if (tag__is_type(type) && !tag__type(type)->definition_emitted) {
|
2008-10-01 17:43:01 +02:00
|
|
|
type__emit_definitions(type, cu, &emissions, fp);
|
2019-04-05 02:15:56 +02:00
|
|
|
if (!tag__is_typedef(type))
|
|
|
|
type__emit(type, cu, NULL, NULL, 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
|
|
|
putchar('\n');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void function__show(struct function *func, struct cu *cu)
|
2009-06-04 19:56:44 +02:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
struct tag *tag = function__tag(func);
|
2009-06-04 19:56:44 +02:00
|
|
|
|
2019-04-05 02:27:41 +02:00
|
|
|
if (func->abstract_origin || func->external)
|
2019-04-05 02:22:42 +02:00
|
|
|
return;
|
|
|
|
|
2009-06-04 19:56:44 +02:00
|
|
|
if (expand_types)
|
2012-08-17 23:47:15 +02:00
|
|
|
function__emit_type_definitions(func, cu, stdout);
|
2009-06-04 19:56:44 +02:00
|
|
|
tag__fprintf(tag, cu, &conf, stdout);
|
2019-04-05 21:33:43 +02:00
|
|
|
if (compilable_output) {
|
2019-04-16 01:17:22 +02:00
|
|
|
struct tag *type = cu__type(cu, func->proto.tag.type);
|
2019-04-05 21:33:43 +02:00
|
|
|
|
|
|
|
fprintf(stdout, "\n{");
|
2019-11-05 16:03:16 +01:00
|
|
|
if (type != NULL && type->type != 0) { /* NULL == void */
|
2019-04-05 21:33:43 +02:00
|
|
|
if (tag__is_pointer(type))
|
|
|
|
fprintf(stdout, "\n\treturn (void *)0;");
|
|
|
|
else if (tag__is_struct(type))
|
|
|
|
fprintf(stdout, "\n\treturn *(struct %s *)1;", class__name(tag__class(type), cu));
|
2019-04-16 01:17:22 +02:00
|
|
|
else if (tag__is_union(type))
|
|
|
|
fprintf(stdout, "\n\treturn *(union %s *)1;", type__name(tag__type(type), cu));
|
|
|
|
else if (tag__is_typedef(type))
|
|
|
|
fprintf(stdout, "\n\treturn *(%s *)1;", type__name(tag__type(type), cu));
|
2019-04-05 21:33:43 +02:00
|
|
|
else
|
|
|
|
fprintf(stdout, "\n\treturn 0;");
|
|
|
|
}
|
|
|
|
fprintf(stdout, "\n}\n");
|
|
|
|
}
|
2009-06-04 19:56:44 +02:00
|
|
|
putchar('\n');
|
|
|
|
if (show_variables || show_inline_expansions)
|
|
|
|
function__fprintf_stats(tag, cu, &conf, stdout);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cu_function_iterator(struct cu *cu, void *cookie)
|
2006-10-31 21:23:16 +01:00
|
|
|
{
|
2007-01-04 00:29:24 +01:00
|
|
|
struct function *function;
|
2009-04-01 16:55:49 +02:00
|
|
|
uint32_t id;
|
2007-01-04 00:29:24 +01:00
|
|
|
|
2009-04-01 16:55:49 +02:00
|
|
|
cu__for_each_function(cu, id, function) {
|
2019-04-04 20:49:19 +02:00
|
|
|
if (cookie && strcmp(function__name(function, cu), cookie) != 0)
|
2009-04-01 16:55:49 +02:00
|
|
|
continue;
|
2009-06-04 19:56:44 +02:00
|
|
|
function__show(function, cu);
|
2019-04-04 20:49:19 +02:00
|
|
|
if (!expand_types)
|
|
|
|
return 1;
|
2006-10-31 21:23:16 +01:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-03-25 22:03:28 +01:00
|
|
|
int elf_symtab__show(char *filename)
|
|
|
|
{
|
|
|
|
int fd = open(filename, O_RDONLY), err = -1;
|
|
|
|
if (fd < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (elf_version(EV_CURRENT) == EV_NONE) {
|
|
|
|
fprintf(stderr, "%s: cannot set libelf version.\n", __func__);
|
|
|
|
goto out_close;
|
|
|
|
}
|
|
|
|
|
|
|
|
Elf *elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
|
|
|
|
if (elf == NULL) {
|
|
|
|
fprintf(stderr, "%s: cannot read %s ELF file.\n",
|
|
|
|
__func__, filename);
|
|
|
|
goto out_close;
|
|
|
|
}
|
|
|
|
|
|
|
|
GElf_Ehdr ehdr;
|
|
|
|
if (gelf_getehdr(elf, &ehdr) == NULL) {
|
|
|
|
fprintf(stderr, "%s: cannot get elf header.\n", __func__);
|
|
|
|
goto out_elf_end;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct elf_symtab *symtab = elf_symtab__new(symtab_name, elf, &ehdr);
|
|
|
|
if (symtab == NULL)
|
|
|
|
goto out_elf_end;
|
|
|
|
|
|
|
|
GElf_Sym sym;
|
|
|
|
uint32_t index;
|
|
|
|
int longest_name = 0;
|
|
|
|
elf_symtab__for_each_symbol(symtab, index, sym) {
|
2009-03-28 23:27:00 +01:00
|
|
|
if (!elf_sym__is_local_function(&sym))
|
2009-03-25 22:03:28 +01:00
|
|
|
continue;
|
|
|
|
int len = strlen(elf_sym__name(&sym, symtab));
|
|
|
|
if (len > longest_name)
|
|
|
|
longest_name = len;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (longest_name > 32)
|
|
|
|
longest_name = 32;
|
|
|
|
|
|
|
|
int index_spacing = 0;
|
|
|
|
int nr = elf_symtab__nr_symbols(symtab);
|
|
|
|
while (nr) {
|
|
|
|
++index_spacing;
|
|
|
|
nr /= 10;
|
|
|
|
}
|
|
|
|
|
|
|
|
elf_symtab__for_each_symbol(symtab, index, sym) {
|
2009-03-28 23:27:00 +01:00
|
|
|
if (!elf_sym__is_local_function(&sym))
|
2009-03-25 22:03:28 +01:00
|
|
|
continue;
|
|
|
|
printf("%*d: %-*s %#llx %5u\n",
|
|
|
|
index_spacing, index, longest_name,
|
|
|
|
elf_sym__name(&sym, symtab),
|
|
|
|
(unsigned long long)elf_sym__value(&sym),
|
|
|
|
elf_sym__size(&sym));
|
|
|
|
}
|
|
|
|
|
|
|
|
elf_symtab__delete(symtab);
|
|
|
|
err = 0;
|
|
|
|
out_elf_end:
|
|
|
|
elf_end(elf);
|
|
|
|
out_close:
|
|
|
|
close(fd);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
int elf_symtabs__show(char *filenames[])
|
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
while (filenames[i] != NULL) {
|
|
|
|
if (elf_symtab__show(filenames[i]))
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2009-02-13 13:57:23 +01:00
|
|
|
/* Name and version of program. */
|
|
|
|
ARGP_PROGRAM_VERSION_HOOK_DEF = dwarves_print_version;
|
|
|
|
|
2009-03-31 02:47:59 +02:00
|
|
|
#define ARGP_symtab 300
|
|
|
|
#define ARGP_no_parm_names 301
|
2019-04-04 21:03:33 +02:00
|
|
|
#define ARGP_compile 302
|
2009-03-25 22:03:28 +01:00
|
|
|
|
2007-03-30 15:24:13 +02:00
|
|
|
static const struct argp_option pfunct__options[] = {
|
2009-06-04 19:56:44 +02:00
|
|
|
{
|
|
|
|
.key = 'a',
|
|
|
|
.name = "addr",
|
|
|
|
.arg = "ADDR",
|
|
|
|
.doc = "show just the function that where ADDR is",
|
|
|
|
},
|
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",
|
|
|
|
},
|
2009-03-24 20:39:14 +01:00
|
|
|
{
|
|
|
|
.name = "format_path",
|
|
|
|
.key = 'F',
|
|
|
|
.arg = "FORMAT_LIST",
|
|
|
|
.doc = "List of debugging formats to try"
|
|
|
|
},
|
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",
|
|
|
|
},
|
2010-05-04 18:33:08 +02:00
|
|
|
{
|
|
|
|
.key = 'P',
|
|
|
|
.name = "prototypes",
|
|
|
|
.doc = "show function prototypes",
|
|
|
|
},
|
2007-03-30 15:24:13 +02:00
|
|
|
{
|
|
|
|
.key = 'S',
|
|
|
|
.name = "nr_variables",
|
|
|
|
.doc = "show number of variables",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.key = 'T',
|
|
|
|
.name = "variables",
|
|
|
|
.doc = "show variables",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.key = 'V',
|
|
|
|
.name = "verbose",
|
|
|
|
.doc = "be verbose",
|
|
|
|
},
|
2009-03-25 22:03:28 +01:00
|
|
|
{
|
|
|
|
.name = "symtab",
|
|
|
|
.key = ARGP_symtab,
|
|
|
|
.arg = "NAME",
|
|
|
|
.flags = OPTION_ARG_OPTIONAL,
|
|
|
|
.doc = "show symbol table NAME (Default .symtab)",
|
|
|
|
},
|
2019-04-04 21:03:33 +02:00
|
|
|
{
|
|
|
|
.name = "compile",
|
|
|
|
.key = ARGP_compile,
|
|
|
|
.arg = "FUNCTION",
|
|
|
|
.flags = OPTION_ARG_OPTIONAL,
|
|
|
|
.doc = "Generate compilable source code with types expanded (Default all functions)",
|
|
|
|
},
|
2009-03-31 02:47:59 +02:00
|
|
|
{
|
|
|
|
.name = "no_parm_names",
|
|
|
|
.key = ARGP_no_parm_names,
|
|
|
|
.doc = "Don't show parameter names",
|
|
|
|
},
|
2007-03-30 15:24:13 +02:00
|
|
|
{
|
|
|
|
.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) {
|
2008-11-18 17:09:13 +01:00
|
|
|
case ARGP_KEY_INIT:
|
|
|
|
if (state->child_inputs != NULL)
|
|
|
|
state->child_inputs[0] = state->input;
|
|
|
|
break;
|
2009-07-06 18:44:57 +02:00
|
|
|
case 'a': addr = strtoull(arg, NULL, 0);
|
|
|
|
conf_load.get_addr_info = true; 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;
|
2009-03-24 20:39:14 +01:00
|
|
|
case 'F': conf_load.format_path = arg; break;
|
2007-03-30 18:45:57 +02:00
|
|
|
case 'E': show_externals = 1; break;
|
2009-07-06 18:44:57 +02:00
|
|
|
case 's': formatter = fn_stats_size_fmtr;
|
|
|
|
conf_load.get_addr_info = true; break;
|
2007-03-30 15:24:13 +02:00
|
|
|
case 'S': formatter = fn_stats_variables_fmtr; break;
|
|
|
|
case 'p': formatter = fn_stats_nr_parms_fmtr; break;
|
2010-05-04 18:33:08 +02:00
|
|
|
case 'P': show_prototypes = true; break;
|
2007-03-30 15:24:13 +02:00
|
|
|
case 'g': formatter = fn_stats_labels_fmtr; break;
|
|
|
|
case 'G': show_cc_uninlined = 1; break;
|
|
|
|
case 'H': show_cc_inlined = 1; break;
|
2009-03-09 18:43:47 +01:00
|
|
|
case 'i': show_inline_expansions = verbose = 1;
|
2009-07-06 18:44:57 +02:00
|
|
|
conf_load.extra_dbg_info = true;
|
|
|
|
conf_load.get_addr_info = true; break;
|
|
|
|
case 'I': formatter = fn_stats_inline_exps_fmtr;
|
|
|
|
conf_load.get_addr_info = true; break;
|
2009-03-09 18:43:47 +01:00
|
|
|
case 'l': conf.show_decl_info = 1;
|
|
|
|
conf_load.extra_dbg_info = 1; break;
|
2009-07-06 18:44:57 +02:00
|
|
|
case 't': show_total_inline_expansion_stats = true;
|
|
|
|
conf_load.get_addr_info = true; break;
|
2007-03-30 15:24:13 +02:00
|
|
|
case 'T': show_variables = 1; break;
|
|
|
|
case 'N': formatter = fn_stats_name_len_fmtr; break;
|
2009-03-09 18:43:47 +01:00
|
|
|
case 'V': verbose = 1;
|
2009-07-06 18:44:57 +02:00
|
|
|
conf_load.extra_dbg_info = true;
|
|
|
|
conf_load.get_addr_info = true; break;
|
2009-03-25 22:03:28 +01:00
|
|
|
case ARGP_symtab: symtab_name = arg ?: ".symtab"; break;
|
2009-03-31 02:47:59 +02:00
|
|
|
case ARGP_no_parm_names: conf.no_parm_names = 1; break;
|
2019-04-04 21:03:33 +02:00
|
|
|
case ARGP_compile:
|
|
|
|
expand_types = true;
|
|
|
|
type_emissions__init(&emissions);
|
|
|
|
compilable_output = true;
|
|
|
|
conf.no_semicolon = true;
|
2019-04-16 20:00:44 +02:00
|
|
|
conf.strip_inline = true;
|
2019-04-04 21:03:33 +02:00
|
|
|
if (arg)
|
|
|
|
function_name = arg;
|
|
|
|
break;
|
2007-03-30 15:24:13 +02:00
|
|
|
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[])
|
|
|
|
{
|
2009-03-11 16:31:17 +01:00
|
|
|
int err, remaining, rc = EXIT_FAILURE;
|
2006-11-11 19:31:04 +01:00
|
|
|
|
2009-02-10 00:43:56 +01:00
|
|
|
if (argp_parse(&pfunct__argp, argc, argv, 0, &remaining, NULL) ||
|
2017-11-24 15:24:16 +01:00
|
|
|
(remaining == argc && class_name == NULL && function_name == NULL)) {
|
2009-02-10 00:43:56 +01:00
|
|
|
argp_help(&pfunct__argp, stderr, ARGP_HELP_SEE, argv[0]);
|
2009-03-11 16:31:17 +01:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2009-03-25 22:03:28 +01:00
|
|
|
if (symtab_name != NULL)
|
|
|
|
return elf_symtabs__show(argv + remaining);
|
|
|
|
|
all: Fix possible uninitialized variable uses
I wasn't especifying the optimization level and the default, despite
using -Wall, was for this so simple case not to be warned about, so
now I'm using -O2.
Alexandre provided a patch initializing the variables to NULL, so that
when we called cus__delete it would bail out and not possibly act on
a random value, I preferred to add extra goto labels and do the exit
path only on the resources that were successfully allocated/initialized,
avoiding, for instance, to call dwarves_exit() if dwarves_init() wasn't
called, which wasn't a problem so far, but could be in the future.
Reported-by: Alexandre Vassalotti <alexandre@peadrop.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-05-04 20:50:06 +02:00
|
|
|
if (dwarves__init(0)) {
|
2009-03-11 16:31:17 +01:00
|
|
|
fputs("pfunct: insufficient memory\n", stderr);
|
|
|
|
goto out;
|
2009-02-10 00:43:56 +01:00
|
|
|
}
|
|
|
|
|
all: Fix possible uninitialized variable uses
I wasn't especifying the optimization level and the default, despite
using -Wall, was for this so simple case not to be warned about, so
now I'm using -O2.
Alexandre provided a patch initializing the variables to NULL, so that
when we called cus__delete it would bail out and not possibly act on
a random value, I preferred to add extra goto labels and do the exit
path only on the resources that were successfully allocated/initialized,
avoiding, for instance, to call dwarves_exit() if dwarves_init() wasn't
called, which wasn't a problem so far, but could be in the future.
Reported-by: Alexandre Vassalotti <alexandre@peadrop.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-05-04 20:50:06 +02:00
|
|
|
struct cus *cus = cus__new();
|
|
|
|
if (cus == NULL) {
|
|
|
|
fputs("pfunct: insufficient memory\n", stderr);
|
|
|
|
goto out_dwarves_exit;
|
|
|
|
}
|
|
|
|
|
2020-11-10 18:57:35 +01:00
|
|
|
try_sole_arg_as_function_name:
|
2009-03-13 14:49:01 +01:00
|
|
|
err = cus__load_files(cus, &conf_load, argv + remaining);
|
2016-03-15 18:29:57 +01:00
|
|
|
if (err != 0) {
|
2020-11-10 18:57:35 +01:00
|
|
|
if (function_name == NULL) {
|
|
|
|
function_name = argv[remaining];
|
|
|
|
if (access(function_name, R_OK) == 0) {
|
|
|
|
fprintf(stderr, "pfunct: file '%s' has no %s type information.\n",
|
|
|
|
function_name, conf_load.format_path ?: "supported");
|
|
|
|
goto out_dwarves_exit;
|
|
|
|
}
|
|
|
|
remaining = argc;
|
|
|
|
goto try_sole_arg_as_function_name;
|
|
|
|
}
|
2016-03-15 18:29:57 +01:00
|
|
|
cus__fprintf_load_files_err(cus, "pfunct", argv + remaining, err, stderr);
|
all: Fix possible uninitialized variable uses
I wasn't especifying the optimization level and the default, despite
using -Wall, was for this so simple case not to be warned about, so
now I'm using -O2.
Alexandre provided a patch initializing the variables to NULL, so that
when we called cus__delete it would bail out and not possibly act on
a random value, I preferred to add extra goto labels and do the exit
path only on the resources that were successfully allocated/initialized,
avoiding, for instance, to call dwarves_exit() if dwarves_init() wasn't
called, which wasn't a problem so far, but could be in the future.
Reported-by: Alexandre Vassalotti <alexandre@peadrop.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-05-04 20:50:06 +02:00
|
|
|
goto out_cus_delete;
|
2016-03-15 18:29:57 +01:00
|
|
|
}
|
2007-03-30 18:45:57 +02:00
|
|
|
|
2020-11-10 18:57:35 +01:00
|
|
|
|
2006-12-18 18:43:17 +01:00
|
|
|
cus__for_each_cu(cus, cu_unique_iterator, NULL, NULL);
|
|
|
|
|
2009-06-04 19:56:44 +02:00
|
|
|
if (addr) {
|
|
|
|
struct cu *cu;
|
|
|
|
struct function *f = cus__find_function_at_addr(cus, addr, &cu);
|
|
|
|
|
|
|
|
if (f == NULL) {
|
|
|
|
fprintf(stderr, "pfunct: No function found at %#llx!\n",
|
|
|
|
(unsigned long long)addr);
|
|
|
|
goto out_cus_delete;
|
|
|
|
}
|
|
|
|
function__show(f, cu);
|
|
|
|
} else 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);
|
2019-04-04 20:49:19 +02:00
|
|
|
else if (function_name != NULL || expand_types)
|
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
|
|
|
|
2009-03-11 16:31:17 +01:00
|
|
|
rc = EXIT_SUCCESS;
|
all: Fix possible uninitialized variable uses
I wasn't especifying the optimization level and the default, despite
using -Wall, was for this so simple case not to be warned about, so
now I'm using -O2.
Alexandre provided a patch initializing the variables to NULL, so that
when we called cus__delete it would bail out and not possibly act on
a random value, I preferred to add extra goto labels and do the exit
path only on the resources that were successfully allocated/initialized,
avoiding, for instance, to call dwarves_exit() if dwarves_init() wasn't
called, which wasn't a problem so far, but could be in the future.
Reported-by: Alexandre Vassalotti <alexandre@peadrop.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-05-04 20:50:06 +02:00
|
|
|
out_cus_delete:
|
2009-03-11 16:31:17 +01:00
|
|
|
cus__delete(cus);
|
|
|
|
fn_stats__delete_list();
|
all: Fix possible uninitialized variable uses
I wasn't especifying the optimization level and the default, despite
using -Wall, was for this so simple case not to be warned about, so
now I'm using -O2.
Alexandre provided a patch initializing the variables to NULL, so that
when we called cus__delete it would bail out and not possibly act on
a random value, I preferred to add extra goto labels and do the exit
path only on the resources that were successfully allocated/initialized,
avoiding, for instance, to call dwarves_exit() if dwarves_init() wasn't
called, which wasn't a problem so far, but could be in the future.
Reported-by: Alexandre Vassalotti <alexandre@peadrop.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-05-04 20:50:06 +02:00
|
|
|
out_dwarves_exit:
|
2009-03-11 16:31:17 +01:00
|
|
|
dwarves__exit();
|
all: Fix possible uninitialized variable uses
I wasn't especifying the optimization level and the default, despite
using -Wall, was for this so simple case not to be warned about, so
now I'm using -O2.
Alexandre provided a patch initializing the variables to NULL, so that
when we called cus__delete it would bail out and not possibly act on
a random value, I preferred to add extra goto labels and do the exit
path only on the resources that were successfully allocated/initialized,
avoiding, for instance, to call dwarves_exit() if dwarves_init() wasn't
called, which wasn't a problem so far, but could be in the future.
Reported-by: Alexandre Vassalotti <alexandre@peadrop.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-05-04 20:50:06 +02:00
|
|
|
out:
|
2009-03-11 16:31:17 +01:00
|
|
|
return rc;
|
2006-10-29 00:07:45 +02:00
|
|
|
}
|