2007-01-29 14:18:46 +01:00
|
|
|
/*
|
2006-10-25 17:49:47 +02:00
|
|
|
Copyright (C) 2006 Mandriva Conectiva S.A.
|
|
|
|
Copyright (C) 2006 Arnaldo Carvalho de Melo <acme@mandriva.com>
|
2008-02-07 12:16:22 +01:00
|
|
|
Copyright (C) 2007-2008 Arnaldo Carvalho de Melo <acme@redhat.com>
|
2006-10-25 17:49:47 +02:00
|
|
|
|
2006-10-25 01:42:39 +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:07:01 +02:00
|
|
|
#include <argp.h>
|
2008-10-28 21:56:47 +01:00
|
|
|
#include <assert.h>
|
2006-10-25 01:42:39 +02:00
|
|
|
#include <stdio.h>
|
2006-10-28 23:22:42 +02:00
|
|
|
#include <dwarf.h>
|
2008-10-28 21:56:47 +01:00
|
|
|
#include <search.h>
|
2006-12-18 13:47:39 +01:00
|
|
|
#include <stdarg.h>
|
2006-10-25 01:42:39 +02:00
|
|
|
#include <stdlib.h>
|
2006-11-11 17:15:50 +01:00
|
|
|
#include <string.h>
|
2006-10-25 01:42:39 +02:00
|
|
|
|
2007-05-07 05:30:02 +02:00
|
|
|
#include "dwarves_reorganize.h"
|
2007-01-11 19:07:05 +01:00
|
|
|
#include "dwarves.h"
|
2007-12-16 17:47:59 +01:00
|
|
|
#include "dutil.h"
|
2009-03-19 16:16:07 +01:00
|
|
|
#include "ctf_encoder.h"
|
|
|
|
|
|
|
|
static bool ctf_encode;
|
2009-08-24 20:13:58 +02:00
|
|
|
static bool first_obj_only;
|
2006-10-25 01:42:39 +02:00
|
|
|
|
2007-01-28 14:07:22 +01:00
|
|
|
static uint8_t class__include_anonymous;
|
|
|
|
static uint8_t class__include_nested_anonymous;
|
2008-01-12 16:14:40 +01:00
|
|
|
static uint8_t word_size, original_word_size;
|
2007-01-28 14:07:22 +01:00
|
|
|
|
2006-12-01 02:23:41 +01:00
|
|
|
static char *class__exclude_prefix;
|
|
|
|
static size_t class__exclude_prefix_len;
|
2006-12-01 02:12:21 +01:00
|
|
|
|
2008-04-21 17:41:44 +02:00
|
|
|
static char *class__include_prefix;
|
|
|
|
static size_t class__include_prefix_len;
|
|
|
|
|
2006-12-01 02:36:55 +01:00
|
|
|
static char *cu__exclude_prefix;
|
|
|
|
static size_t cu__exclude_prefix_len;
|
|
|
|
|
2006-12-01 03:08:10 +01:00
|
|
|
static char *decl_exclude_prefix;
|
|
|
|
static size_t decl_exclude_prefix_len;
|
|
|
|
|
2006-12-28 14:18:43 +01:00
|
|
|
static uint16_t nr_holes;
|
|
|
|
static uint16_t nr_bit_holes;
|
[LIB]: Introduce class__has_hole_ge()
That returns if the class has a hole greater or equal to the size specified.
Pahole now has a --hole_size_ge command line option to use it.
Example on a linux kernel built for x86_64 where we list the structs that have
holes bigger than 32 bytes, that provides an approximation of structs with
____cacheline_aligned_in_smp annotated members:
[acme@filo pahole]$ pahole --hole_size_ge 32 examples/vmlinux-x86_64
inet_hashinfo
rcu_ctrlblk
hh_cache
net_device
files_struct
module
zone
For instance, look at struct zone clever use of such construct:
_pad1_ is defined with ZONE_PADDING(_pad1_), that is:
/* <40e> /home/acme/git/net-2.6.22/include/linux/mmzone.h:179 */
struct zone {
long unsigned int pages_min; /* 0 8 */
long unsigned int pages_low; /* 8 8 */
long unsigned int pages_high; /* 16 8 */
long unsigned int lowmem_reserve[3]; /* 24 24 */
int node; /* 48 4 */
/* XXX 4 bytes hole, try to pack */
long unsigned int min_unmapped_pages; /* 56 8 */
/* --- cacheline 1 boundary (64 bytes) --- */
long unsigned int min_slab_pages; /* 64 8 */
struct per_cpu_pageset * pageset[255]; /* 72 2040 */
/* --- cacheline 33 boundary (2112 bytes) --- */
spinlock_t lock; /* 2112 4 */
/* XXX 4 bytes hole, try to pack */
struct free_area free_area[11]; /* 2120 264 */
/* XXX 48 bytes hole, try to pack */
/* --- cacheline 38 boundary (2432 bytes) --- */
struct zone_padding _pad1_; /* 2432 0 */
spinlock_t lru_lock; /* 2432 4 */
/* XXX 4 bytes hole, try to pack */
struct list_head active_list; /* 2440 16 */
struct list_head inactive_list; /* 2456 16 */
long unsigned int nr_scan_active; /* 2472 8 */
long unsigned int nr_scan_inactive; /* 2480 8 */
long unsigned int pages_scanned; /* 2488 8 */
/* --- cacheline 39 boundary (2496 bytes) --- */
int all_unreclaimable; /* 2496 4 */
atomic_t reclaim_in_progress; /* 2500 4 */
atomic_long_t vm_stat[20]; /* 2504 160 */
/* --- cacheline 41 boundary (2624 bytes) was 40 bytes ago --- */
int prev_priority; /* 2664 4 */
/* XXX 20 bytes hole, try to pack */
/* --- cacheline 42 boundary (2688 bytes) --- */
struct zone_padding _pad2_; /* 2688 0 */
wait_queue_head_t * wait_table; /* 2688 8 */
long unsigned int wait_table_hash_nr_entries; /* 2696 8 */
long unsigned int wait_table_bits; /* 2704 8 */
struct pglist_data * zone_pgdat; /* 2712 8 */
long unsigned int zone_start_pfn; /* 2720 8 */
long unsigned int spanned_pages; /* 2728 8 */
long unsigned int present_pages; /* 2736 8 */
const char * name; /* 2744 8 */
/* --- cacheline 43 boundary (2752 bytes) --- */
}; /* size: 2752, cachelines: 43 */
/* sum members: 2672, holes: 5, sum holes: 80 */
/* definitions: 933 */
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-05-11 18:32:53 +02:00
|
|
|
static uint16_t hole_size_ge;
|
2006-12-18 19:27:14 +01:00
|
|
|
static uint8_t show_packable;
|
[PAHOLE]: Reorganize bitfields
This cset also does a fixup for cases where the compiler keeps the type
specified by the programmer for a bitfield but uses less space to combine with
the next, non-bitfield member, these cases can be caught using plain pahole and
will appear with this comment:
/* --- cacheline 1 boundary (64 bytes) --- */
int bitfield1:1; /* 64 4 */
int bitfield2:1; /* 64 4 */
/* XXX 14 bits hole, try to pack */
/* Bitfield WARNING: DWARF size=4, real size=2 */
short int d; /* 66 2 */
The fixup is done prior to reorganizing the fields.
Now an example of this code in action:
[acme@filo examples]$ cat swiss_cheese.c
<SNIP>
struct cheese {
char id;
short number;
char name[52];
int a:1;
int b;
int bitfield1:1;
int bitfield2:1;
short d;
short e;
short last:5;
};
<SNIP>
[acme@filo examples]$
Lets look at the layout:
[acme@filo examples]$ pahole swiss_cheese cheese
/* <11b> /home/acme/git/pahole/examples/swiss_cheese.c:3 */
struct cheese {
char id; /* 0 1 */
/* XXX 1 byte hole, try to pack */
short int number; /* 2 2 */
char name[52]; /* 4 52 */
int a:1; /* 56 4 */
/* XXX 31 bits hole, try to pack */
int b; /* 60 4 */
/* --- cacheline 1 boundary (64 bytes) --- */
int bitfield1:1; /* 64 4 */
int bitfield2:1; /* 64 4 */
/* XXX 14 bits hole, try to pack */
/* Bitfield WARNING: DWARF size=4, real size=2 */
short int d; /* 66 2 */
short int e; /* 68 2 */
short int last:5; /* 70 2 */
}; /* size: 72, cachelines: 2 */
/* sum members: 71, holes: 1, sum holes: 1 */
/* bit holes: 2, sum bit holes: 45 bits */
/* bit_padding: 11 bits */
/* last cacheline: 8 bytes */
[acme@filo examples]$
Full of holes, has bit padding and uses more than one 64 bytes cacheline.
Now lets ask pahole to reorganize it:
[acme@filo examples]$ pahole --reorganize --verbose swiss_cheese cheese
/* Demoting bitfield ('a' ... 'a') from 'int' to 'unsigned char' */
/* Demoting bitfield ('bitfield1' ... 'bitfield2') from 'short unsigned int' to 'unsigned char' */
/* Demoting bitfield ('last') from 'short int' to 'unsigned char' */
/* Moving 'bitfield2:1' from after 'bitfield1' to after 'a:1' */
/* Moving 'bitfield1:1' from after 'b' to after 'bitfield2:1' */
/* Moving 'last:5' from after 'e' to after 'bitfield1:1' */
/* Moving bitfield('a' ... 'last') from after 'name' to after 'id' */
/* Moving 'e' from after 'd' to after 'b' */
/* <11b> /home/acme/git/pahole/examples/swiss_cheese.c:3 */
struct cheese {
char id; /* 0 1 */
unsigned char a:1; /* 1 1 */
unsigned char bitfield2:1; /* 1 1 */
unsigned char bitfield1:1; /* 1 1 */
unsigned char last:5; /* 1 1 */
short int number; /* 2 2 */
char name[52]; /* 4 52 */
int b; /* 56 4 */
short int e; /* 60 2 */
short int d; /* 62 2 */
/* --- cacheline 1 boundary (64 bytes) --- */
}; /* size: 64, cachelines: 1 */
/* saved 8 bytes and 1 cacheline! */
[acme@filo examples]$
Instant karma, it gets completely packed, and look ma, no
__attribute__((packed)) :-)
With this struct task_struct in the linux kernel is shrunk by 12 bytes, there
is more 4 bytes to save with another technique that involves not combining
holes, but using the last single hole to fill it with members at the tail of
the struct.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2007-02-01 13:51:16 +01:00
|
|
|
static uint8_t global_verbose;
|
2007-05-11 00:11:51 +02:00
|
|
|
static uint8_t recursive;
|
2007-03-30 15:07:01 +02:00
|
|
|
static size_t cacheline_size;
|
2007-05-10 20:28:00 +02:00
|
|
|
static uint8_t find_containers;
|
2007-11-16 21:18:08 +01:00
|
|
|
static uint8_t find_pointers_in_structs;
|
2007-03-30 15:07:01 +02:00
|
|
|
static int reorganize;
|
2009-03-20 15:37:22 +01:00
|
|
|
static bool show_private_classes;
|
2008-02-07 12:16:22 +01:00
|
|
|
static bool defined_in;
|
2007-03-30 15:07:01 +02:00
|
|
|
static int show_reorg_steps;
|
2007-04-24 21:09:34 +02:00
|
|
|
static char *class_name;
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
static struct strlist *class_names;
|
2007-05-23 21:15:21 +02:00
|
|
|
static char separator = '\t';
|
2006-12-07 19:14:15 +01:00
|
|
|
|
2007-06-22 21:43:29 +02:00
|
|
|
static struct conf_fprintf conf = {
|
2007-05-24 22:18:32 +02:00
|
|
|
.emit_stats = 1,
|
|
|
|
};
|
|
|
|
|
2009-03-09 18:43:47 +01:00
|
|
|
static struct conf_load conf_load;
|
|
|
|
|
2006-11-04 00:24:37 +01:00
|
|
|
struct structure {
|
2007-05-24 23:45:34 +02:00
|
|
|
struct list_head node;
|
2009-06-19 05:42:42 +02:00
|
|
|
struct rb_node rb_node;
|
2009-04-03 14:04:26 +02:00
|
|
|
char *name;
|
2007-05-24 23:45:34 +02:00
|
|
|
uint32_t nr_files;
|
|
|
|
uint32_t nr_methods;
|
2006-11-04 00:24:37 +01:00
|
|
|
};
|
|
|
|
|
2009-04-02 21:46:37 +02:00
|
|
|
static struct structure *structure__new(const char *name)
|
2006-11-04 00:24:37 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
struct structure *st = malloc(sizeof(*st));
|
2006-11-04 00:24:37 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
if (st != NULL) {
|
|
|
|
st->name = strdup(name);
|
|
|
|
if (st->name == NULL) {
|
|
|
|
free(st);
|
2009-04-02 21:46:37 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
2012-08-17 23:47:15 +02:00
|
|
|
st->nr_files = 1;
|
|
|
|
st->nr_methods = 0;
|
2006-11-04 00:24:37 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
return st;
|
2006-11-04 00:24:37 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void structure__delete(struct structure *st)
|
2009-03-11 16:31:17 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
free(st->name);
|
|
|
|
free(st);
|
2009-03-11 16:31:17 +01:00
|
|
|
}
|
|
|
|
|
2009-06-19 05:42:42 +02:00
|
|
|
static struct rb_root structures__tree = RB_ROOT;
|
2009-03-13 19:05:19 +01:00
|
|
|
static LIST_HEAD(structures__list);
|
2008-10-28 21:56:47 +01:00
|
|
|
|
2009-06-22 23:40:39 +02:00
|
|
|
static struct structure *structures__add(struct class *class,
|
|
|
|
const struct cu *cu,
|
|
|
|
bool *existing_entry)
|
2008-10-28 21:56:47 +01:00
|
|
|
{
|
2009-06-19 05:42:42 +02:00
|
|
|
struct rb_node **p = &structures__tree.rb_node;
|
|
|
|
struct rb_node *parent = NULL;
|
2008-10-28 21:56:47 +01:00
|
|
|
struct structure *str;
|
2009-06-19 05:42:42 +02:00
|
|
|
const char *new_class_name = class__name(class, cu);
|
2008-10-28 21:56:47 +01:00
|
|
|
|
2009-06-19 05:42:42 +02:00
|
|
|
while (*p != NULL) {
|
|
|
|
int rc;
|
2008-10-28 21:56:47 +01:00
|
|
|
|
2009-06-19 05:42:42 +02:00
|
|
|
parent = *p;
|
|
|
|
str = rb_entry(parent, struct structure, rb_node);
|
|
|
|
rc = strcmp(str->name, new_class_name);
|
|
|
|
|
|
|
|
if (rc > 0)
|
|
|
|
p = &(*p)->rb_left;
|
|
|
|
else if (rc < 0)
|
|
|
|
p = &(*p)->rb_right;
|
2009-06-22 23:40:39 +02:00
|
|
|
else {
|
|
|
|
*existing_entry = true;
|
2009-06-19 05:42:42 +02:00
|
|
|
return str;
|
2009-06-22 23:40:39 +02:00
|
|
|
}
|
2009-06-19 05:42:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
str = structure__new(new_class_name);
|
2008-10-28 21:56:47 +01:00
|
|
|
if (str == NULL)
|
2009-03-13 19:05:19 +01:00
|
|
|
return NULL;
|
2008-10-28 21:56:47 +01:00
|
|
|
|
2009-06-22 23:40:39 +02:00
|
|
|
*existing_entry = false;
|
2009-06-19 05:42:42 +02:00
|
|
|
rb_link_node(&str->rb_node, parent, p);
|
|
|
|
rb_insert_color(&str->rb_node, &structures__tree);
|
2007-01-28 14:07:22 +01:00
|
|
|
|
2008-10-28 21:56:47 +01:00
|
|
|
/* For linear traversals */
|
2009-03-13 19:05:19 +01:00
|
|
|
list_add_tail(&str->node, &structures__list);
|
2009-06-19 05:42:42 +02:00
|
|
|
|
2009-03-13 19:05:19 +01:00
|
|
|
return str;
|
2006-11-04 00:24:37 +01:00
|
|
|
}
|
|
|
|
|
2009-03-11 16:31:17 +01:00
|
|
|
void structures__delete(void)
|
|
|
|
{
|
2009-06-19 05:42:42 +02:00
|
|
|
struct rb_node *next = rb_first(&structures__tree);
|
|
|
|
|
|
|
|
while (next) {
|
|
|
|
struct structure *pos = rb_entry(next, struct structure, rb_node);
|
|
|
|
next = rb_next(&pos->rb_node);
|
|
|
|
rb_erase(&pos->rb_node, &structures__tree);
|
|
|
|
structure__delete(pos);
|
|
|
|
}
|
2009-03-11 16:31:17 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void nr_definitions_formatter(struct structure *st)
|
2006-12-18 13:47:39 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
printf("%s%c%u\n", st->name, separator, st->nr_files);
|
2006-11-04 00:24:37 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void nr_members_formatter(struct class *class,
|
2009-04-02 22:54:43 +02:00
|
|
|
struct cu *cu, uint16_t id __unused)
|
2006-11-04 00:24:37 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
printf("%s%c%u\n", class__name(class, cu), separator,
|
|
|
|
class__nr_members(class));
|
2006-11-04 00:24:37 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void nr_methods_formatter(struct structure *st)
|
2007-01-13 16:59:32 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
printf("%s%c%u\n", st->name, separator, st->nr_methods);
|
2007-01-13 16:59:32 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void size_formatter(struct class *class,
|
2009-04-02 22:54:43 +02:00
|
|
|
struct cu *cu, uint16_t id __unused)
|
2006-12-18 13:47:39 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
printf("%s%c%d%c%u\n", class__name(class, cu), separator,
|
|
|
|
class__size(class), separator, class->nr_holes);
|
2006-12-18 13:47:39 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void class_name_len_formatter(struct class *class, struct cu *cu,
|
2009-03-13 19:05:19 +01:00
|
|
|
uint16_t id __unused)
|
2006-12-18 13:47:39 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
const char *name = class__name(class, cu);
|
2007-05-23 21:15:21 +02:00
|
|
|
printf("%s%c%zd\n", name, separator, strlen(name));
|
2006-12-18 13:47:39 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void class_name_formatter(struct class *class,
|
2009-04-02 22:54:43 +02:00
|
|
|
struct cu *cu, uint16_t id __unused)
|
[LIB]: Introduce class__has_hole_ge()
That returns if the class has a hole greater or equal to the size specified.
Pahole now has a --hole_size_ge command line option to use it.
Example on a linux kernel built for x86_64 where we list the structs that have
holes bigger than 32 bytes, that provides an approximation of structs with
____cacheline_aligned_in_smp annotated members:
[acme@filo pahole]$ pahole --hole_size_ge 32 examples/vmlinux-x86_64
inet_hashinfo
rcu_ctrlblk
hh_cache
net_device
files_struct
module
zone
For instance, look at struct zone clever use of such construct:
_pad1_ is defined with ZONE_PADDING(_pad1_), that is:
/* <40e> /home/acme/git/net-2.6.22/include/linux/mmzone.h:179 */
struct zone {
long unsigned int pages_min; /* 0 8 */
long unsigned int pages_low; /* 8 8 */
long unsigned int pages_high; /* 16 8 */
long unsigned int lowmem_reserve[3]; /* 24 24 */
int node; /* 48 4 */
/* XXX 4 bytes hole, try to pack */
long unsigned int min_unmapped_pages; /* 56 8 */
/* --- cacheline 1 boundary (64 bytes) --- */
long unsigned int min_slab_pages; /* 64 8 */
struct per_cpu_pageset * pageset[255]; /* 72 2040 */
/* --- cacheline 33 boundary (2112 bytes) --- */
spinlock_t lock; /* 2112 4 */
/* XXX 4 bytes hole, try to pack */
struct free_area free_area[11]; /* 2120 264 */
/* XXX 48 bytes hole, try to pack */
/* --- cacheline 38 boundary (2432 bytes) --- */
struct zone_padding _pad1_; /* 2432 0 */
spinlock_t lru_lock; /* 2432 4 */
/* XXX 4 bytes hole, try to pack */
struct list_head active_list; /* 2440 16 */
struct list_head inactive_list; /* 2456 16 */
long unsigned int nr_scan_active; /* 2472 8 */
long unsigned int nr_scan_inactive; /* 2480 8 */
long unsigned int pages_scanned; /* 2488 8 */
/* --- cacheline 39 boundary (2496 bytes) --- */
int all_unreclaimable; /* 2496 4 */
atomic_t reclaim_in_progress; /* 2500 4 */
atomic_long_t vm_stat[20]; /* 2504 160 */
/* --- cacheline 41 boundary (2624 bytes) was 40 bytes ago --- */
int prev_priority; /* 2664 4 */
/* XXX 20 bytes hole, try to pack */
/* --- cacheline 42 boundary (2688 bytes) --- */
struct zone_padding _pad2_; /* 2688 0 */
wait_queue_head_t * wait_table; /* 2688 8 */
long unsigned int wait_table_hash_nr_entries; /* 2696 8 */
long unsigned int wait_table_bits; /* 2704 8 */
struct pglist_data * zone_pgdat; /* 2712 8 */
long unsigned int zone_start_pfn; /* 2720 8 */
long unsigned int spanned_pages; /* 2728 8 */
long unsigned int present_pages; /* 2736 8 */
const char * name; /* 2744 8 */
/* --- cacheline 43 boundary (2752 bytes) --- */
}; /* size: 2752, cachelines: 43 */
/* sum members: 2672, holes: 5, sum holes: 80 */
/* definitions: 933 */
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-05-11 18:32:53 +02:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
puts(class__name(class, cu));
|
[LIB]: Introduce class__has_hole_ge()
That returns if the class has a hole greater or equal to the size specified.
Pahole now has a --hole_size_ge command line option to use it.
Example on a linux kernel built for x86_64 where we list the structs that have
holes bigger than 32 bytes, that provides an approximation of structs with
____cacheline_aligned_in_smp annotated members:
[acme@filo pahole]$ pahole --hole_size_ge 32 examples/vmlinux-x86_64
inet_hashinfo
rcu_ctrlblk
hh_cache
net_device
files_struct
module
zone
For instance, look at struct zone clever use of such construct:
_pad1_ is defined with ZONE_PADDING(_pad1_), that is:
/* <40e> /home/acme/git/net-2.6.22/include/linux/mmzone.h:179 */
struct zone {
long unsigned int pages_min; /* 0 8 */
long unsigned int pages_low; /* 8 8 */
long unsigned int pages_high; /* 16 8 */
long unsigned int lowmem_reserve[3]; /* 24 24 */
int node; /* 48 4 */
/* XXX 4 bytes hole, try to pack */
long unsigned int min_unmapped_pages; /* 56 8 */
/* --- cacheline 1 boundary (64 bytes) --- */
long unsigned int min_slab_pages; /* 64 8 */
struct per_cpu_pageset * pageset[255]; /* 72 2040 */
/* --- cacheline 33 boundary (2112 bytes) --- */
spinlock_t lock; /* 2112 4 */
/* XXX 4 bytes hole, try to pack */
struct free_area free_area[11]; /* 2120 264 */
/* XXX 48 bytes hole, try to pack */
/* --- cacheline 38 boundary (2432 bytes) --- */
struct zone_padding _pad1_; /* 2432 0 */
spinlock_t lru_lock; /* 2432 4 */
/* XXX 4 bytes hole, try to pack */
struct list_head active_list; /* 2440 16 */
struct list_head inactive_list; /* 2456 16 */
long unsigned int nr_scan_active; /* 2472 8 */
long unsigned int nr_scan_inactive; /* 2480 8 */
long unsigned int pages_scanned; /* 2488 8 */
/* --- cacheline 39 boundary (2496 bytes) --- */
int all_unreclaimable; /* 2496 4 */
atomic_t reclaim_in_progress; /* 2500 4 */
atomic_long_t vm_stat[20]; /* 2504 160 */
/* --- cacheline 41 boundary (2624 bytes) was 40 bytes ago --- */
int prev_priority; /* 2664 4 */
/* XXX 20 bytes hole, try to pack */
/* --- cacheline 42 boundary (2688 bytes) --- */
struct zone_padding _pad2_; /* 2688 0 */
wait_queue_head_t * wait_table; /* 2688 8 */
long unsigned int wait_table_hash_nr_entries; /* 2696 8 */
long unsigned int wait_table_bits; /* 2704 8 */
struct pglist_data * zone_pgdat; /* 2712 8 */
long unsigned int zone_start_pfn; /* 2720 8 */
long unsigned int spanned_pages; /* 2728 8 */
long unsigned int present_pages; /* 2736 8 */
const char * name; /* 2744 8 */
/* --- cacheline 43 boundary (2752 bytes) --- */
}; /* size: 2752, cachelines: 43 */
/* sum members: 2672, holes: 5, sum holes: 80 */
/* definitions: 933 */
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-05-11 18:32:53 +02:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void class_formatter(struct class *class, struct cu *cu, uint16_t id)
|
2006-12-18 13:47:39 +01:00
|
|
|
{
|
2007-01-28 14:07:22 +01:00
|
|
|
struct tag *typedef_alias = NULL;
|
2012-08-17 23:47:15 +02:00
|
|
|
struct tag *tag = class__tag(class);
|
|
|
|
const char *name = class__name(class, cu);
|
2007-01-28 14:07:22 +01:00
|
|
|
|
|
|
|
if (name == NULL) {
|
|
|
|
/*
|
|
|
|
* Find the first typedef for this struct, this is enough
|
|
|
|
* as if we optimize the struct all the typedefs will be
|
|
|
|
* affected.
|
|
|
|
*/
|
2009-03-13 19:05:19 +01:00
|
|
|
typedef_alias = cu__find_first_typedef_of_type(cu, id);
|
2007-01-28 14:07:22 +01:00
|
|
|
/*
|
|
|
|
* If there is no typedefs for this anonymous struct it is
|
|
|
|
* found just inside another struct, and in this case it'll
|
|
|
|
* be printed when the type it is in is printed, but if
|
|
|
|
* the user still wants to see its statistics, just use
|
|
|
|
* --nested_anon_include.
|
|
|
|
*/
|
|
|
|
if (typedef_alias == NULL && !class__include_nested_anonymous)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (typedef_alias != NULL) {
|
2007-05-24 23:45:34 +02:00
|
|
|
struct type *tdef = tag__type(typedef_alias);
|
2007-04-28 21:13:35 +02:00
|
|
|
|
|
|
|
conf.prefix = "typedef";
|
2009-04-02 22:54:43 +02:00
|
|
|
conf.suffix = type__name(tdef, cu);
|
2007-05-24 22:18:32 +02:00
|
|
|
} else
|
|
|
|
conf.prefix = conf.suffix = NULL;
|
2007-04-28 21:13:35 +02:00
|
|
|
|
2009-03-13 19:05:19 +01:00
|
|
|
tag__fprintf(tag, cu, &conf, stdout);
|
2007-06-22 21:43:29 +02:00
|
|
|
|
2006-12-18 13:47:39 +01:00
|
|
|
putchar('\n');
|
|
|
|
}
|
|
|
|
|
2009-03-13 19:05:19 +01:00
|
|
|
static void print_packable_info(struct class *c, struct cu *cu, uint16_t id)
|
2008-10-28 21:56:47 +01:00
|
|
|
{
|
|
|
|
const struct tag *t = class__tag(c);
|
|
|
|
const size_t orig_size = class__size(c);
|
|
|
|
const size_t new_size = class__size(c->priv);
|
|
|
|
const size_t savings = orig_size - new_size;
|
2009-04-02 22:54:43 +02:00
|
|
|
const char *name = class__name(c, cu);
|
2008-10-28 21:56:47 +01:00
|
|
|
|
|
|
|
/* Anonymous struct? Try finding a typedef */
|
|
|
|
if (name == NULL) {
|
|
|
|
const struct tag *tdef =
|
2009-03-13 19:05:19 +01:00
|
|
|
cu__find_first_typedef_of_type(cu, id);
|
2008-10-28 21:56:47 +01:00
|
|
|
|
|
|
|
if (tdef != NULL)
|
2009-04-02 22:54:43 +02:00
|
|
|
name = class__name(tag__class(tdef), cu);
|
2008-10-28 21:56:47 +01:00
|
|
|
}
|
|
|
|
if (name != NULL)
|
|
|
|
printf("%s%c%zd%c%zd%c%zd\n",
|
|
|
|
name, separator,
|
|
|
|
orig_size, separator,
|
|
|
|
new_size, separator,
|
|
|
|
savings);
|
|
|
|
else
|
|
|
|
printf("%s(%d)%c%zd%c%zd%c%zd\n",
|
2009-03-13 19:05:19 +01:00
|
|
|
tag__decl_file(t, cu),
|
|
|
|
tag__decl_line(t, cu),
|
2008-10-28 21:56:47 +01:00
|
|
|
separator,
|
|
|
|
orig_size, separator,
|
|
|
|
new_size, separator,
|
|
|
|
savings);
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void (*stats_formatter)(struct structure *st);
|
2009-03-13 19:05:19 +01:00
|
|
|
|
|
|
|
static void print_stats(void)
|
2006-11-04 00:24:37 +01:00
|
|
|
{
|
|
|
|
struct structure *pos;
|
|
|
|
|
2009-03-13 19:05:19 +01:00
|
|
|
list_for_each_entry(pos, &structures__list, node)
|
|
|
|
stats_formatter(pos);
|
|
|
|
}
|
2008-10-28 21:56:47 +01:00
|
|
|
|
2009-03-13 19:05:19 +01:00
|
|
|
static struct class *class__filter(struct class *class, struct cu *cu,
|
|
|
|
uint16_t tag_id);
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void (*formatter)(struct class *class,
|
2009-03-13 19:05:19 +01:00
|
|
|
struct cu *cu, uint16_t id) = class_formatter;
|
|
|
|
|
|
|
|
static void print_classes(struct cu *cu)
|
|
|
|
{
|
|
|
|
uint16_t id;
|
|
|
|
struct class *pos;
|
|
|
|
|
|
|
|
cu__for_each_struct(cu, id, pos) {
|
2009-06-22 23:40:39 +02:00
|
|
|
bool existing_entry;
|
|
|
|
struct structure *str;
|
|
|
|
|
2009-03-13 19:05:19 +01:00
|
|
|
if (pos->type.namespace.name == 0 &&
|
|
|
|
!(class__include_anonymous ||
|
|
|
|
class__include_nested_anonymous))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!class__filter(pos, cu, id))
|
|
|
|
continue;
|
2009-05-08 06:05:31 +02:00
|
|
|
/*
|
|
|
|
* FIXME: No sense in adding an anonymous struct to the list of
|
|
|
|
* structs already printed, as we look for the name... The
|
|
|
|
* right fix probably will be to call class__fprintf on a
|
|
|
|
* in-memory FILE, do a hash, and look it by full contents, not
|
|
|
|
* by name. And this is needed for CTF as well, but its late now
|
|
|
|
* and I'm sleepy, will leave for later...
|
|
|
|
*/
|
2009-06-27 16:59:58 +02:00
|
|
|
if (pos->type.namespace.name != 0) {
|
|
|
|
str = structures__add(pos, cu, &existing_entry);
|
|
|
|
if (str == NULL) {
|
|
|
|
fprintf(stderr, "pahole: insufficient memory for "
|
|
|
|
"processing %s, skipping it...\n", cu->name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Already printed... */
|
|
|
|
if (existing_entry) {
|
|
|
|
str->nr_files++;
|
|
|
|
continue;
|
|
|
|
}
|
2009-06-22 23:40:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (show_packable && !global_verbose)
|
|
|
|
print_packable_info(pos, cu, id);
|
|
|
|
else if (formatter != NULL)
|
|
|
|
formatter(pos, cu, id);
|
2009-03-13 19:05:19 +01:00
|
|
|
}
|
2006-11-04 00:24:37 +01:00
|
|
|
}
|
|
|
|
|
2006-12-05 17:58:27 +01:00
|
|
|
static struct cu *cu__filter(struct cu *cu)
|
2006-12-01 02:36:55 +01:00
|
|
|
{
|
|
|
|
if (cu__exclude_prefix != NULL &&
|
|
|
|
(cu->name == NULL ||
|
|
|
|
strncmp(cu__exclude_prefix, cu->name,
|
|
|
|
cu__exclude_prefix_len) == 0))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return cu;
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static int class__packable(struct class *class, struct cu *cu)
|
2006-12-07 19:14:15 +01:00
|
|
|
{
|
2009-03-14 17:50:36 +01:00
|
|
|
struct class *clone;
|
2006-12-07 19:14:15 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
if (class->nr_holes == 0 && class->nr_bit_holes == 0)
|
2006-12-07 19:14:15 +01:00
|
|
|
return 0;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
clone = class__clone(class, NULL, cu);
|
2009-03-14 17:50:36 +01:00
|
|
|
if (clone == NULL)
|
2007-04-01 14:31:35 +02:00
|
|
|
return 0;
|
2009-03-14 17:50:36 +01:00
|
|
|
class__reorganize(clone, cu, 0, stdout);
|
2012-08-17 23:47:15 +02:00
|
|
|
if (class__size(class) > class__size(clone)) {
|
|
|
|
class->priv = clone;
|
2007-04-01 15:03:04 +02:00
|
|
|
return 1;
|
|
|
|
}
|
2009-09-20 21:46:32 +02:00
|
|
|
/* FIXME: we need to free in the right order,
|
|
|
|
* cu->obstack is being corrupted...
|
2009-08-18 23:21:20 +02:00
|
|
|
class__delete(clone, cu);
|
2009-09-20 21:46:32 +02:00
|
|
|
*/
|
2007-04-01 15:03:04 +02:00
|
|
|
return 0;
|
2006-12-07 19:14:15 +01:00
|
|
|
}
|
|
|
|
|
2009-03-13 19:05:19 +01:00
|
|
|
static struct class *class__filter(struct class *class, struct cu *cu,
|
|
|
|
uint16_t tag_id)
|
2006-12-01 02:12:21 +01:00
|
|
|
{
|
2009-03-13 19:05:19 +01:00
|
|
|
struct tag *tag = class__tag(class);
|
2007-01-07 15:30:58 +01:00
|
|
|
const char *name;
|
2006-12-18 13:47:39 +01:00
|
|
|
|
2009-06-22 23:40:39 +02:00
|
|
|
if (!tag->top_level) {
|
|
|
|
class__find_holes(class);
|
|
|
|
|
|
|
|
if (!show_private_classes)
|
|
|
|
return NULL;
|
|
|
|
}
|
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
|
|
|
|
2009-04-02 22:54:43 +02:00
|
|
|
name = class__name(class, cu);
|
2006-12-01 03:00:24 +01:00
|
|
|
|
2007-01-09 13:00:47 +01:00
|
|
|
if (class__is_declaration(class))
|
2006-12-18 13:47:39 +01:00
|
|
|
return NULL;
|
|
|
|
|
2007-01-28 14:07:22 +01:00
|
|
|
if (!class__include_anonymous && name == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2007-04-04 19:21:41 +02:00
|
|
|
if (class__exclude_prefix != NULL) {
|
|
|
|
if (name == NULL) {
|
|
|
|
const struct tag *tdef =
|
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
|
|
|
cu__find_first_typedef_of_type(cu, tag_id);
|
2008-10-28 21:56:47 +01:00
|
|
|
if (tdef != NULL) {
|
|
|
|
struct class *c = tag__class(tdef);
|
|
|
|
|
2009-04-02 22:54:43 +02:00
|
|
|
name = class__name(c, cu);
|
2008-10-28 21:56:47 +01:00
|
|
|
}
|
2007-04-04 19:21:41 +02:00
|
|
|
}
|
|
|
|
if (name != NULL && strncmp(class__exclude_prefix, name,
|
|
|
|
class__exclude_prefix_len) == 0)
|
|
|
|
return NULL;
|
|
|
|
}
|
2006-12-01 02:12:21 +01:00
|
|
|
|
2008-04-21 17:41:44 +02:00
|
|
|
if (class__include_prefix != NULL) {
|
|
|
|
if (name == NULL) {
|
|
|
|
const struct tag *tdef =
|
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
|
|
|
cu__find_first_typedef_of_type(cu, tag_id);
|
2008-10-28 21:56:47 +01:00
|
|
|
if (tdef != NULL) {
|
|
|
|
struct class *c = tag__class(tdef);
|
|
|
|
|
2009-04-02 22:54:43 +02:00
|
|
|
name = class__name(c, cu);
|
2008-10-28 21:56:47 +01:00
|
|
|
}
|
2008-04-21 17:41:44 +02:00
|
|
|
}
|
|
|
|
if (name != NULL && strncmp(class__include_prefix, name,
|
|
|
|
class__include_prefix_len) != 0)
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2006-12-01 03:08:10 +01:00
|
|
|
if (decl_exclude_prefix != NULL &&
|
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
|
|
|
(!tag__decl_file(tag, cu) ||
|
|
|
|
strncmp(decl_exclude_prefix, tag__decl_file(tag, cu),
|
2006-12-01 03:08:10 +01:00
|
|
|
decl_exclude_prefix_len) == 0))
|
|
|
|
return NULL;
|
|
|
|
|
2009-06-22 23:40:39 +02:00
|
|
|
if (tag->top_level)
|
|
|
|
class__find_holes(class);
|
|
|
|
|
2006-12-18 13:47:39 +01:00
|
|
|
if (class->nr_holes < nr_holes ||
|
[LIB]: Introduce class__has_hole_ge()
That returns if the class has a hole greater or equal to the size specified.
Pahole now has a --hole_size_ge command line option to use it.
Example on a linux kernel built for x86_64 where we list the structs that have
holes bigger than 32 bytes, that provides an approximation of structs with
____cacheline_aligned_in_smp annotated members:
[acme@filo pahole]$ pahole --hole_size_ge 32 examples/vmlinux-x86_64
inet_hashinfo
rcu_ctrlblk
hh_cache
net_device
files_struct
module
zone
For instance, look at struct zone clever use of such construct:
_pad1_ is defined with ZONE_PADDING(_pad1_), that is:
/* <40e> /home/acme/git/net-2.6.22/include/linux/mmzone.h:179 */
struct zone {
long unsigned int pages_min; /* 0 8 */
long unsigned int pages_low; /* 8 8 */
long unsigned int pages_high; /* 16 8 */
long unsigned int lowmem_reserve[3]; /* 24 24 */
int node; /* 48 4 */
/* XXX 4 bytes hole, try to pack */
long unsigned int min_unmapped_pages; /* 56 8 */
/* --- cacheline 1 boundary (64 bytes) --- */
long unsigned int min_slab_pages; /* 64 8 */
struct per_cpu_pageset * pageset[255]; /* 72 2040 */
/* --- cacheline 33 boundary (2112 bytes) --- */
spinlock_t lock; /* 2112 4 */
/* XXX 4 bytes hole, try to pack */
struct free_area free_area[11]; /* 2120 264 */
/* XXX 48 bytes hole, try to pack */
/* --- cacheline 38 boundary (2432 bytes) --- */
struct zone_padding _pad1_; /* 2432 0 */
spinlock_t lru_lock; /* 2432 4 */
/* XXX 4 bytes hole, try to pack */
struct list_head active_list; /* 2440 16 */
struct list_head inactive_list; /* 2456 16 */
long unsigned int nr_scan_active; /* 2472 8 */
long unsigned int nr_scan_inactive; /* 2480 8 */
long unsigned int pages_scanned; /* 2488 8 */
/* --- cacheline 39 boundary (2496 bytes) --- */
int all_unreclaimable; /* 2496 4 */
atomic_t reclaim_in_progress; /* 2500 4 */
atomic_long_t vm_stat[20]; /* 2504 160 */
/* --- cacheline 41 boundary (2624 bytes) was 40 bytes ago --- */
int prev_priority; /* 2664 4 */
/* XXX 20 bytes hole, try to pack */
/* --- cacheline 42 boundary (2688 bytes) --- */
struct zone_padding _pad2_; /* 2688 0 */
wait_queue_head_t * wait_table; /* 2688 8 */
long unsigned int wait_table_hash_nr_entries; /* 2696 8 */
long unsigned int wait_table_bits; /* 2704 8 */
struct pglist_data * zone_pgdat; /* 2712 8 */
long unsigned int zone_start_pfn; /* 2720 8 */
long unsigned int spanned_pages; /* 2728 8 */
long unsigned int present_pages; /* 2736 8 */
const char * name; /* 2744 8 */
/* --- cacheline 43 boundary (2752 bytes) --- */
}; /* size: 2752, cachelines: 43 */
/* sum members: 2672, holes: 5, sum holes: 80 */
/* definitions: 933 */
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-05-11 18:32:53 +02:00
|
|
|
class->nr_bit_holes < nr_bit_holes ||
|
|
|
|
(hole_size_ge != 0 && !class__has_hole_ge(class, hole_size_ge)))
|
2006-12-18 13:47:39 +01:00
|
|
|
return NULL;
|
|
|
|
|
2007-04-01 14:31:35 +02:00
|
|
|
if (show_packable && !class__packable(class, cu))
|
2006-12-07 19:14:15 +01:00
|
|
|
return NULL;
|
|
|
|
|
2009-03-13 19:05:19 +01:00
|
|
|
return class;
|
2006-11-04 00:24:37 +01:00
|
|
|
}
|
|
|
|
|
2008-01-12 18:25:12 +01:00
|
|
|
static void union__find_new_size(struct tag *tag, struct cu *cu);
|
|
|
|
|
2008-01-12 16:14:40 +01:00
|
|
|
static void class__resize_LP(struct tag *tag, struct cu *cu)
|
|
|
|
{
|
|
|
|
struct tag *tag_pos;
|
2012-08-17 23:47:15 +02:00
|
|
|
struct class *class = tag__class(tag);
|
2008-01-12 16:14:40 +01:00
|
|
|
size_t word_size_diff;
|
2012-08-17 23:47:15 +02:00
|
|
|
size_t orig_size = class->type.size;
|
2008-01-12 16:14:40 +01:00
|
|
|
|
2008-01-12 18:25:12 +01:00
|
|
|
if (tag__type(tag)->resized)
|
|
|
|
return;
|
|
|
|
|
|
|
|
tag__type(tag)->resized = 1;
|
|
|
|
|
2008-01-12 16:14:40 +01:00
|
|
|
if (original_word_size > word_size)
|
|
|
|
word_size_diff = original_word_size - word_size;
|
|
|
|
else
|
|
|
|
word_size_diff = word_size - original_word_size;
|
|
|
|
|
|
|
|
type__for_each_tag(tag__type(tag), tag_pos) {
|
|
|
|
struct tag *type;
|
|
|
|
size_t diff = 0;
|
2008-01-12 23:06:46 +01:00
|
|
|
size_t array_multiplier = 1;
|
2008-01-12 16:14:40 +01:00
|
|
|
|
|
|
|
/* we want only data members, i.e. with byte_offset attr */
|
|
|
|
if (tag_pos->tag != DW_TAG_member &&
|
|
|
|
tag_pos->tag != DW_TAG_inheritance)
|
|
|
|
continue;
|
|
|
|
|
2009-03-18 16:17:07 +01:00
|
|
|
type = cu__type(cu, tag_pos->type);
|
2008-04-20 23:56:36 +02:00
|
|
|
tag__assert_search_result(type);
|
2008-01-12 23:06:46 +01:00
|
|
|
if (type->tag == DW_TAG_array_type) {
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < tag__array_type(type)->dimensions; ++i)
|
|
|
|
array_multiplier *= tag__array_type(type)->nr_entries[i];
|
|
|
|
|
2009-03-18 16:17:07 +01:00
|
|
|
type = cu__type(cu, type->type);
|
2008-04-20 23:56:36 +02:00
|
|
|
tag__assert_search_result(type);
|
2008-01-12 23:06:46 +01:00
|
|
|
}
|
|
|
|
|
2008-09-30 19:21:03 +02:00
|
|
|
if (tag__is_typedef(type)) {
|
2008-01-12 22:21:46 +01:00
|
|
|
type = tag__follow_typedef(type, cu);
|
2008-04-20 23:56:36 +02:00
|
|
|
tag__assert_search_result(type);
|
|
|
|
}
|
2008-01-12 23:06:46 +01:00
|
|
|
|
2008-01-12 16:14:40 +01:00
|
|
|
switch (type->tag) {
|
|
|
|
case DW_TAG_base_type: {
|
|
|
|
struct base_type *bt = tag__base_type(type);
|
2009-04-02 21:46:37 +02:00
|
|
|
char bf[64];
|
2009-04-02 22:54:43 +02:00
|
|
|
const char *name = base_type__name(bt, cu, bf,
|
|
|
|
sizeof(bf));
|
2009-04-02 21:46:37 +02:00
|
|
|
if (strcmp(name, "long int") != 0 &&
|
|
|
|
strcmp(name, "long unsigned int") != 0)
|
2008-01-12 16:14:40 +01:00
|
|
|
break;
|
|
|
|
/* fallthru */
|
|
|
|
}
|
|
|
|
case DW_TAG_pointer_type:
|
|
|
|
diff = word_size_diff;
|
|
|
|
break;
|
|
|
|
case DW_TAG_structure_type:
|
|
|
|
case DW_TAG_union_type:
|
2008-09-30 19:43:22 +02:00
|
|
|
if (tag__is_union(type))
|
2008-01-12 18:25:12 +01:00
|
|
|
union__find_new_size(type, cu);
|
|
|
|
else
|
|
|
|
class__resize_LP(type, cu);
|
2008-01-12 16:14:40 +01:00
|
|
|
diff = tag__type(type)->size_diff;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-01-12 23:06:46 +01:00
|
|
|
diff *= array_multiplier;
|
|
|
|
|
2008-01-12 16:14:40 +01:00
|
|
|
if (diff != 0) {
|
|
|
|
struct class_member *m = tag__class_member(tag_pos);
|
|
|
|
if (original_word_size > word_size) {
|
2012-08-17 23:47:15 +02:00
|
|
|
class->type.size -= diff;
|
|
|
|
class__subtract_offsets_from(class, m, diff);
|
2008-01-12 16:14:40 +01:00
|
|
|
} else {
|
2012-08-17 23:47:15 +02:00
|
|
|
class->type.size += diff;
|
|
|
|
class__add_offsets_from(class, m, diff);
|
2008-01-12 16:14:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (original_word_size > word_size)
|
2012-08-17 23:47:15 +02:00
|
|
|
tag__type(tag)->size_diff = orig_size - class->type.size;
|
2008-01-12 16:14:40 +01:00
|
|
|
else
|
2012-08-17 23:47:15 +02:00
|
|
|
tag__type(tag)->size_diff = class->type.size - orig_size;
|
2008-01-12 16:14:40 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
class__find_holes(class);
|
|
|
|
class__fixup_alignment(class, cu);
|
2008-01-12 16:14:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void union__find_new_size(struct tag *tag, struct cu *cu)
|
|
|
|
{
|
|
|
|
struct tag *tag_pos;
|
2012-08-17 23:47:15 +02:00
|
|
|
struct type *type = tag__type(tag);
|
2008-01-12 16:14:40 +01:00
|
|
|
size_t max_size = 0;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
if (type->resized)
|
2008-01-12 18:25:12 +01:00
|
|
|
return;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
type->resized = 1;
|
2008-01-12 18:25:12 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
type__for_each_tag(type, tag_pos) {
|
2008-01-12 16:14:40 +01:00
|
|
|
struct tag *type;
|
|
|
|
size_t size;
|
|
|
|
|
|
|
|
/* we want only data members, i.e. with byte_offset attr */
|
|
|
|
if (tag_pos->tag != DW_TAG_member &&
|
|
|
|
tag_pos->tag != DW_TAG_inheritance)
|
|
|
|
continue;
|
|
|
|
|
2009-03-18 16:17:07 +01:00
|
|
|
type = cu__type(cu, tag_pos->type);
|
2008-04-20 23:56:36 +02:00
|
|
|
tag__assert_search_result(type);
|
2008-09-30 19:21:03 +02:00
|
|
|
if (tag__is_typedef(type))
|
2008-01-12 22:40:10 +01:00
|
|
|
type = tag__follow_typedef(type, cu);
|
2008-01-12 18:25:12 +01:00
|
|
|
|
2008-09-30 19:43:22 +02:00
|
|
|
if (tag__is_union(type))
|
2008-01-12 18:25:12 +01:00
|
|
|
union__find_new_size(type, cu);
|
2008-09-30 19:43:22 +02:00
|
|
|
else if (tag__is_struct(type))
|
2008-01-12 18:25:12 +01:00
|
|
|
class__resize_LP(type, cu);
|
|
|
|
|
2008-01-12 16:14:40 +01:00
|
|
|
size = tag__size(type, cu);
|
|
|
|
if (size > max_size)
|
|
|
|
max_size = size;
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
if (max_size > type->size)
|
|
|
|
type->size_diff = max_size - type->size;
|
2008-01-12 16:14:40 +01:00
|
|
|
else
|
2012-08-17 23:47:15 +02:00
|
|
|
type->size_diff = type->size - max_size;
|
2008-01-12 16:14:40 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
type->size = max_size;
|
2008-01-12 16:14:40 +01:00
|
|
|
}
|
|
|
|
|
2009-04-01 15:58:25 +02:00
|
|
|
static void tag__fixup_word_size(struct tag *tag, struct cu *cu)
|
2008-01-12 16:14:40 +01:00
|
|
|
{
|
2008-09-30 19:43:22 +02:00
|
|
|
if (tag__is_struct(tag) || tag__is_union(tag)) {
|
2008-01-12 16:14:40 +01:00
|
|
|
struct tag *pos;
|
|
|
|
|
|
|
|
namespace__for_each_tag(tag__namespace(tag), pos)
|
2009-04-01 15:58:25 +02:00
|
|
|
tag__fixup_word_size(pos, cu);
|
2008-01-12 16:14:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
switch (tag->tag) {
|
|
|
|
case DW_TAG_base_type: {
|
|
|
|
struct base_type *bt = tag__base_type(tag);
|
|
|
|
|
2008-02-01 22:53:47 +01:00
|
|
|
/*
|
|
|
|
* This shouldn't happen, but at least on a tcp_ipv6.c
|
|
|
|
* built with GNU C 4.3.0 20080130 (Red Hat 4.3.0-0.7),
|
|
|
|
* one was found, so just bail out.
|
|
|
|
*/
|
2008-10-02 19:34:42 +02:00
|
|
|
if (!bt->name)
|
2009-04-01 15:58:25 +02:00
|
|
|
return;
|
2009-04-02 21:46:37 +02:00
|
|
|
char bf[64];
|
2009-04-02 22:54:43 +02:00
|
|
|
const char *name = base_type__name(bt, cu, bf, sizeof(bf));
|
2008-02-01 22:53:47 +01:00
|
|
|
|
2009-04-02 21:46:37 +02:00
|
|
|
if (strcmp(name, "long int") == 0 ||
|
|
|
|
strcmp(name, "long unsigned int") == 0)
|
2008-03-04 22:38:21 +01:00
|
|
|
bt->bit_size = word_size * 8;
|
2008-01-12 16:14:40 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case DW_TAG_structure_type:
|
|
|
|
class__resize_LP(tag, cu);
|
|
|
|
break;
|
|
|
|
case DW_TAG_union_type:
|
|
|
|
union__find_new_size(tag, cu);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-04-01 15:58:25 +02:00
|
|
|
return;
|
2008-01-12 16:14:40 +01:00
|
|
|
}
|
|
|
|
|
2009-03-13 19:05:19 +01:00
|
|
|
static void cu_fixup_word_size_iterator(struct cu *cu)
|
2008-01-12 16:14:40 +01:00
|
|
|
{
|
|
|
|
original_word_size = cu->addr_size;
|
|
|
|
cu->addr_size = word_size;
|
2009-04-01 15:58:25 +02:00
|
|
|
|
|
|
|
uint16_t id;
|
|
|
|
struct tag *pos;
|
|
|
|
cu__for_each_type(cu, id, pos)
|
|
|
|
tag__fixup_word_size(pos, cu);
|
2007-01-13 16:59:32 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void cu__account_nr_methods(struct cu *cu)
|
2007-01-13 16:59:32 +01:00
|
|
|
{
|
2009-03-13 19:05:19 +01:00
|
|
|
struct function *pos_function;
|
2007-01-13 16:59:32 +01:00
|
|
|
struct structure *str;
|
2009-03-13 19:05:19 +01:00
|
|
|
uint32_t id;
|
2007-01-13 16:59:32 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
cu__for_each_function(cu, id, pos_function) {
|
2009-03-13 19:05:19 +01:00
|
|
|
struct class_member *pos;
|
|
|
|
list_for_each_entry(pos, &pos_function->proto.parms, tag.node) {
|
2012-08-17 23:47:15 +02:00
|
|
|
struct tag *type = cu__type(cu, pos->tag.type);
|
2007-01-13 16:59:32 +01:00
|
|
|
|
2009-03-13 19:05:19 +01:00
|
|
|
if (type == NULL || type->tag != DW_TAG_pointer_type)
|
|
|
|
continue;
|
2007-01-13 16:59:32 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
type = cu__type(cu, type->type);
|
2009-03-13 19:05:19 +01:00
|
|
|
if (type == NULL || !tag__is_struct(type))
|
|
|
|
continue;
|
2007-01-13 16:59:32 +01:00
|
|
|
|
2009-03-13 19:05:19 +01:00
|
|
|
struct type *ctype = tag__type(type);
|
|
|
|
if (ctype->namespace.name == 0)
|
|
|
|
continue;
|
2007-01-13 16:59:32 +01:00
|
|
|
|
2009-06-22 23:40:39 +02:00
|
|
|
struct class *class = tag__class(type);
|
2009-03-13 19:05:19 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
if (!class__filter(class, cu, 0))
|
2009-06-22 23:40:39 +02:00
|
|
|
continue;
|
2009-03-14 17:50:36 +01:00
|
|
|
|
2009-06-22 23:40:39 +02:00
|
|
|
bool existing_entry;
|
2012-08-17 23:47:15 +02:00
|
|
|
str = structures__add(class, cu, &existing_entry);
|
2009-06-22 23:40:39 +02:00
|
|
|
if (str == NULL) {
|
|
|
|
fprintf(stderr, "pahole: insufficient memory "
|
|
|
|
"for processing %s, skipping it...\n",
|
2012-08-17 23:47:15 +02:00
|
|
|
cu->name);
|
2009-06-22 23:40:39 +02:00
|
|
|
return;
|
2009-03-13 19:05:19 +01:00
|
|
|
}
|
2009-06-22 23:40:39 +02:00
|
|
|
|
|
|
|
if (!existing_entry)
|
|
|
|
class__find_holes(class);
|
2007-01-13 16:59:32 +01:00
|
|
|
++str->nr_methods;
|
2009-03-13 19:05:19 +01:00
|
|
|
}
|
2007-01-13 16:59:32 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-05-11 00:11:51 +02:00
|
|
|
static char tab[128];
|
|
|
|
|
2009-03-13 19:05:19 +01:00
|
|
|
static void print_structs_with_pointer_to(const struct cu *cu, uint16_t type)
|
2007-11-16 21:18:08 +01:00
|
|
|
{
|
2009-03-13 19:05:19 +01:00
|
|
|
struct class *pos;
|
|
|
|
struct class_member *pos_member;
|
|
|
|
uint16_t id;
|
2007-11-16 21:18:08 +01:00
|
|
|
|
2009-03-13 19:05:19 +01:00
|
|
|
cu__for_each_struct(cu, id, pos) {
|
2009-06-22 23:40:39 +02:00
|
|
|
bool looked = false;
|
|
|
|
struct structure *str;
|
|
|
|
|
2009-03-13 19:05:19 +01:00
|
|
|
if (pos->type.namespace.name == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
type__for_each_member(&pos->type, pos_member) {
|
2009-03-18 16:17:07 +01:00
|
|
|
struct tag *ctype = cu__type(cu, pos_member->tag.type);
|
2007-11-16 21:18:08 +01:00
|
|
|
|
2008-04-20 23:56:36 +02:00
|
|
|
tag__assert_search_result(ctype);
|
2009-03-13 19:05:19 +01:00
|
|
|
if (ctype->tag != DW_TAG_pointer_type || ctype->type != type)
|
|
|
|
continue;
|
|
|
|
|
2009-06-22 23:40:39 +02:00
|
|
|
if (!looked) {
|
|
|
|
bool existing_entry;
|
2009-03-13 19:05:19 +01:00
|
|
|
|
2009-06-22 23:40:39 +02:00
|
|
|
str = structures__add(pos, cu, &existing_entry);
|
|
|
|
if (str == NULL) {
|
|
|
|
fprintf(stderr, "pahole: insufficient memory for "
|
|
|
|
"processing %s, skipping it...\n",
|
|
|
|
cu->name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* We already printed this struct in another CU
|
|
|
|
*/
|
|
|
|
if (existing_entry)
|
|
|
|
break;
|
|
|
|
looked = true;
|
2009-03-13 19:05:19 +01:00
|
|
|
}
|
2009-06-19 05:42:42 +02:00
|
|
|
printf("%s: %s\n", str->name,
|
2009-04-02 22:54:43 +02:00
|
|
|
class_member__name(pos_member, cu));
|
2007-11-16 21:18:08 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-13 19:05:19 +01:00
|
|
|
static void print_containers(const struct cu *cu, uint16_t type, int ident)
|
2007-05-10 20:28:00 +02:00
|
|
|
{
|
2009-03-13 19:05:19 +01:00
|
|
|
struct class *pos;
|
|
|
|
uint16_t id;
|
2007-05-10 20:28:00 +02:00
|
|
|
|
2009-03-13 19:05:19 +01:00
|
|
|
cu__for_each_struct(cu, id, pos) {
|
|
|
|
if (pos->type.namespace.name == 0)
|
|
|
|
continue;
|
2007-05-10 20:28:00 +02:00
|
|
|
|
2009-03-13 19:05:19 +01:00
|
|
|
const uint32_t n = type__nr_members_of_type(&pos->type, type);
|
|
|
|
if (n == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (ident == 0) {
|
2009-06-22 23:40:39 +02:00
|
|
|
bool existing_entry;
|
|
|
|
struct structure *str = structures__add(pos, cu, &existing_entry);
|
|
|
|
if (str == NULL) {
|
2009-03-13 19:05:19 +01:00
|
|
|
fprintf(stderr, "pahole: insufficient memory for "
|
|
|
|
"processing %s, skipping it...\n",
|
|
|
|
cu->name);
|
|
|
|
return;
|
|
|
|
}
|
2009-06-22 23:40:39 +02:00
|
|
|
/*
|
|
|
|
* We already printed this struct in another CU
|
|
|
|
*/
|
|
|
|
if (existing_entry)
|
|
|
|
break;
|
2007-05-10 20:28:00 +02:00
|
|
|
}
|
2009-03-13 19:05:19 +01:00
|
|
|
|
2009-04-02 22:54:43 +02:00
|
|
|
printf("%.*s%s", ident * 2, tab, class__name(pos, cu));
|
2009-03-13 19:05:19 +01:00
|
|
|
if (global_verbose)
|
|
|
|
printf(": %u", n);
|
|
|
|
putchar('\n');
|
|
|
|
if (recursive)
|
|
|
|
print_containers(cu, id, ident + 1);
|
2007-05-10 20:28:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-13 13:57:23 +01:00
|
|
|
/* Name and version of program. */
|
|
|
|
ARGP_PROGRAM_VERSION_HOOK_DEF = dwarves_print_version;
|
|
|
|
|
2009-03-20 17:54:04 +01:00
|
|
|
#define ARGP_flat_arrays 300
|
|
|
|
#define ARGP_show_private_classes 301
|
|
|
|
#define ARGP_fixup_silly_bitfields 302
|
2009-08-24 20:13:58 +02:00
|
|
|
#define ARGP_first_obj_only 303
|
2009-08-24 22:22:43 +02:00
|
|
|
#define ARGP_classes_as_structs 304
|
2009-10-20 17:59:12 +02:00
|
|
|
#define ARGP_hex_fmt 305
|
2009-03-20 14:29:50 +01:00
|
|
|
|
2007-03-30 15:07:01 +02:00
|
|
|
static const struct argp_option pahole__options[] = {
|
|
|
|
{
|
|
|
|
.name = "bit_holes",
|
|
|
|
.key = 'B',
|
|
|
|
.arg = "NR_HOLES",
|
|
|
|
.doc = "Show only structs at least NR_HOLES bit holes"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "cacheline_size",
|
|
|
|
.key = 'c',
|
|
|
|
.arg = "SIZE",
|
|
|
|
.doc = "set cacheline size to SIZE"
|
|
|
|
},
|
2007-04-24 21:09:34 +02:00
|
|
|
{
|
|
|
|
.name = "class_name",
|
|
|
|
.key = 'C',
|
|
|
|
.arg = "CLASS_NAME",
|
|
|
|
.doc = "Show just this class"
|
|
|
|
},
|
2007-11-16 21:18:08 +01:00
|
|
|
{
|
|
|
|
.name = "find_pointers_to",
|
|
|
|
.key = 'f',
|
|
|
|
.arg = "CLASS_NAME",
|
|
|
|
.doc = "Find pointers to CLASS_NAME"
|
|
|
|
},
|
2009-03-19 16:19:37 +01:00
|
|
|
{
|
|
|
|
.name = "format_path",
|
|
|
|
.key = 'F',
|
|
|
|
.arg = "FORMAT_LIST",
|
|
|
|
.doc = "List of debugging formats to try"
|
|
|
|
},
|
2007-05-10 20:28:00 +02:00
|
|
|
{
|
|
|
|
.name = "contains",
|
|
|
|
.key = 'i',
|
|
|
|
.arg = "CLASS_NAME",
|
|
|
|
.doc = "Show classes that contains CLASS_NAME"
|
|
|
|
},
|
2007-05-30 16:28:16 +02:00
|
|
|
{
|
|
|
|
.name = "show_decl_info",
|
|
|
|
.key = 'I',
|
|
|
|
.doc = "Show the file and line number where the tags were defined"
|
|
|
|
},
|
2007-03-30 15:07:01 +02:00
|
|
|
{
|
|
|
|
.name = "holes",
|
|
|
|
.key = 'H',
|
|
|
|
.arg = "NR_HOLES",
|
[LIB]: Introduce class__has_hole_ge()
That returns if the class has a hole greater or equal to the size specified.
Pahole now has a --hole_size_ge command line option to use it.
Example on a linux kernel built for x86_64 where we list the structs that have
holes bigger than 32 bytes, that provides an approximation of structs with
____cacheline_aligned_in_smp annotated members:
[acme@filo pahole]$ pahole --hole_size_ge 32 examples/vmlinux-x86_64
inet_hashinfo
rcu_ctrlblk
hh_cache
net_device
files_struct
module
zone
For instance, look at struct zone clever use of such construct:
_pad1_ is defined with ZONE_PADDING(_pad1_), that is:
/* <40e> /home/acme/git/net-2.6.22/include/linux/mmzone.h:179 */
struct zone {
long unsigned int pages_min; /* 0 8 */
long unsigned int pages_low; /* 8 8 */
long unsigned int pages_high; /* 16 8 */
long unsigned int lowmem_reserve[3]; /* 24 24 */
int node; /* 48 4 */
/* XXX 4 bytes hole, try to pack */
long unsigned int min_unmapped_pages; /* 56 8 */
/* --- cacheline 1 boundary (64 bytes) --- */
long unsigned int min_slab_pages; /* 64 8 */
struct per_cpu_pageset * pageset[255]; /* 72 2040 */
/* --- cacheline 33 boundary (2112 bytes) --- */
spinlock_t lock; /* 2112 4 */
/* XXX 4 bytes hole, try to pack */
struct free_area free_area[11]; /* 2120 264 */
/* XXX 48 bytes hole, try to pack */
/* --- cacheline 38 boundary (2432 bytes) --- */
struct zone_padding _pad1_; /* 2432 0 */
spinlock_t lru_lock; /* 2432 4 */
/* XXX 4 bytes hole, try to pack */
struct list_head active_list; /* 2440 16 */
struct list_head inactive_list; /* 2456 16 */
long unsigned int nr_scan_active; /* 2472 8 */
long unsigned int nr_scan_inactive; /* 2480 8 */
long unsigned int pages_scanned; /* 2488 8 */
/* --- cacheline 39 boundary (2496 bytes) --- */
int all_unreclaimable; /* 2496 4 */
atomic_t reclaim_in_progress; /* 2500 4 */
atomic_long_t vm_stat[20]; /* 2504 160 */
/* --- cacheline 41 boundary (2624 bytes) was 40 bytes ago --- */
int prev_priority; /* 2664 4 */
/* XXX 20 bytes hole, try to pack */
/* --- cacheline 42 boundary (2688 bytes) --- */
struct zone_padding _pad2_; /* 2688 0 */
wait_queue_head_t * wait_table; /* 2688 8 */
long unsigned int wait_table_hash_nr_entries; /* 2696 8 */
long unsigned int wait_table_bits; /* 2704 8 */
struct pglist_data * zone_pgdat; /* 2712 8 */
long unsigned int zone_start_pfn; /* 2720 8 */
long unsigned int spanned_pages; /* 2728 8 */
long unsigned int present_pages; /* 2736 8 */
const char * name; /* 2744 8 */
/* --- cacheline 43 boundary (2752 bytes) --- */
}; /* size: 2752, cachelines: 43 */
/* sum members: 2672, holes: 5, sum holes: 80 */
/* definitions: 933 */
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-05-11 18:32:53 +02:00
|
|
|
.doc = "show only structs with at least NR_HOLES holes",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "hole_size_ge",
|
|
|
|
.key = 'z',
|
|
|
|
.arg = "HOLE_SIZE",
|
|
|
|
.doc = "show only structs with at least one hole greater "
|
|
|
|
"or equal to HOLE_SIZE",
|
2007-03-30 15:07:01 +02:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "packable",
|
[PAHOLE]: Use cus__loadfl, i.e. libdwfl
Now we have:
[acme@filo pahole]$ pahole --help
Usage: pahole [OPTION...] [FILE] {[CLASS]}
-a, --anon_include include anonymous classes
-A, --nested_anon_include include nested (inside other structs) anonymous
classes
-B, --bit_holes=NR_HOLES Show only structs at least NR_HOLES bit holes
-c, --cacheline_size=SIZE set cacheline size to SIZE
-D, --decl_exclude=PREFIX exclude classes declared in files with PREFIX
-E, --expand_types expand class members
-H, --holes=NR_HOLES show only structs at least NR_HOLES holes
-m, --nr_methods show number of methods
-n, --nr_members show number of members
-N, --class_name_len show size of classes
-P, --packable show only structs that has holes that can be
packed
-R, --reorganize reorg struct trying to kill holes
-s, --sizes show size of classes
-S, --show_reorg_steps show the struct layout at each reorganization step
-t, --nr_definitions show how many times struct was defined
-V, --verbose be verbose
-x, --exclude=PREFIX exclude PREFIXed classes
-X, --cu_exclude=PREFIX exclude PREFIXed compilation units
Input Selection:
--debuginfo-path=PATH Search path for separate debuginfo files
-e, --executable=FILE Find addresses in FILE
-k, --kernel Find addresses in the running kernel
-K, --offline-kernel[=RELEASE] Kernel with all modules
-M, --linux-process-map=FILE Find addresses in files mapped as read from
FILE in Linux /proc/PID/maps format
-p, --pid=PID Find addresses in files mapped into process PID
-?, --help Give this help list
--usage Give a short usage message
Mandatory or optional arguments to long options are also mandatory or optional
for any corresponding short options.
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-03-30 18:25:51 +02:00
|
|
|
.key = 'P',
|
2007-03-30 15:07:01 +02:00
|
|
|
.doc = "show only structs that has holes that can be packed",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "expand_types",
|
[PAHOLE]: Use cus__loadfl, i.e. libdwfl
Now we have:
[acme@filo pahole]$ pahole --help
Usage: pahole [OPTION...] [FILE] {[CLASS]}
-a, --anon_include include anonymous classes
-A, --nested_anon_include include nested (inside other structs) anonymous
classes
-B, --bit_holes=NR_HOLES Show only structs at least NR_HOLES bit holes
-c, --cacheline_size=SIZE set cacheline size to SIZE
-D, --decl_exclude=PREFIX exclude classes declared in files with PREFIX
-E, --expand_types expand class members
-H, --holes=NR_HOLES show only structs at least NR_HOLES holes
-m, --nr_methods show number of methods
-n, --nr_members show number of members
-N, --class_name_len show size of classes
-P, --packable show only structs that has holes that can be
packed
-R, --reorganize reorg struct trying to kill holes
-s, --sizes show size of classes
-S, --show_reorg_steps show the struct layout at each reorganization step
-t, --nr_definitions show how many times struct was defined
-V, --verbose be verbose
-x, --exclude=PREFIX exclude PREFIXed classes
-X, --cu_exclude=PREFIX exclude PREFIXed compilation units
Input Selection:
--debuginfo-path=PATH Search path for separate debuginfo files
-e, --executable=FILE Find addresses in FILE
-k, --kernel Find addresses in the running kernel
-K, --offline-kernel[=RELEASE] Kernel with all modules
-M, --linux-process-map=FILE Find addresses in files mapped as read from
FILE in Linux /proc/PID/maps format
-p, --pid=PID Find addresses in files mapped into process PID
-?, --help Give this help list
--usage Give a short usage message
Mandatory or optional arguments to long options are also mandatory or optional
for any corresponding short options.
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-03-30 18:25:51 +02:00
|
|
|
.key = 'E',
|
2007-03-30 15:07:01 +02:00
|
|
|
.doc = "expand class members",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "nr_members",
|
|
|
|
.key = 'n',
|
|
|
|
.doc = "show number of members",
|
|
|
|
},
|
2007-05-02 21:14:20 +02:00
|
|
|
{
|
|
|
|
.name = "rel_offset",
|
|
|
|
.key = 'r',
|
|
|
|
.doc = "show relative offsets of members in inner structs"
|
|
|
|
},
|
2007-05-11 00:11:51 +02:00
|
|
|
{
|
|
|
|
.name = "recursive",
|
|
|
|
.key = 'd',
|
|
|
|
.doc = "recursive mode, affects several other flags",
|
|
|
|
},
|
2007-03-30 15:07:01 +02:00
|
|
|
{
|
|
|
|
.name = "reorganize",
|
[PAHOLE]: Use cus__loadfl, i.e. libdwfl
Now we have:
[acme@filo pahole]$ pahole --help
Usage: pahole [OPTION...] [FILE] {[CLASS]}
-a, --anon_include include anonymous classes
-A, --nested_anon_include include nested (inside other structs) anonymous
classes
-B, --bit_holes=NR_HOLES Show only structs at least NR_HOLES bit holes
-c, --cacheline_size=SIZE set cacheline size to SIZE
-D, --decl_exclude=PREFIX exclude classes declared in files with PREFIX
-E, --expand_types expand class members
-H, --holes=NR_HOLES show only structs at least NR_HOLES holes
-m, --nr_methods show number of methods
-n, --nr_members show number of members
-N, --class_name_len show size of classes
-P, --packable show only structs that has holes that can be
packed
-R, --reorganize reorg struct trying to kill holes
-s, --sizes show size of classes
-S, --show_reorg_steps show the struct layout at each reorganization step
-t, --nr_definitions show how many times struct was defined
-V, --verbose be verbose
-x, --exclude=PREFIX exclude PREFIXed classes
-X, --cu_exclude=PREFIX exclude PREFIXed compilation units
Input Selection:
--debuginfo-path=PATH Search path for separate debuginfo files
-e, --executable=FILE Find addresses in FILE
-k, --kernel Find addresses in the running kernel
-K, --offline-kernel[=RELEASE] Kernel with all modules
-M, --linux-process-map=FILE Find addresses in files mapped as read from
FILE in Linux /proc/PID/maps format
-p, --pid=PID Find addresses in files mapped into process PID
-?, --help Give this help list
--usage Give a short usage message
Mandatory or optional arguments to long options are also mandatory or optional
for any corresponding short options.
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-03-30 18:25:51 +02:00
|
|
|
.key = 'R',
|
2007-03-30 15:07:01 +02:00
|
|
|
.doc = "reorg struct trying to kill holes",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "show_reorg_steps",
|
|
|
|
.key = 'S',
|
|
|
|
.doc = "show the struct layout at each reorganization step",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "class_name_len",
|
|
|
|
.key = 'N',
|
|
|
|
.doc = "show size of classes",
|
|
|
|
},
|
2008-01-13 18:20:06 +01:00
|
|
|
{
|
|
|
|
.name = "show_first_biggest_size_base_type_member",
|
|
|
|
.key = 'l',
|
|
|
|
.doc = "show first biggest size base_type member",
|
|
|
|
},
|
2007-03-30 15:07:01 +02:00
|
|
|
{
|
|
|
|
.name = "nr_methods",
|
|
|
|
.key = 'm',
|
|
|
|
.doc = "show number of methods",
|
|
|
|
},
|
2007-05-30 16:36:54 +02:00
|
|
|
{
|
|
|
|
.name = "show_only_data_members",
|
|
|
|
.key = 'M',
|
|
|
|
.doc = "show only the members that use space in the class layout",
|
|
|
|
},
|
2007-07-05 01:36:28 +02:00
|
|
|
{
|
|
|
|
.name = "expand_pointers",
|
|
|
|
.key = 'p',
|
|
|
|
.doc = "expand class pointer members",
|
|
|
|
},
|
2007-03-30 15:07:01 +02:00
|
|
|
{
|
|
|
|
.name = "sizes",
|
|
|
|
.key = 's',
|
|
|
|
.doc = "show size of classes",
|
|
|
|
},
|
|
|
|
{
|
[PAHOLE]: Introduce --separator/-t
[acme@filo pahole]$ pahole -t, --packable examples/ipv6.ko.debug.x86-64 | sort -t, -k2 -n | tail
inode,1008,1000,8
hh_cache,256,128,128
proto,8512,8504,8
super_block,1184,1168,16
task_struct,3776,3704,72
module,8832,8800,32
pglist_data,10752,10744,8
zone,1536,1352,184
net_device,1664,1208,456
softnet_data,1920,1792,128
[acme@filo pahole]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-05-23 21:26:39 +02:00
|
|
|
.name = "separator",
|
2007-03-30 15:07:01 +02:00
|
|
|
.key = 't',
|
[PAHOLE]: Introduce --separator/-t
[acme@filo pahole]$ pahole -t, --packable examples/ipv6.ko.debug.x86-64 | sort -t, -k2 -n | tail
inode,1008,1000,8
hh_cache,256,128,128
proto,8512,8504,8
super_block,1184,1168,16
task_struct,3776,3704,72
module,8832,8800,32
pglist_data,10752,10744,8
zone,1536,1352,184
net_device,1664,1208,456
softnet_data,1920,1792,128
[acme@filo pahole]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-05-23 21:26:39 +02:00
|
|
|
.arg = "SEP",
|
|
|
|
.doc = "use SEP as the field separator",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "nr_definitions",
|
|
|
|
.key = 'T',
|
2007-03-30 15:07:01 +02:00
|
|
|
.doc = "show how many times struct was defined",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "decl_exclude",
|
|
|
|
.key = 'D',
|
|
|
|
.arg = "PREFIX",
|
|
|
|
.doc = "exclude classes declared in files with PREFIX",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "exclude",
|
|
|
|
.key = 'x',
|
|
|
|
.arg = "PREFIX",
|
|
|
|
.doc = "exclude PREFIXed classes",
|
|
|
|
},
|
2008-04-21 17:41:44 +02:00
|
|
|
{
|
|
|
|
.name = "prefix_filter",
|
|
|
|
.key = 'y',
|
|
|
|
.arg = "PREFIX",
|
|
|
|
.doc = "include PREFIXed classes",
|
|
|
|
},
|
2007-03-30 15:07:01 +02:00
|
|
|
{
|
|
|
|
.name = "cu_exclude",
|
|
|
|
.key = 'X',
|
|
|
|
.arg = "PREFIX",
|
|
|
|
.doc = "exclude PREFIXed compilation units",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "anon_include",
|
|
|
|
.key = 'a',
|
|
|
|
.doc = "include anonymous classes",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "nested_anon_include",
|
|
|
|
.key = 'A',
|
|
|
|
.doc = "include nested (inside other structs) anonymous classes",
|
|
|
|
},
|
2007-06-22 21:43:29 +02:00
|
|
|
{
|
|
|
|
.name = "quiet",
|
|
|
|
.key = 'q',
|
|
|
|
.doc = "be quieter",
|
|
|
|
},
|
2008-02-07 12:16:22 +01:00
|
|
|
{
|
|
|
|
.name = "defined_in",
|
|
|
|
.key = 'u',
|
|
|
|
.doc = "show CUs where CLASS_NAME (-C) is defined",
|
|
|
|
},
|
2007-03-30 15:07:01 +02:00
|
|
|
{
|
|
|
|
.name = "verbose",
|
|
|
|
.key = 'V',
|
|
|
|
.doc = "be verbose",
|
|
|
|
},
|
2008-01-12 16:14:40 +01:00
|
|
|
{
|
|
|
|
.name = "word_size",
|
|
|
|
.key = 'w',
|
|
|
|
.arg = "WORD_SIZE",
|
|
|
|
.doc = "change the arch word size to WORD_SIZE"
|
|
|
|
},
|
2009-03-19 16:16:07 +01:00
|
|
|
{
|
|
|
|
.name = "ctf_encode",
|
|
|
|
.key = 'Z',
|
|
|
|
.doc = "Encode as CTF",
|
|
|
|
},
|
2009-03-20 14:29:50 +01:00
|
|
|
{
|
|
|
|
.name = "flat_arrays",
|
|
|
|
.key = ARGP_flat_arrays,
|
|
|
|
.doc = "Flat arrays",
|
|
|
|
},
|
2009-03-20 15:37:22 +01:00
|
|
|
{
|
|
|
|
.name = "show_private_classes",
|
|
|
|
.key = ARGP_show_private_classes,
|
|
|
|
.doc = "Show classes that are defined inside other classes or in functions",
|
|
|
|
},
|
2009-03-20 17:54:04 +01:00
|
|
|
{
|
|
|
|
.name = "fixup_silly_bitfields",
|
|
|
|
.key = ARGP_fixup_silly_bitfields,
|
|
|
|
.doc = "Fix silly bitfields such as int foo:32",
|
|
|
|
},
|
2009-08-24 20:13:58 +02:00
|
|
|
{
|
|
|
|
.name = "first_obj_only",
|
|
|
|
.key = ARGP_first_obj_only,
|
|
|
|
.doc = "Only process the first object file in the binary",
|
|
|
|
},
|
2009-08-24 22:22:43 +02:00
|
|
|
{
|
|
|
|
.name = "classes_as_structs",
|
|
|
|
.key = ARGP_classes_as_structs,
|
|
|
|
.doc = "Use 'struct' when printing classes",
|
|
|
|
},
|
2009-10-20 17:59:12 +02:00
|
|
|
{
|
|
|
|
.name = "hex",
|
|
|
|
.key = ARGP_hex_fmt,
|
|
|
|
.doc = "Print offsets and sizes in hexadecimal",
|
|
|
|
},
|
2007-03-30 15:07:01 +02:00
|
|
|
{
|
|
|
|
.name = NULL,
|
|
|
|
}
|
2006-11-02 17:47:37 +01:00
|
|
|
};
|
|
|
|
|
2007-03-30 15:07:01 +02:00
|
|
|
static error_t pahole__options_parser(int key, char *arg,
|
[PAHOLE]: Use cus__loadfl, i.e. libdwfl
Now we have:
[acme@filo pahole]$ pahole --help
Usage: pahole [OPTION...] [FILE] {[CLASS]}
-a, --anon_include include anonymous classes
-A, --nested_anon_include include nested (inside other structs) anonymous
classes
-B, --bit_holes=NR_HOLES Show only structs at least NR_HOLES bit holes
-c, --cacheline_size=SIZE set cacheline size to SIZE
-D, --decl_exclude=PREFIX exclude classes declared in files with PREFIX
-E, --expand_types expand class members
-H, --holes=NR_HOLES show only structs at least NR_HOLES holes
-m, --nr_methods show number of methods
-n, --nr_members show number of members
-N, --class_name_len show size of classes
-P, --packable show only structs that has holes that can be
packed
-R, --reorganize reorg struct trying to kill holes
-s, --sizes show size of classes
-S, --show_reorg_steps show the struct layout at each reorganization step
-t, --nr_definitions show how many times struct was defined
-V, --verbose be verbose
-x, --exclude=PREFIX exclude PREFIXed classes
-X, --cu_exclude=PREFIX exclude PREFIXed compilation units
Input Selection:
--debuginfo-path=PATH Search path for separate debuginfo files
-e, --executable=FILE Find addresses in FILE
-k, --kernel Find addresses in the running kernel
-K, --offline-kernel[=RELEASE] Kernel with all modules
-M, --linux-process-map=FILE Find addresses in files mapped as read from
FILE in Linux /proc/PID/maps format
-p, --pid=PID Find addresses in files mapped into process PID
-?, --help Give this help list
--usage Give a short usage message
Mandatory or optional arguments to long options are also mandatory or optional
for any corresponding short options.
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-03-30 18:25:51 +02:00
|
|
|
struct argp_state *state)
|
2006-11-02 17:47:37 +01:00
|
|
|
{
|
2007-03-30 15:07:01 +02:00
|
|
|
switch (key) {
|
2008-10-08 15:46:34 +02:00
|
|
|
case ARGP_KEY_INIT:
|
|
|
|
if (state->child_inputs != NULL)
|
|
|
|
state->child_inputs[0] = state->input;
|
|
|
|
break;
|
2007-11-16 19:01:26 +01:00
|
|
|
case 'A': class__include_nested_anonymous = 1; break;
|
|
|
|
case 'a': class__include_anonymous = 1; break;
|
|
|
|
case 'B': nr_bit_holes = atoi(arg); break;
|
2007-04-24 21:09:34 +02:00
|
|
|
case 'C': class_name = arg; break;
|
2007-11-16 19:01:26 +01:00
|
|
|
case 'c': cacheline_size = atoi(arg); break;
|
|
|
|
case 'D': decl_exclude_prefix = arg;
|
|
|
|
decl_exclude_prefix_len = strlen(decl_exclude_prefix);
|
2009-03-09 18:43:47 +01:00
|
|
|
conf_load.extra_dbg_info = 1; break;
|
2007-05-11 00:11:51 +02:00
|
|
|
case 'd': recursive = 1; break;
|
2007-11-16 19:01:26 +01:00
|
|
|
case 'E': conf.expand_types = 1; break;
|
2007-11-16 21:18:08 +01:00
|
|
|
case 'f': find_pointers_in_structs = 1;
|
|
|
|
class_name = arg; break;
|
2009-03-19 16:19:37 +01:00
|
|
|
case 'F': conf_load.format_path = arg; break;
|
2007-11-16 19:01:26 +01:00
|
|
|
case 'H': nr_holes = atoi(arg); break;
|
2009-03-09 18:43:47 +01:00
|
|
|
case 'I': conf.show_decl_info = 1;
|
|
|
|
conf_load.extra_dbg_info = 1; break;
|
2007-05-10 20:28:00 +02:00
|
|
|
case 'i': find_containers = 1;
|
|
|
|
class_name = arg; break;
|
2008-01-13 18:20:06 +01:00
|
|
|
case 'l': conf.show_first_biggest_size_base_type_member = 1; break;
|
2007-11-16 19:01:26 +01:00
|
|
|
case 'M': conf.show_only_data_members = 1; break;
|
2009-03-13 19:05:19 +01:00
|
|
|
case 'm': stats_formatter = nr_methods_formatter; break;
|
2007-11-16 19:01:26 +01:00
|
|
|
case 'N': formatter = class_name_len_formatter; break;
|
|
|
|
case 'n': formatter = nr_members_formatter; break;
|
2009-03-09 18:43:47 +01:00
|
|
|
case 'P': show_packable = 1;
|
|
|
|
conf_load.extra_dbg_info = 1; break;
|
2007-07-05 01:36:28 +02:00
|
|
|
case 'p': conf.expand_pointers = 1; break;
|
2007-11-16 19:01:26 +01:00
|
|
|
case 'q': conf.emit_stats = 0;
|
|
|
|
conf.suppress_comments = 1;
|
|
|
|
conf.suppress_offset_comment = 1; break;
|
[PAHOLE]: Use cus__loadfl, i.e. libdwfl
Now we have:
[acme@filo pahole]$ pahole --help
Usage: pahole [OPTION...] [FILE] {[CLASS]}
-a, --anon_include include anonymous classes
-A, --nested_anon_include include nested (inside other structs) anonymous
classes
-B, --bit_holes=NR_HOLES Show only structs at least NR_HOLES bit holes
-c, --cacheline_size=SIZE set cacheline size to SIZE
-D, --decl_exclude=PREFIX exclude classes declared in files with PREFIX
-E, --expand_types expand class members
-H, --holes=NR_HOLES show only structs at least NR_HOLES holes
-m, --nr_methods show number of methods
-n, --nr_members show number of members
-N, --class_name_len show size of classes
-P, --packable show only structs that has holes that can be
packed
-R, --reorganize reorg struct trying to kill holes
-s, --sizes show size of classes
-S, --show_reorg_steps show the struct layout at each reorganization step
-t, --nr_definitions show how many times struct was defined
-V, --verbose be verbose
-x, --exclude=PREFIX exclude PREFIXed classes
-X, --cu_exclude=PREFIX exclude PREFIXed compilation units
Input Selection:
--debuginfo-path=PATH Search path for separate debuginfo files
-e, --executable=FILE Find addresses in FILE
-k, --kernel Find addresses in the running kernel
-K, --offline-kernel[=RELEASE] Kernel with all modules
-M, --linux-process-map=FILE Find addresses in files mapped as read from
FILE in Linux /proc/PID/maps format
-p, --pid=PID Find addresses in files mapped into process PID
-?, --help Give this help list
--usage Give a short usage message
Mandatory or optional arguments to long options are also mandatory or optional
for any corresponding short options.
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-03-30 18:25:51 +02:00
|
|
|
case 'R': reorganize = 1; break;
|
2007-11-16 19:01:26 +01:00
|
|
|
case 'r': conf.rel_offset = 1; break;
|
2007-03-30 15:07:01 +02:00
|
|
|
case 'S': show_reorg_steps = 1; break;
|
|
|
|
case 's': formatter = size_formatter; break;
|
2009-03-13 19:05:19 +01:00
|
|
|
case 'T': stats_formatter = nr_definitions_formatter;
|
|
|
|
formatter = NULL; break;
|
2007-11-16 19:01:26 +01:00
|
|
|
case 't': separator = arg[0]; break;
|
2008-02-07 12:16:22 +01:00
|
|
|
case 'u': defined_in = 1; break;
|
2007-11-16 19:01:26 +01:00
|
|
|
case 'V': global_verbose = 1; break;
|
2008-01-12 16:14:40 +01:00
|
|
|
case 'w': word_size = atoi(arg); break;
|
2007-11-16 19:01:26 +01:00
|
|
|
case 'X': cu__exclude_prefix = arg;
|
|
|
|
cu__exclude_prefix_len = strlen(cu__exclude_prefix);
|
2007-03-30 15:07:01 +02:00
|
|
|
break;
|
|
|
|
case 'x': class__exclude_prefix = arg;
|
|
|
|
class__exclude_prefix_len = strlen(class__exclude_prefix);
|
|
|
|
break;
|
2009-03-13 19:05:19 +01:00
|
|
|
case 'y': class__include_prefix = arg;
|
|
|
|
class__include_prefix_len = strlen(class__include_prefix);
|
|
|
|
break;
|
2007-11-16 19:01:26 +01:00
|
|
|
case 'z':
|
|
|
|
hole_size_ge = atoi(arg);
|
|
|
|
if (!global_verbose)
|
|
|
|
formatter = class_name_formatter;
|
|
|
|
break;
|
2009-03-20 14:29:50 +01:00
|
|
|
case 'Z': ctf_encode = 1; break;
|
|
|
|
case ARGP_flat_arrays: conf.flat_arrays = 1; break;
|
2009-03-20 15:37:22 +01:00
|
|
|
case ARGP_show_private_classes:
|
2009-03-20 18:13:40 +01:00
|
|
|
show_private_classes = true;
|
|
|
|
conf.show_only_data_members = 1; break;
|
2009-03-20 17:54:04 +01:00
|
|
|
case ARGP_fixup_silly_bitfields:
|
|
|
|
conf_load.fixup_silly_bitfields = 1; break;
|
2009-08-24 20:13:58 +02:00
|
|
|
case ARGP_first_obj_only:
|
|
|
|
first_obj_only = true; break;
|
2009-08-24 22:22:43 +02:00
|
|
|
case ARGP_classes_as_structs:
|
|
|
|
conf.classes_as_structs = 1; break;
|
2009-10-20 17:59:12 +02:00
|
|
|
case ARGP_hex_fmt:
|
|
|
|
conf.hex_fmt = 1; break;
|
2007-03-30 15:07:01 +02:00
|
|
|
default:
|
|
|
|
return ARGP_ERR_UNKNOWN;
|
|
|
|
}
|
|
|
|
return 0;
|
2006-11-02 17:47:37 +01:00
|
|
|
}
|
|
|
|
|
2008-01-31 12:30:55 +01:00
|
|
|
static const char pahole__args_doc[] = "FILE";
|
2007-03-30 15:07:01 +02:00
|
|
|
|
|
|
|
static struct argp pahole__argp = {
|
|
|
|
.options = pahole__options,
|
|
|
|
.parser = pahole__options_parser,
|
|
|
|
.args_doc = pahole__args_doc,
|
|
|
|
};
|
|
|
|
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
static void do_reorg(struct tag *class, struct cu *cu)
|
2009-03-13 19:05:19 +01:00
|
|
|
{
|
2009-08-13 16:59:18 +02:00
|
|
|
int savings;
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
const uint8_t reorg_verbose =
|
|
|
|
show_reorg_steps ? 2 : global_verbose;
|
2009-08-18 23:21:20 +02:00
|
|
|
struct class *clone = class__clone(tag__class(class), NULL, cu);
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
if (clone == NULL) {
|
|
|
|
fprintf(stderr, "pahole: out of memory!\n");
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
class__reorganize(clone, cu, reorg_verbose, stdout);
|
|
|
|
savings = class__size(tag__class(class)) - class__size(clone);
|
|
|
|
if (savings != 0 && reorg_verbose) {
|
|
|
|
putchar('\n');
|
|
|
|
if (show_reorg_steps)
|
|
|
|
puts("/* Final reorganized struct: */");
|
|
|
|
}
|
|
|
|
tag__fprintf(class__tag(clone), cu, &conf, stdout);
|
|
|
|
if (savings != 0) {
|
|
|
|
const size_t cacheline_savings =
|
|
|
|
(tag__nr_cachelines(class, cu) -
|
|
|
|
tag__nr_cachelines(class__tag(clone), cu));
|
|
|
|
|
2009-08-13 16:59:18 +02:00
|
|
|
printf(" /* saved %d byte%s", savings,
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
savings != 1 ? "s" : "");
|
|
|
|
if (cacheline_savings != 0)
|
|
|
|
printf(" and %zu cacheline%s",
|
|
|
|
cacheline_savings,
|
|
|
|
cacheline_savings != 1 ?
|
|
|
|
"s" : "");
|
|
|
|
puts("! */");
|
|
|
|
} else
|
|
|
|
putchar('\n');
|
|
|
|
|
2009-09-20 21:46:32 +02:00
|
|
|
/* FIXME: we need to free in the right order,
|
|
|
|
* cu->obstack is being corrupted...
|
|
|
|
class__delete(clone, cu);
|
|
|
|
*/
|
2009-03-13 19:05:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static enum load_steal_kind pahole_stealer(struct cu *cu,
|
|
|
|
struct conf_load *conf_load __unused)
|
|
|
|
{
|
2012-03-22 19:30:28 +01:00
|
|
|
int ret = LSK__DELETE;
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
|
2009-03-13 19:05:19 +01:00
|
|
|
if (!cu__filter(cu))
|
2009-08-24 20:13:58 +02:00
|
|
|
goto filter_it;
|
2009-03-13 19:05:19 +01:00
|
|
|
|
2009-03-19 16:16:07 +01:00
|
|
|
if (ctf_encode) {
|
2009-12-06 17:17:29 +01:00
|
|
|
cu__encode_ctf(cu, global_verbose);
|
2009-03-19 16:16:07 +01:00
|
|
|
/*
|
|
|
|
* We still have to get the type signature code merged to eliminate
|
|
|
|
* dups, reference another CTF file, etc, so for now just encode the
|
|
|
|
* first cu that is let thru by cu__filter.
|
|
|
|
*/
|
|
|
|
goto dump_and_stop;
|
|
|
|
}
|
|
|
|
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
if (class_name == NULL) {
|
|
|
|
if (stats_formatter == nr_methods_formatter) {
|
|
|
|
cu__account_nr_methods(cu);
|
|
|
|
goto dump_it;
|
|
|
|
}
|
2009-03-13 19:05:19 +01:00
|
|
|
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
if (word_size != 0)
|
|
|
|
cu_fixup_word_size_iterator(cu);
|
2009-02-10 00:43:56 +01:00
|
|
|
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
memset(tab, ' ', sizeof(tab) - 1);
|
2009-03-13 19:05:19 +01:00
|
|
|
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
print_classes(cu);
|
2009-03-13 19:05:19 +01:00
|
|
|
goto dump_it;
|
2009-02-10 22:11:32 +01:00
|
|
|
}
|
[PAHOLE]: Use cus__loadfl, i.e. libdwfl
Now we have:
[acme@filo pahole]$ pahole --help
Usage: pahole [OPTION...] [FILE] {[CLASS]}
-a, --anon_include include anonymous classes
-A, --nested_anon_include include nested (inside other structs) anonymous
classes
-B, --bit_holes=NR_HOLES Show only structs at least NR_HOLES bit holes
-c, --cacheline_size=SIZE set cacheline size to SIZE
-D, --decl_exclude=PREFIX exclude classes declared in files with PREFIX
-E, --expand_types expand class members
-H, --holes=NR_HOLES show only structs at least NR_HOLES holes
-m, --nr_methods show number of methods
-n, --nr_members show number of members
-N, --class_name_len show size of classes
-P, --packable show only structs that has holes that can be
packed
-R, --reorganize reorg struct trying to kill holes
-s, --sizes show size of classes
-S, --show_reorg_steps show the struct layout at each reorganization step
-t, --nr_definitions show how many times struct was defined
-V, --verbose be verbose
-x, --exclude=PREFIX exclude PREFIXed classes
-X, --cu_exclude=PREFIX exclude PREFIXed compilation units
Input Selection:
--debuginfo-path=PATH Search path for separate debuginfo files
-e, --executable=FILE Find addresses in FILE
-k, --kernel Find addresses in the running kernel
-K, --offline-kernel[=RELEASE] Kernel with all modules
-M, --linux-process-map=FILE Find addresses in files mapped as read from
FILE in Linux /proc/PID/maps format
-p, --pid=PID Find addresses in files mapped into process PID
-?, --help Give this help list
--usage Give a short usage message
Mandatory or optional arguments to long options are also mandatory or optional
for any corresponding short options.
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-03-30 18:25:51 +02:00
|
|
|
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
struct str_node *pos;
|
|
|
|
struct rb_node *next = rb_first(&class_names->entries);
|
2008-01-12 16:14:40 +01:00
|
|
|
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
while (next) {
|
|
|
|
pos = rb_entry(next, struct str_node, rb_node);
|
|
|
|
next = rb_next(&pos->rb_node);
|
2007-05-11 00:11:51 +02:00
|
|
|
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
static uint16_t class_id;
|
|
|
|
bool include_decls = find_pointers_in_structs != 0 ||
|
|
|
|
stats_formatter == nr_methods_formatter;
|
|
|
|
struct tag *class = cu__find_struct_by_name(cu, pos->s,
|
|
|
|
include_decls,
|
|
|
|
&class_id);
|
|
|
|
if (class == NULL)
|
|
|
|
continue;
|
2008-10-28 21:56:47 +01:00
|
|
|
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
if (defined_in) {
|
|
|
|
puts(cu->name);
|
|
|
|
goto dump_it;
|
2009-03-13 19:05:19 +01:00
|
|
|
}
|
|
|
|
/*
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
* Ok, found it, so remove from the list to avoid printing it
|
|
|
|
* twice, in another CU.
|
2009-03-13 19:05:19 +01:00
|
|
|
*/
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
strlist__remove(class_names, pos);
|
|
|
|
|
|
|
|
class__find_holes(tag__class(class));
|
|
|
|
if (reorganize)
|
|
|
|
do_reorg(class, cu);
|
|
|
|
else if (find_containers)
|
|
|
|
print_containers(cu, class_id, 0);
|
|
|
|
else if (find_pointers_in_structs)
|
|
|
|
print_structs_with_pointer_to(cu, class_id);
|
|
|
|
else {
|
|
|
|
/*
|
|
|
|
* We don't need to print it for every compile unit
|
|
|
|
* but the previous options need
|
|
|
|
*/
|
|
|
|
tag__fprintf(class, cu, &conf, stdout);
|
|
|
|
putchar('\n');
|
|
|
|
}
|
2009-03-13 19:05:19 +01:00
|
|
|
}
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If we found all the entries in --class_name, stop
|
|
|
|
*/
|
|
|
|
if (strlist__empty(class_names)) {
|
2009-03-19 16:16:07 +01:00
|
|
|
dump_and_stop:
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
ret = LSK__STOP_LOADING;
|
|
|
|
}
|
2009-03-13 19:05:19 +01:00
|
|
|
dump_it:
|
2009-08-24 20:13:58 +02:00
|
|
|
if (first_obj_only)
|
|
|
|
ret = LSK__STOP_LOADING;
|
|
|
|
filter_it:
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int add_class_name_entry(const char *s)
|
|
|
|
{
|
|
|
|
if (strncmp(s, "file://", 7) == 0) {
|
|
|
|
if (strlist__load(class_names, s + 7))
|
|
|
|
return -1;
|
|
|
|
} else switch (strlist__add(class_names, s)) {
|
|
|
|
case -EEXIST:
|
|
|
|
if (global_verbose)
|
|
|
|
fprintf(stderr,
|
|
|
|
"pahole: %s dup in -C, ignoring\n", s);
|
|
|
|
break;
|
|
|
|
case -ENOMEM:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int populate_class_names(void)
|
|
|
|
{
|
|
|
|
char *s = class_name, *sep;
|
|
|
|
|
|
|
|
while ((sep = strchr(s, ',')) != NULL) {
|
|
|
|
*sep = '\0';
|
|
|
|
if (add_class_name_entry(s))
|
|
|
|
return -1;
|
|
|
|
*sep = ',';
|
|
|
|
s = sep + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return *s ? add_class_name_entry(s) : 0;
|
2009-03-13 19:05:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
int err, remaining, rc = EXIT_FAILURE;
|
|
|
|
|
|
|
|
if (argp_parse(&pahole__argp, argc, argv, 0, &remaining, NULL) ||
|
|
|
|
remaining == argc) {
|
|
|
|
argp_help(&pahole__argp, stderr, ARGP_HELP_SEE, argv[0]);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
class_names = strlist__new(true);
|
|
|
|
|
|
|
|
if (class_names == NULL || dwarves__init(cacheline_size)) {
|
2009-03-13 19:05:19 +01:00
|
|
|
fputs("pahole: insufficient memory\n", stderr);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
if (class_name && populate_class_names())
|
|
|
|
goto out_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
|
|
|
struct cus *cus = cus__new();
|
|
|
|
if (cus == NULL) {
|
|
|
|
fputs("pahole: insufficient memory\n", stderr);
|
|
|
|
goto out_dwarves_exit;
|
|
|
|
}
|
|
|
|
|
2009-03-13 19:05:19 +01:00
|
|
|
conf_load.steal = pahole_stealer;
|
|
|
|
|
|
|
|
err = cus__load_files(cus, &conf_load, argv + remaining);
|
|
|
|
if (err != 0) {
|
|
|
|
fputs("pahole: No debugging information found\n", 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;
|
2009-03-13 19:05:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (stats_formatter != NULL)
|
|
|
|
print_stats();
|
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-07-06 05:42:59 +02:00
|
|
|
#ifdef DEBUG_CHECK_LEAKS
|
2009-03-11 16:31:17 +01:00
|
|
|
cus__delete(cus);
|
|
|
|
structures__delete();
|
2009-07-06 05:42:59 +02:00
|
|
|
#endif
|
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-07-06 05:42:59 +02:00
|
|
|
#ifdef DEBUG_CHECK_LEAKS
|
2009-03-11 16:31:17 +01:00
|
|
|
dwarves__exit();
|
2009-07-06 05:42:59 +02:00
|
|
|
#endif
|
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-07-06 05:42:59 +02:00
|
|
|
#ifdef DEBUG_CHECK_LEAKS
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
strlist__delete(class_names);
|
2009-07-06 05:42:59 +02:00
|
|
|
#endif
|
2009-03-11 16:31:17 +01:00
|
|
|
return rc;
|
2006-10-25 01:42:39 +02:00
|
|
|
}
|