dwarves/pahole.c

1300 lines
30 KiB
C
Raw Normal View History

/*
SPDX-License-Identifier: GPL-2.0-only
Copyright (C) 2006 Mandriva Conectiva S.A.
Copyright (C) 2006 Arnaldo Carvalho de Melo <acme@mandriva.com>
Copyright (C) 2007-2008 Arnaldo Carvalho de Melo <acme@redhat.com>
*/
#include <argp.h>
#include <assert.h>
#include <stdio.h>
#include <dwarf.h>
#include <search.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include "dwarves_reorganize.h"
#include "dwarves.h"
#include "dutil.h"
#include "ctf_encoder.h"
#include "btf_encoder.h"
static bool btf_encode;
static bool ctf_encode;
static bool first_obj_only;
static uint8_t class__include_anonymous;
static uint8_t class__include_nested_anonymous;
[PAHOLE]: Allow changing the architecture word-size Using a x86_64 binary: [acme@doppio pahole]$ build/pahole -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 8 */ union { struct { long unsigned int arg0; /* 8 8 */ long unsigned int arg1; /* 16 8 */ long unsigned int arg2; /* 24 8 */ long unsigned int arg3; /* 32 8 */ }; /* 32 */ struct { u32 * uaddr; /* 8 8 */ u32 val; /* 16 4 */ u32 flags; /* 20 4 */ u64 time; /* 24 8 */ } fu; /* 24 */ }; /* 8 32 */ /* size: 40, cachelines: 1 */ /* last cacheline: 40 bytes */ }; Changing the word-size from 8 to 4 bytes: [acme@doppio pahole]$ build/pahole -w 4 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 4 */ union { struct { long unsigned int arg0; /* 4 4 */ long unsigned int arg1; /* 8 4 */ long unsigned int arg2; /* 12 4 */ long unsigned int arg3; /* 16 4 */ }; /* 16 */ struct { u32 * uaddr; /* 4 4 */ u32 val; /* 8 4 */ u32 flags; /* 12 4 */ u64 time; /* 16 8 */ } fu; /* 20 */ }; /* 4 20 */ /* size: 24, cachelines: 1 */ /* last cacheline: 24 bytes */ }; And from 8 to 16: [acme@doppio pahole]$ build/pahole -w 16 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 16 */ union { struct { long unsigned int arg0; /* 16 16 */ long unsigned int arg1; /* 32 16 */ long unsigned int arg2; /* 48 16 */ long unsigned int arg3; /* 64 16 */ /* --- cacheline 1 boundary (64 bytes) --- */ }; /* 64 */ struct { u32 * uaddr; /* 16 16 */ u32 val; /* 32 4 */ u32 flags; /* 36 4 */ u64 time; /* 40 8 */ } fu; /* 32 */ }; /* 16 64 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ /* size: 80, cachelines: 2 */ /* last cacheline: 16 bytes */ }; More work is required to specify different alignment rules. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2008-01-12 16:14:40 +01:00
static uint8_t word_size, original_word_size;
static char *class__exclude_prefix;
static size_t class__exclude_prefix_len;
static char *class__include_prefix;
static size_t class__include_prefix_len;
static char *cu__exclude_prefix;
static size_t cu__exclude_prefix_len;
static char *decl_exclude_prefix;
static size_t decl_exclude_prefix_len;
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;
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;
[PAHOLE]: Introduce --recursive For now only affects the --contains output. Example showing the structs that include struct list_head in a linux kernel module: [acme@filo pahole]$ pahole --recursive --contains list_head examples/ipv6.ko.debug.x86-64 inet_protosw proto sock_iocb key_type msg_queue msg_msg nf_hook_ops softnet_data net_device softnet_data dma_device dma_client dma_chan class_device net_device softnet_data dma_chan class klist_node device_driver device klist device_driver bus_type device file_system_type nfs_lock_info file_lock block_device address_space inode dquot mem_dqinfo super_block inode signal_struct page kioctx file kiocb work_struct delayed_work kioctx timer_list ifmcaddr6 inet6_dev inet6_ifaddr neigh_table neighbour net_device softnet_data sock inet_sock delayed_work kioctx plist_head task_struct sigpending signal_struct task_struct user_struct device dev_pm_info device mutex_waiter mutex seq_file block_device quota_info super_block dquot super_block inode zone per_cpu_pages free_area kset bus_type subsystem class bus_type __wait_queue_head __wait_queue rw_semaphore quota_info super_block super_block inode key blocking_notifier_head bus_type subsystem class bus_type mm_struct dentry vm_area_struct kobject class_device net_device softnet_data dma_chan device_driver module_kobject module device kset bus_type subsystem class bus_type lock_class module mm_struct task_struct Handling in multi-cu objects is not very precise, as the same struct has different dwarf offsets (id) in each CU. A mitigation for this problem will be provided with the --cu_list and --cu_name upcoming options, where one will be able to get a list of the object files in a, for instance, linux kernel .ko module and also to specify a cu name to be the only to be considered when processing multi-cu files (again, such as .ko linux kernel modules). This ends up being also useful to generate a reverse class hierarchy :-) Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-05-11 00:11:51 +02:00
static uint8_t recursive;
static size_t cacheline_size;
static uint8_t find_containers;
static uint8_t find_pointers_in_structs;
static int reorganize;
static bool show_private_classes;
static bool defined_in;
static int show_reorg_steps;
static char *class_name;
static struct strlist *class_names;
static char separator = '\t';
static struct conf_fprintf conf = {
.emit_stats = 1,
};
static struct conf_load conf_load;
struct structure {
struct list_head node;
struct rb_node rb_node;
char *name;
uint32_t nr_files;
uint32_t nr_methods;
};
static struct structure *structure__new(const char *name)
{
struct structure *st = malloc(sizeof(*st));
if (st != NULL) {
st->name = strdup(name);
if (st->name == NULL) {
free(st);
return NULL;
}
st->nr_files = 1;
st->nr_methods = 0;
}
return st;
}
static void structure__delete(struct structure *st)
{
free(st->name);
free(st);
}
static struct rb_root structures__tree = RB_ROOT;
static LIST_HEAD(structures__list);
static struct structure *structures__add(struct class *class,
const struct cu *cu,
bool *existing_entry)
{
struct rb_node **p = &structures__tree.rb_node;
struct rb_node *parent = NULL;
struct structure *str;
const char *new_class_name = class__name(class, cu);
while (*p != NULL) {
int rc;
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;
else {
*existing_entry = true;
return str;
}
}
str = structure__new(new_class_name);
if (str == NULL)
return NULL;
*existing_entry = false;
rb_link_node(&str->rb_node, parent, p);
rb_insert_color(&str->rb_node, &structures__tree);
/* For linear traversals */
list_add_tail(&str->node, &structures__list);
return str;
}
void structures__delete(void)
{
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);
}
}
static void nr_definitions_formatter(struct structure *st)
{
printf("%s%c%u\n", st->name, separator, st->nr_files);
}
static void nr_members_formatter(struct class *class,
struct cu *cu, uint16_t id __unused)
{
printf("%s%c%u\n", class__name(class, cu), separator,
class__nr_members(class));
}
static void nr_methods_formatter(struct structure *st)
{
printf("%s%c%u\n", st->name, separator, st->nr_methods);
}
static void size_formatter(struct class *class,
struct cu *cu, uint16_t id __unused)
{
printf("%s%c%d%c%u\n", class__name(class, cu), separator,
class__size(class), separator, class->nr_holes);
}
static void class_name_len_formatter(struct class *class, struct cu *cu,
uint16_t id __unused)
{
const char *name = class__name(class, cu);
printf("%s%c%zd\n", name, separator, strlen(name));
}
static void class_name_formatter(struct class *class,
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
{
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
}
static void class_formatter(struct class *class, struct cu *cu, uint16_t id)
{
struct tag *typedef_alias = NULL;
struct tag *tag = class__tag(class);
const char *name = class__name(class, cu);
if (name == NULL) {
/*
* Find the first typedef for this struct, this is enough
* as if we optimize the struct all the typedefs will be
* affected.
*/
typedef_alias = cu__find_first_typedef_of_type(cu, id);
/*
* If there is no typedefs for this anonymous struct it is
* found just inside another struct, and in this case it'll
* be printed when the type it is in is printed, but if
* the user still wants to see its statistics, just use
* --nested_anon_include.
*/
if (typedef_alias == NULL && !class__include_nested_anonymous)
return;
}
if (typedef_alias != NULL) {
struct type *tdef = tag__type(typedef_alias);
conf.prefix = "typedef";
conf.suffix = type__name(tdef, cu);
} else
conf.prefix = conf.suffix = NULL;
tag__fprintf(tag, cu, &conf, stdout);
putchar('\n');
}
static void print_packable_info(struct class *c, struct cu *cu, uint16_t id)
{
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;
const char *name = class__name(c, cu);
/* Anonymous struct? Try finding a typedef */
if (name == NULL) {
const struct tag *tdef =
cu__find_first_typedef_of_type(cu, id);
if (tdef != NULL)
name = class__name(tag__class(tdef), cu);
}
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",
tag__decl_file(t, cu),
tag__decl_line(t, cu),
separator,
orig_size, separator,
new_size, separator,
savings);
}
static void (*stats_formatter)(struct structure *st);
static void print_stats(void)
{
struct structure *pos;
list_for_each_entry(pos, &structures__list, node)
stats_formatter(pos);
}
static struct class *class__filter(struct class *class, struct cu *cu,
uint16_t tag_id);
static void (*formatter)(struct class *class,
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_or_union(cu, id, pos) {
bool existing_entry;
struct structure *str;
if (pos->type.namespace.name == 0 &&
!(class__include_anonymous ||
class__include_nested_anonymous))
continue;
if (!class__filter(pos, cu, id))
continue;
/*
* 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...
*/
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;
}
}
if (show_packable && !global_verbose)
print_packable_info(pos, cu, id);
else if (formatter != NULL)
formatter(pos, cu, id);
}
}
static struct cu *cu__filter(struct cu *cu)
{
if (cu__exclude_prefix != NULL &&
(cu->name == NULL ||
strncmp(cu__exclude_prefix, cu->name,
cu__exclude_prefix_len) == 0))
return NULL;
return cu;
}
static int class__packable(struct class *class, struct cu *cu)
{
struct class *clone;
if (class->nr_holes == 0 && class->nr_bit_holes == 0)
return 0;
clone = class__clone(class, NULL, cu);
if (clone == NULL)
return 0;
class__reorganize(clone, cu, 0, stdout);
if (class__size(class) > class__size(clone)) {
class->priv = clone;
return 1;
}
/* FIXME: we need to free in the right order,
* cu->obstack is being corrupted...
class__delete(clone, cu);
*/
return 0;
}
static struct class *class__filter(struct class *class, struct cu *cu,
uint16_t tag_id)
{
struct tag *tag = class__tag(class);
const char *name;
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
name = class__name(class, cu);
if (class__is_declaration(class))
return NULL;
if (!class__include_anonymous && name == NULL)
return NULL;
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);
if (tdef != NULL) {
struct class *c = tag__class(tdef);
name = class__name(c, cu);
}
}
if (name != NULL && strncmp(class__exclude_prefix, name,
class__exclude_prefix_len) == 0)
return NULL;
}
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);
if (tdef != NULL) {
struct class *c = tag__class(tdef);
name = class__name(c, cu);
}
}
if (name != NULL && strncmp(class__include_prefix, name,
class__include_prefix_len) != 0)
return NULL;
}
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),
decl_exclude_prefix_len) == 0))
return NULL;
/*
* The following only make sense for structs, i.e. 'struct class',
* and as we can get here with a union, that is represented by a 'struct type',
* bail out if we get here with an union
*/
if (!tag__is_struct(class__tag(class)))
return class;
if (tag->top_level)
class__find_holes(class);
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)))
return NULL;
if (show_packable && !class__packable(class, cu))
return NULL;
return class;
}
static void union__find_new_size(struct tag *tag, struct cu *cu);
[PAHOLE]: Allow changing the architecture word-size Using a x86_64 binary: [acme@doppio pahole]$ build/pahole -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 8 */ union { struct { long unsigned int arg0; /* 8 8 */ long unsigned int arg1; /* 16 8 */ long unsigned int arg2; /* 24 8 */ long unsigned int arg3; /* 32 8 */ }; /* 32 */ struct { u32 * uaddr; /* 8 8 */ u32 val; /* 16 4 */ u32 flags; /* 20 4 */ u64 time; /* 24 8 */ } fu; /* 24 */ }; /* 8 32 */ /* size: 40, cachelines: 1 */ /* last cacheline: 40 bytes */ }; Changing the word-size from 8 to 4 bytes: [acme@doppio pahole]$ build/pahole -w 4 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 4 */ union { struct { long unsigned int arg0; /* 4 4 */ long unsigned int arg1; /* 8 4 */ long unsigned int arg2; /* 12 4 */ long unsigned int arg3; /* 16 4 */ }; /* 16 */ struct { u32 * uaddr; /* 4 4 */ u32 val; /* 8 4 */ u32 flags; /* 12 4 */ u64 time; /* 16 8 */ } fu; /* 20 */ }; /* 4 20 */ /* size: 24, cachelines: 1 */ /* last cacheline: 24 bytes */ }; And from 8 to 16: [acme@doppio pahole]$ build/pahole -w 16 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 16 */ union { struct { long unsigned int arg0; /* 16 16 */ long unsigned int arg1; /* 32 16 */ long unsigned int arg2; /* 48 16 */ long unsigned int arg3; /* 64 16 */ /* --- cacheline 1 boundary (64 bytes) --- */ }; /* 64 */ struct { u32 * uaddr; /* 16 16 */ u32 val; /* 32 4 */ u32 flags; /* 36 4 */ u64 time; /* 40 8 */ } fu; /* 32 */ }; /* 16 64 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ /* size: 80, cachelines: 2 */ /* last cacheline: 16 bytes */ }; More work is required to specify different alignment rules. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2008-01-12 16:14:40 +01:00
static void class__resize_LP(struct tag *tag, struct cu *cu)
{
struct tag *tag_pos;
struct class *class = tag__class(tag);
[PAHOLE]: Allow changing the architecture word-size Using a x86_64 binary: [acme@doppio pahole]$ build/pahole -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 8 */ union { struct { long unsigned int arg0; /* 8 8 */ long unsigned int arg1; /* 16 8 */ long unsigned int arg2; /* 24 8 */ long unsigned int arg3; /* 32 8 */ }; /* 32 */ struct { u32 * uaddr; /* 8 8 */ u32 val; /* 16 4 */ u32 flags; /* 20 4 */ u64 time; /* 24 8 */ } fu; /* 24 */ }; /* 8 32 */ /* size: 40, cachelines: 1 */ /* last cacheline: 40 bytes */ }; Changing the word-size from 8 to 4 bytes: [acme@doppio pahole]$ build/pahole -w 4 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 4 */ union { struct { long unsigned int arg0; /* 4 4 */ long unsigned int arg1; /* 8 4 */ long unsigned int arg2; /* 12 4 */ long unsigned int arg3; /* 16 4 */ }; /* 16 */ struct { u32 * uaddr; /* 4 4 */ u32 val; /* 8 4 */ u32 flags; /* 12 4 */ u64 time; /* 16 8 */ } fu; /* 20 */ }; /* 4 20 */ /* size: 24, cachelines: 1 */ /* last cacheline: 24 bytes */ }; And from 8 to 16: [acme@doppio pahole]$ build/pahole -w 16 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 16 */ union { struct { long unsigned int arg0; /* 16 16 */ long unsigned int arg1; /* 32 16 */ long unsigned int arg2; /* 48 16 */ long unsigned int arg3; /* 64 16 */ /* --- cacheline 1 boundary (64 bytes) --- */ }; /* 64 */ struct { u32 * uaddr; /* 16 16 */ u32 val; /* 32 4 */ u32 flags; /* 36 4 */ u64 time; /* 40 8 */ } fu; /* 32 */ }; /* 16 64 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ /* size: 80, cachelines: 2 */ /* last cacheline: 16 bytes */ }; More work is required to specify different alignment rules. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2008-01-12 16:14:40 +01:00
size_t word_size_diff;
size_t orig_size = class->type.size;
[PAHOLE]: Allow changing the architecture word-size Using a x86_64 binary: [acme@doppio pahole]$ build/pahole -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 8 */ union { struct { long unsigned int arg0; /* 8 8 */ long unsigned int arg1; /* 16 8 */ long unsigned int arg2; /* 24 8 */ long unsigned int arg3; /* 32 8 */ }; /* 32 */ struct { u32 * uaddr; /* 8 8 */ u32 val; /* 16 4 */ u32 flags; /* 20 4 */ u64 time; /* 24 8 */ } fu; /* 24 */ }; /* 8 32 */ /* size: 40, cachelines: 1 */ /* last cacheline: 40 bytes */ }; Changing the word-size from 8 to 4 bytes: [acme@doppio pahole]$ build/pahole -w 4 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 4 */ union { struct { long unsigned int arg0; /* 4 4 */ long unsigned int arg1; /* 8 4 */ long unsigned int arg2; /* 12 4 */ long unsigned int arg3; /* 16 4 */ }; /* 16 */ struct { u32 * uaddr; /* 4 4 */ u32 val; /* 8 4 */ u32 flags; /* 12 4 */ u64 time; /* 16 8 */ } fu; /* 20 */ }; /* 4 20 */ /* size: 24, cachelines: 1 */ /* last cacheline: 24 bytes */ }; And from 8 to 16: [acme@doppio pahole]$ build/pahole -w 16 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 16 */ union { struct { long unsigned int arg0; /* 16 16 */ long unsigned int arg1; /* 32 16 */ long unsigned int arg2; /* 48 16 */ long unsigned int arg3; /* 64 16 */ /* --- cacheline 1 boundary (64 bytes) --- */ }; /* 64 */ struct { u32 * uaddr; /* 16 16 */ u32 val; /* 32 4 */ u32 flags; /* 36 4 */ u64 time; /* 40 8 */ } fu; /* 32 */ }; /* 16 64 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ /* size: 80, cachelines: 2 */ /* last cacheline: 16 bytes */ }; More work is required to specify different alignment rules. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2008-01-12 16:14:40 +01:00
if (tag__type(tag)->resized)
return;
tag__type(tag)->resized = 1;
[PAHOLE]: Allow changing the architecture word-size Using a x86_64 binary: [acme@doppio pahole]$ build/pahole -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 8 */ union { struct { long unsigned int arg0; /* 8 8 */ long unsigned int arg1; /* 16 8 */ long unsigned int arg2; /* 24 8 */ long unsigned int arg3; /* 32 8 */ }; /* 32 */ struct { u32 * uaddr; /* 8 8 */ u32 val; /* 16 4 */ u32 flags; /* 20 4 */ u64 time; /* 24 8 */ } fu; /* 24 */ }; /* 8 32 */ /* size: 40, cachelines: 1 */ /* last cacheline: 40 bytes */ }; Changing the word-size from 8 to 4 bytes: [acme@doppio pahole]$ build/pahole -w 4 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 4 */ union { struct { long unsigned int arg0; /* 4 4 */ long unsigned int arg1; /* 8 4 */ long unsigned int arg2; /* 12 4 */ long unsigned int arg3; /* 16 4 */ }; /* 16 */ struct { u32 * uaddr; /* 4 4 */ u32 val; /* 8 4 */ u32 flags; /* 12 4 */ u64 time; /* 16 8 */ } fu; /* 20 */ }; /* 4 20 */ /* size: 24, cachelines: 1 */ /* last cacheline: 24 bytes */ }; And from 8 to 16: [acme@doppio pahole]$ build/pahole -w 16 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 16 */ union { struct { long unsigned int arg0; /* 16 16 */ long unsigned int arg1; /* 32 16 */ long unsigned int arg2; /* 48 16 */ long unsigned int arg3; /* 64 16 */ /* --- cacheline 1 boundary (64 bytes) --- */ }; /* 64 */ struct { u32 * uaddr; /* 16 16 */ u32 val; /* 32 4 */ u32 flags; /* 36 4 */ u64 time; /* 40 8 */ } fu; /* 32 */ }; /* 16 64 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ /* size: 80, cachelines: 2 */ /* last cacheline: 16 bytes */ }; More work is required to specify different alignment rules. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
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;
size_t array_multiplier = 1;
[PAHOLE]: Allow changing the architecture word-size Using a x86_64 binary: [acme@doppio pahole]$ build/pahole -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 8 */ union { struct { long unsigned int arg0; /* 8 8 */ long unsigned int arg1; /* 16 8 */ long unsigned int arg2; /* 24 8 */ long unsigned int arg3; /* 32 8 */ }; /* 32 */ struct { u32 * uaddr; /* 8 8 */ u32 val; /* 16 4 */ u32 flags; /* 20 4 */ u64 time; /* 24 8 */ } fu; /* 24 */ }; /* 8 32 */ /* size: 40, cachelines: 1 */ /* last cacheline: 40 bytes */ }; Changing the word-size from 8 to 4 bytes: [acme@doppio pahole]$ build/pahole -w 4 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 4 */ union { struct { long unsigned int arg0; /* 4 4 */ long unsigned int arg1; /* 8 4 */ long unsigned int arg2; /* 12 4 */ long unsigned int arg3; /* 16 4 */ }; /* 16 */ struct { u32 * uaddr; /* 4 4 */ u32 val; /* 8 4 */ u32 flags; /* 12 4 */ u64 time; /* 16 8 */ } fu; /* 20 */ }; /* 4 20 */ /* size: 24, cachelines: 1 */ /* last cacheline: 24 bytes */ }; And from 8 to 16: [acme@doppio pahole]$ build/pahole -w 16 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 16 */ union { struct { long unsigned int arg0; /* 16 16 */ long unsigned int arg1; /* 32 16 */ long unsigned int arg2; /* 48 16 */ long unsigned int arg3; /* 64 16 */ /* --- cacheline 1 boundary (64 bytes) --- */ }; /* 64 */ struct { u32 * uaddr; /* 16 16 */ u32 val; /* 32 4 */ u32 flags; /* 36 4 */ u64 time; /* 40 8 */ } fu; /* 32 */ }; /* 16 64 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ /* size: 80, cachelines: 2 */ /* last cacheline: 16 bytes */ }; More work is required to specify different alignment rules. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
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;
type = cu__type(cu, tag_pos->type);
tag__assert_search_result(type);
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];
type = cu__type(cu, type->type);
tag__assert_search_result(type);
}
if (tag__is_typedef(type)) {
type = tag__follow_typedef(type, cu);
tag__assert_search_result(type);
}
[PAHOLE]: Allow changing the architecture word-size Using a x86_64 binary: [acme@doppio pahole]$ build/pahole -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 8 */ union { struct { long unsigned int arg0; /* 8 8 */ long unsigned int arg1; /* 16 8 */ long unsigned int arg2; /* 24 8 */ long unsigned int arg3; /* 32 8 */ }; /* 32 */ struct { u32 * uaddr; /* 8 8 */ u32 val; /* 16 4 */ u32 flags; /* 20 4 */ u64 time; /* 24 8 */ } fu; /* 24 */ }; /* 8 32 */ /* size: 40, cachelines: 1 */ /* last cacheline: 40 bytes */ }; Changing the word-size from 8 to 4 bytes: [acme@doppio pahole]$ build/pahole -w 4 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 4 */ union { struct { long unsigned int arg0; /* 4 4 */ long unsigned int arg1; /* 8 4 */ long unsigned int arg2; /* 12 4 */ long unsigned int arg3; /* 16 4 */ }; /* 16 */ struct { u32 * uaddr; /* 4 4 */ u32 val; /* 8 4 */ u32 flags; /* 12 4 */ u64 time; /* 16 8 */ } fu; /* 20 */ }; /* 4 20 */ /* size: 24, cachelines: 1 */ /* last cacheline: 24 bytes */ }; And from 8 to 16: [acme@doppio pahole]$ build/pahole -w 16 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 16 */ union { struct { long unsigned int arg0; /* 16 16 */ long unsigned int arg1; /* 32 16 */ long unsigned int arg2; /* 48 16 */ long unsigned int arg3; /* 64 16 */ /* --- cacheline 1 boundary (64 bytes) --- */ }; /* 64 */ struct { u32 * uaddr; /* 16 16 */ u32 val; /* 32 4 */ u32 flags; /* 36 4 */ u64 time; /* 40 8 */ } fu; /* 32 */ }; /* 16 64 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ /* size: 80, cachelines: 2 */ /* last cacheline: 16 bytes */ }; More work is required to specify different alignment rules. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2008-01-12 16:14:40 +01:00
switch (type->tag) {
case DW_TAG_base_type: {
struct base_type *bt = tag__base_type(type);
char bf[64];
const char *name = base_type__name(bt, cu, bf,
sizeof(bf));
if (strcmp(name, "long int") != 0 &&
strcmp(name, "long unsigned int") != 0)
[PAHOLE]: Allow changing the architecture word-size Using a x86_64 binary: [acme@doppio pahole]$ build/pahole -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 8 */ union { struct { long unsigned int arg0; /* 8 8 */ long unsigned int arg1; /* 16 8 */ long unsigned int arg2; /* 24 8 */ long unsigned int arg3; /* 32 8 */ }; /* 32 */ struct { u32 * uaddr; /* 8 8 */ u32 val; /* 16 4 */ u32 flags; /* 20 4 */ u64 time; /* 24 8 */ } fu; /* 24 */ }; /* 8 32 */ /* size: 40, cachelines: 1 */ /* last cacheline: 40 bytes */ }; Changing the word-size from 8 to 4 bytes: [acme@doppio pahole]$ build/pahole -w 4 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 4 */ union { struct { long unsigned int arg0; /* 4 4 */ long unsigned int arg1; /* 8 4 */ long unsigned int arg2; /* 12 4 */ long unsigned int arg3; /* 16 4 */ }; /* 16 */ struct { u32 * uaddr; /* 4 4 */ u32 val; /* 8 4 */ u32 flags; /* 12 4 */ u64 time; /* 16 8 */ } fu; /* 20 */ }; /* 4 20 */ /* size: 24, cachelines: 1 */ /* last cacheline: 24 bytes */ }; And from 8 to 16: [acme@doppio pahole]$ build/pahole -w 16 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 16 */ union { struct { long unsigned int arg0; /* 16 16 */ long unsigned int arg1; /* 32 16 */ long unsigned int arg2; /* 48 16 */ long unsigned int arg3; /* 64 16 */ /* --- cacheline 1 boundary (64 bytes) --- */ }; /* 64 */ struct { u32 * uaddr; /* 16 16 */ u32 val; /* 32 4 */ u32 flags; /* 36 4 */ u64 time; /* 40 8 */ } fu; /* 32 */ }; /* 16 64 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ /* size: 80, cachelines: 2 */ /* last cacheline: 16 bytes */ }; More work is required to specify different alignment rules. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
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:
if (tag__is_union(type))
union__find_new_size(type, cu);
else
class__resize_LP(type, cu);
[PAHOLE]: Allow changing the architecture word-size Using a x86_64 binary: [acme@doppio pahole]$ build/pahole -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 8 */ union { struct { long unsigned int arg0; /* 8 8 */ long unsigned int arg1; /* 16 8 */ long unsigned int arg2; /* 24 8 */ long unsigned int arg3; /* 32 8 */ }; /* 32 */ struct { u32 * uaddr; /* 8 8 */ u32 val; /* 16 4 */ u32 flags; /* 20 4 */ u64 time; /* 24 8 */ } fu; /* 24 */ }; /* 8 32 */ /* size: 40, cachelines: 1 */ /* last cacheline: 40 bytes */ }; Changing the word-size from 8 to 4 bytes: [acme@doppio pahole]$ build/pahole -w 4 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 4 */ union { struct { long unsigned int arg0; /* 4 4 */ long unsigned int arg1; /* 8 4 */ long unsigned int arg2; /* 12 4 */ long unsigned int arg3; /* 16 4 */ }; /* 16 */ struct { u32 * uaddr; /* 4 4 */ u32 val; /* 8 4 */ u32 flags; /* 12 4 */ u64 time; /* 16 8 */ } fu; /* 20 */ }; /* 4 20 */ /* size: 24, cachelines: 1 */ /* last cacheline: 24 bytes */ }; And from 8 to 16: [acme@doppio pahole]$ build/pahole -w 16 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 16 */ union { struct { long unsigned int arg0; /* 16 16 */ long unsigned int arg1; /* 32 16 */ long unsigned int arg2; /* 48 16 */ long unsigned int arg3; /* 64 16 */ /* --- cacheline 1 boundary (64 bytes) --- */ }; /* 64 */ struct { u32 * uaddr; /* 16 16 */ u32 val; /* 32 4 */ u32 flags; /* 36 4 */ u64 time; /* 40 8 */ } fu; /* 32 */ }; /* 16 64 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ /* size: 80, cachelines: 2 */ /* last cacheline: 16 bytes */ }; More work is required to specify different alignment rules. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2008-01-12 16:14:40 +01:00
diff = tag__type(type)->size_diff;
break;
}
diff *= array_multiplier;
[PAHOLE]: Allow changing the architecture word-size Using a x86_64 binary: [acme@doppio pahole]$ build/pahole -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 8 */ union { struct { long unsigned int arg0; /* 8 8 */ long unsigned int arg1; /* 16 8 */ long unsigned int arg2; /* 24 8 */ long unsigned int arg3; /* 32 8 */ }; /* 32 */ struct { u32 * uaddr; /* 8 8 */ u32 val; /* 16 4 */ u32 flags; /* 20 4 */ u64 time; /* 24 8 */ } fu; /* 24 */ }; /* 8 32 */ /* size: 40, cachelines: 1 */ /* last cacheline: 40 bytes */ }; Changing the word-size from 8 to 4 bytes: [acme@doppio pahole]$ build/pahole -w 4 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 4 */ union { struct { long unsigned int arg0; /* 4 4 */ long unsigned int arg1; /* 8 4 */ long unsigned int arg2; /* 12 4 */ long unsigned int arg3; /* 16 4 */ }; /* 16 */ struct { u32 * uaddr; /* 4 4 */ u32 val; /* 8 4 */ u32 flags; /* 12 4 */ u64 time; /* 16 8 */ } fu; /* 20 */ }; /* 4 20 */ /* size: 24, cachelines: 1 */ /* last cacheline: 24 bytes */ }; And from 8 to 16: [acme@doppio pahole]$ build/pahole -w 16 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 16 */ union { struct { long unsigned int arg0; /* 16 16 */ long unsigned int arg1; /* 32 16 */ long unsigned int arg2; /* 48 16 */ long unsigned int arg3; /* 64 16 */ /* --- cacheline 1 boundary (64 bytes) --- */ }; /* 64 */ struct { u32 * uaddr; /* 16 16 */ u32 val; /* 32 4 */ u32 flags; /* 36 4 */ u64 time; /* 40 8 */ } fu; /* 32 */ }; /* 16 64 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ /* size: 80, cachelines: 2 */ /* last cacheline: 16 bytes */ }; More work is required to specify different alignment rules. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
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) {
class->type.size -= diff;
class__subtract_offsets_from(class, m, diff);
[PAHOLE]: Allow changing the architecture word-size Using a x86_64 binary: [acme@doppio pahole]$ build/pahole -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 8 */ union { struct { long unsigned int arg0; /* 8 8 */ long unsigned int arg1; /* 16 8 */ long unsigned int arg2; /* 24 8 */ long unsigned int arg3; /* 32 8 */ }; /* 32 */ struct { u32 * uaddr; /* 8 8 */ u32 val; /* 16 4 */ u32 flags; /* 20 4 */ u64 time; /* 24 8 */ } fu; /* 24 */ }; /* 8 32 */ /* size: 40, cachelines: 1 */ /* last cacheline: 40 bytes */ }; Changing the word-size from 8 to 4 bytes: [acme@doppio pahole]$ build/pahole -w 4 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 4 */ union { struct { long unsigned int arg0; /* 4 4 */ long unsigned int arg1; /* 8 4 */ long unsigned int arg2; /* 12 4 */ long unsigned int arg3; /* 16 4 */ }; /* 16 */ struct { u32 * uaddr; /* 4 4 */ u32 val; /* 8 4 */ u32 flags; /* 12 4 */ u64 time; /* 16 8 */ } fu; /* 20 */ }; /* 4 20 */ /* size: 24, cachelines: 1 */ /* last cacheline: 24 bytes */ }; And from 8 to 16: [acme@doppio pahole]$ build/pahole -w 16 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 16 */ union { struct { long unsigned int arg0; /* 16 16 */ long unsigned int arg1; /* 32 16 */ long unsigned int arg2; /* 48 16 */ long unsigned int arg3; /* 64 16 */ /* --- cacheline 1 boundary (64 bytes) --- */ }; /* 64 */ struct { u32 * uaddr; /* 16 16 */ u32 val; /* 32 4 */ u32 flags; /* 36 4 */ u64 time; /* 40 8 */ } fu; /* 32 */ }; /* 16 64 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ /* size: 80, cachelines: 2 */ /* last cacheline: 16 bytes */ }; More work is required to specify different alignment rules. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2008-01-12 16:14:40 +01:00
} else {
class->type.size += diff;
class__add_offsets_from(class, m, diff);
[PAHOLE]: Allow changing the architecture word-size Using a x86_64 binary: [acme@doppio pahole]$ build/pahole -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 8 */ union { struct { long unsigned int arg0; /* 8 8 */ long unsigned int arg1; /* 16 8 */ long unsigned int arg2; /* 24 8 */ long unsigned int arg3; /* 32 8 */ }; /* 32 */ struct { u32 * uaddr; /* 8 8 */ u32 val; /* 16 4 */ u32 flags; /* 20 4 */ u64 time; /* 24 8 */ } fu; /* 24 */ }; /* 8 32 */ /* size: 40, cachelines: 1 */ /* last cacheline: 40 bytes */ }; Changing the word-size from 8 to 4 bytes: [acme@doppio pahole]$ build/pahole -w 4 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 4 */ union { struct { long unsigned int arg0; /* 4 4 */ long unsigned int arg1; /* 8 4 */ long unsigned int arg2; /* 12 4 */ long unsigned int arg3; /* 16 4 */ }; /* 16 */ struct { u32 * uaddr; /* 4 4 */ u32 val; /* 8 4 */ u32 flags; /* 12 4 */ u64 time; /* 16 8 */ } fu; /* 20 */ }; /* 4 20 */ /* size: 24, cachelines: 1 */ /* last cacheline: 24 bytes */ }; And from 8 to 16: [acme@doppio pahole]$ build/pahole -w 16 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 16 */ union { struct { long unsigned int arg0; /* 16 16 */ long unsigned int arg1; /* 32 16 */ long unsigned int arg2; /* 48 16 */ long unsigned int arg3; /* 64 16 */ /* --- cacheline 1 boundary (64 bytes) --- */ }; /* 64 */ struct { u32 * uaddr; /* 16 16 */ u32 val; /* 32 4 */ u32 flags; /* 36 4 */ u64 time; /* 40 8 */ } fu; /* 32 */ }; /* 16 64 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ /* size: 80, cachelines: 2 */ /* last cacheline: 16 bytes */ }; More work is required to specify different alignment rules. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2008-01-12 16:14:40 +01:00
}
}
}
if (original_word_size > word_size)
tag__type(tag)->size_diff = orig_size - class->type.size;
[PAHOLE]: Allow changing the architecture word-size Using a x86_64 binary: [acme@doppio pahole]$ build/pahole -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 8 */ union { struct { long unsigned int arg0; /* 8 8 */ long unsigned int arg1; /* 16 8 */ long unsigned int arg2; /* 24 8 */ long unsigned int arg3; /* 32 8 */ }; /* 32 */ struct { u32 * uaddr; /* 8 8 */ u32 val; /* 16 4 */ u32 flags; /* 20 4 */ u64 time; /* 24 8 */ } fu; /* 24 */ }; /* 8 32 */ /* size: 40, cachelines: 1 */ /* last cacheline: 40 bytes */ }; Changing the word-size from 8 to 4 bytes: [acme@doppio pahole]$ build/pahole -w 4 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 4 */ union { struct { long unsigned int arg0; /* 4 4 */ long unsigned int arg1; /* 8 4 */ long unsigned int arg2; /* 12 4 */ long unsigned int arg3; /* 16 4 */ }; /* 16 */ struct { u32 * uaddr; /* 4 4 */ u32 val; /* 8 4 */ u32 flags; /* 12 4 */ u64 time; /* 16 8 */ } fu; /* 20 */ }; /* 4 20 */ /* size: 24, cachelines: 1 */ /* last cacheline: 24 bytes */ }; And from 8 to 16: [acme@doppio pahole]$ build/pahole -w 16 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 16 */ union { struct { long unsigned int arg0; /* 16 16 */ long unsigned int arg1; /* 32 16 */ long unsigned int arg2; /* 48 16 */ long unsigned int arg3; /* 64 16 */ /* --- cacheline 1 boundary (64 bytes) --- */ }; /* 64 */ struct { u32 * uaddr; /* 16 16 */ u32 val; /* 32 4 */ u32 flags; /* 36 4 */ u64 time; /* 40 8 */ } fu; /* 32 */ }; /* 16 64 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ /* size: 80, cachelines: 2 */ /* last cacheline: 16 bytes */ }; More work is required to specify different alignment rules. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2008-01-12 16:14:40 +01:00
else
tag__type(tag)->size_diff = class->type.size - orig_size;
[PAHOLE]: Allow changing the architecture word-size Using a x86_64 binary: [acme@doppio pahole]$ build/pahole -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 8 */ union { struct { long unsigned int arg0; /* 8 8 */ long unsigned int arg1; /* 16 8 */ long unsigned int arg2; /* 24 8 */ long unsigned int arg3; /* 32 8 */ }; /* 32 */ struct { u32 * uaddr; /* 8 8 */ u32 val; /* 16 4 */ u32 flags; /* 20 4 */ u64 time; /* 24 8 */ } fu; /* 24 */ }; /* 8 32 */ /* size: 40, cachelines: 1 */ /* last cacheline: 40 bytes */ }; Changing the word-size from 8 to 4 bytes: [acme@doppio pahole]$ build/pahole -w 4 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 4 */ union { struct { long unsigned int arg0; /* 4 4 */ long unsigned int arg1; /* 8 4 */ long unsigned int arg2; /* 12 4 */ long unsigned int arg3; /* 16 4 */ }; /* 16 */ struct { u32 * uaddr; /* 4 4 */ u32 val; /* 8 4 */ u32 flags; /* 12 4 */ u64 time; /* 16 8 */ } fu; /* 20 */ }; /* 4 20 */ /* size: 24, cachelines: 1 */ /* last cacheline: 24 bytes */ }; And from 8 to 16: [acme@doppio pahole]$ build/pahole -w 16 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 16 */ union { struct { long unsigned int arg0; /* 16 16 */ long unsigned int arg1; /* 32 16 */ long unsigned int arg2; /* 48 16 */ long unsigned int arg3; /* 64 16 */ /* --- cacheline 1 boundary (64 bytes) --- */ }; /* 64 */ struct { u32 * uaddr; /* 16 16 */ u32 val; /* 32 4 */ u32 flags; /* 36 4 */ u64 time; /* 40 8 */ } fu; /* 32 */ }; /* 16 64 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ /* size: 80, cachelines: 2 */ /* last cacheline: 16 bytes */ }; More work is required to specify different alignment rules. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2008-01-12 16:14:40 +01:00
class__find_holes(class);
class__fixup_alignment(class, cu);
[PAHOLE]: Allow changing the architecture word-size Using a x86_64 binary: [acme@doppio pahole]$ build/pahole -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 8 */ union { struct { long unsigned int arg0; /* 8 8 */ long unsigned int arg1; /* 16 8 */ long unsigned int arg2; /* 24 8 */ long unsigned int arg3; /* 32 8 */ }; /* 32 */ struct { u32 * uaddr; /* 8 8 */ u32 val; /* 16 4 */ u32 flags; /* 20 4 */ u64 time; /* 24 8 */ } fu; /* 24 */ }; /* 8 32 */ /* size: 40, cachelines: 1 */ /* last cacheline: 40 bytes */ }; Changing the word-size from 8 to 4 bytes: [acme@doppio pahole]$ build/pahole -w 4 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 4 */ union { struct { long unsigned int arg0; /* 4 4 */ long unsigned int arg1; /* 8 4 */ long unsigned int arg2; /* 12 4 */ long unsigned int arg3; /* 16 4 */ }; /* 16 */ struct { u32 * uaddr; /* 4 4 */ u32 val; /* 8 4 */ u32 flags; /* 12 4 */ u64 time; /* 16 8 */ } fu; /* 20 */ }; /* 4 20 */ /* size: 24, cachelines: 1 */ /* last cacheline: 24 bytes */ }; And from 8 to 16: [acme@doppio pahole]$ build/pahole -w 16 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 16 */ union { struct { long unsigned int arg0; /* 16 16 */ long unsigned int arg1; /* 32 16 */ long unsigned int arg2; /* 48 16 */ long unsigned int arg3; /* 64 16 */ /* --- cacheline 1 boundary (64 bytes) --- */ }; /* 64 */ struct { u32 * uaddr; /* 16 16 */ u32 val; /* 32 4 */ u32 flags; /* 36 4 */ u64 time; /* 40 8 */ } fu; /* 32 */ }; /* 16 64 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ /* size: 80, cachelines: 2 */ /* last cacheline: 16 bytes */ }; More work is required to specify different alignment rules. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2008-01-12 16:14:40 +01:00
}
static void union__find_new_size(struct tag *tag, struct cu *cu)
{
struct tag *tag_pos;
struct type *type = tag__type(tag);
[PAHOLE]: Allow changing the architecture word-size Using a x86_64 binary: [acme@doppio pahole]$ build/pahole -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 8 */ union { struct { long unsigned int arg0; /* 8 8 */ long unsigned int arg1; /* 16 8 */ long unsigned int arg2; /* 24 8 */ long unsigned int arg3; /* 32 8 */ }; /* 32 */ struct { u32 * uaddr; /* 8 8 */ u32 val; /* 16 4 */ u32 flags; /* 20 4 */ u64 time; /* 24 8 */ } fu; /* 24 */ }; /* 8 32 */ /* size: 40, cachelines: 1 */ /* last cacheline: 40 bytes */ }; Changing the word-size from 8 to 4 bytes: [acme@doppio pahole]$ build/pahole -w 4 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 4 */ union { struct { long unsigned int arg0; /* 4 4 */ long unsigned int arg1; /* 8 4 */ long unsigned int arg2; /* 12 4 */ long unsigned int arg3; /* 16 4 */ }; /* 16 */ struct { u32 * uaddr; /* 4 4 */ u32 val; /* 8 4 */ u32 flags; /* 12 4 */ u64 time; /* 16 8 */ } fu; /* 20 */ }; /* 4 20 */ /* size: 24, cachelines: 1 */ /* last cacheline: 24 bytes */ }; And from 8 to 16: [acme@doppio pahole]$ build/pahole -w 16 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 16 */ union { struct { long unsigned int arg0; /* 16 16 */ long unsigned int arg1; /* 32 16 */ long unsigned int arg2; /* 48 16 */ long unsigned int arg3; /* 64 16 */ /* --- cacheline 1 boundary (64 bytes) --- */ }; /* 64 */ struct { u32 * uaddr; /* 16 16 */ u32 val; /* 32 4 */ u32 flags; /* 36 4 */ u64 time; /* 40 8 */ } fu; /* 32 */ }; /* 16 64 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ /* size: 80, cachelines: 2 */ /* last cacheline: 16 bytes */ }; More work is required to specify different alignment rules. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2008-01-12 16:14:40 +01:00
size_t max_size = 0;
if (type->resized)
return;
type->resized = 1;
type__for_each_tag(type, tag_pos) {
[PAHOLE]: Allow changing the architecture word-size Using a x86_64 binary: [acme@doppio pahole]$ build/pahole -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 8 */ union { struct { long unsigned int arg0; /* 8 8 */ long unsigned int arg1; /* 16 8 */ long unsigned int arg2; /* 24 8 */ long unsigned int arg3; /* 32 8 */ }; /* 32 */ struct { u32 * uaddr; /* 8 8 */ u32 val; /* 16 4 */ u32 flags; /* 20 4 */ u64 time; /* 24 8 */ } fu; /* 24 */ }; /* 8 32 */ /* size: 40, cachelines: 1 */ /* last cacheline: 40 bytes */ }; Changing the word-size from 8 to 4 bytes: [acme@doppio pahole]$ build/pahole -w 4 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 4 */ union { struct { long unsigned int arg0; /* 4 4 */ long unsigned int arg1; /* 8 4 */ long unsigned int arg2; /* 12 4 */ long unsigned int arg3; /* 16 4 */ }; /* 16 */ struct { u32 * uaddr; /* 4 4 */ u32 val; /* 8 4 */ u32 flags; /* 12 4 */ u64 time; /* 16 8 */ } fu; /* 20 */ }; /* 4 20 */ /* size: 24, cachelines: 1 */ /* last cacheline: 24 bytes */ }; And from 8 to 16: [acme@doppio pahole]$ build/pahole -w 16 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 16 */ union { struct { long unsigned int arg0; /* 16 16 */ long unsigned int arg1; /* 32 16 */ long unsigned int arg2; /* 48 16 */ long unsigned int arg3; /* 64 16 */ /* --- cacheline 1 boundary (64 bytes) --- */ }; /* 64 */ struct { u32 * uaddr; /* 16 16 */ u32 val; /* 32 4 */ u32 flags; /* 36 4 */ u64 time; /* 40 8 */ } fu; /* 32 */ }; /* 16 64 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ /* size: 80, cachelines: 2 */ /* last cacheline: 16 bytes */ }; More work is required to specify different alignment rules. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
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;
type = cu__type(cu, tag_pos->type);
tag__assert_search_result(type);
if (tag__is_typedef(type))
type = tag__follow_typedef(type, cu);
if (tag__is_union(type))
union__find_new_size(type, cu);
else if (tag__is_struct(type))
class__resize_LP(type, cu);
[PAHOLE]: Allow changing the architecture word-size Using a x86_64 binary: [acme@doppio pahole]$ build/pahole -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 8 */ union { struct { long unsigned int arg0; /* 8 8 */ long unsigned int arg1; /* 16 8 */ long unsigned int arg2; /* 24 8 */ long unsigned int arg3; /* 32 8 */ }; /* 32 */ struct { u32 * uaddr; /* 8 8 */ u32 val; /* 16 4 */ u32 flags; /* 20 4 */ u64 time; /* 24 8 */ } fu; /* 24 */ }; /* 8 32 */ /* size: 40, cachelines: 1 */ /* last cacheline: 40 bytes */ }; Changing the word-size from 8 to 4 bytes: [acme@doppio pahole]$ build/pahole -w 4 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 4 */ union { struct { long unsigned int arg0; /* 4 4 */ long unsigned int arg1; /* 8 4 */ long unsigned int arg2; /* 12 4 */ long unsigned int arg3; /* 16 4 */ }; /* 16 */ struct { u32 * uaddr; /* 4 4 */ u32 val; /* 8 4 */ u32 flags; /* 12 4 */ u64 time; /* 16 8 */ } fu; /* 20 */ }; /* 4 20 */ /* size: 24, cachelines: 1 */ /* last cacheline: 24 bytes */ }; And from 8 to 16: [acme@doppio pahole]$ build/pahole -w 16 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 16 */ union { struct { long unsigned int arg0; /* 16 16 */ long unsigned int arg1; /* 32 16 */ long unsigned int arg2; /* 48 16 */ long unsigned int arg3; /* 64 16 */ /* --- cacheline 1 boundary (64 bytes) --- */ }; /* 64 */ struct { u32 * uaddr; /* 16 16 */ u32 val; /* 32 4 */ u32 flags; /* 36 4 */ u64 time; /* 40 8 */ } fu; /* 32 */ }; /* 16 64 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ /* size: 80, cachelines: 2 */ /* last cacheline: 16 bytes */ }; More work is required to specify different alignment rules. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2008-01-12 16:14:40 +01:00
size = tag__size(type, cu);
if (size > max_size)
max_size = size;
}
if (max_size > type->size)
type->size_diff = max_size - type->size;
[PAHOLE]: Allow changing the architecture word-size Using a x86_64 binary: [acme@doppio pahole]$ build/pahole -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 8 */ union { struct { long unsigned int arg0; /* 8 8 */ long unsigned int arg1; /* 16 8 */ long unsigned int arg2; /* 24 8 */ long unsigned int arg3; /* 32 8 */ }; /* 32 */ struct { u32 * uaddr; /* 8 8 */ u32 val; /* 16 4 */ u32 flags; /* 20 4 */ u64 time; /* 24 8 */ } fu; /* 24 */ }; /* 8 32 */ /* size: 40, cachelines: 1 */ /* last cacheline: 40 bytes */ }; Changing the word-size from 8 to 4 bytes: [acme@doppio pahole]$ build/pahole -w 4 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 4 */ union { struct { long unsigned int arg0; /* 4 4 */ long unsigned int arg1; /* 8 4 */ long unsigned int arg2; /* 12 4 */ long unsigned int arg3; /* 16 4 */ }; /* 16 */ struct { u32 * uaddr; /* 4 4 */ u32 val; /* 8 4 */ u32 flags; /* 12 4 */ u64 time; /* 16 8 */ } fu; /* 20 */ }; /* 4 20 */ /* size: 24, cachelines: 1 */ /* last cacheline: 24 bytes */ }; And from 8 to 16: [acme@doppio pahole]$ build/pahole -w 16 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 16 */ union { struct { long unsigned int arg0; /* 16 16 */ long unsigned int arg1; /* 32 16 */ long unsigned int arg2; /* 48 16 */ long unsigned int arg3; /* 64 16 */ /* --- cacheline 1 boundary (64 bytes) --- */ }; /* 64 */ struct { u32 * uaddr; /* 16 16 */ u32 val; /* 32 4 */ u32 flags; /* 36 4 */ u64 time; /* 40 8 */ } fu; /* 32 */ }; /* 16 64 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ /* size: 80, cachelines: 2 */ /* last cacheline: 16 bytes */ }; More work is required to specify different alignment rules. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2008-01-12 16:14:40 +01:00
else
type->size_diff = type->size - max_size;
[PAHOLE]: Allow changing the architecture word-size Using a x86_64 binary: [acme@doppio pahole]$ build/pahole -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 8 */ union { struct { long unsigned int arg0; /* 8 8 */ long unsigned int arg1; /* 16 8 */ long unsigned int arg2; /* 24 8 */ long unsigned int arg3; /* 32 8 */ }; /* 32 */ struct { u32 * uaddr; /* 8 8 */ u32 val; /* 16 4 */ u32 flags; /* 20 4 */ u64 time; /* 24 8 */ } fu; /* 24 */ }; /* 8 32 */ /* size: 40, cachelines: 1 */ /* last cacheline: 40 bytes */ }; Changing the word-size from 8 to 4 bytes: [acme@doppio pahole]$ build/pahole -w 4 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 4 */ union { struct { long unsigned int arg0; /* 4 4 */ long unsigned int arg1; /* 8 4 */ long unsigned int arg2; /* 12 4 */ long unsigned int arg3; /* 16 4 */ }; /* 16 */ struct { u32 * uaddr; /* 4 4 */ u32 val; /* 8 4 */ u32 flags; /* 12 4 */ u64 time; /* 16 8 */ } fu; /* 20 */ }; /* 4 20 */ /* size: 24, cachelines: 1 */ /* last cacheline: 24 bytes */ }; And from 8 to 16: [acme@doppio pahole]$ build/pahole -w 16 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 16 */ union { struct { long unsigned int arg0; /* 16 16 */ long unsigned int arg1; /* 32 16 */ long unsigned int arg2; /* 48 16 */ long unsigned int arg3; /* 64 16 */ /* --- cacheline 1 boundary (64 bytes) --- */ }; /* 64 */ struct { u32 * uaddr; /* 16 16 */ u32 val; /* 32 4 */ u32 flags; /* 36 4 */ u64 time; /* 40 8 */ } fu; /* 32 */ }; /* 16 64 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ /* size: 80, cachelines: 2 */ /* last cacheline: 16 bytes */ }; More work is required to specify different alignment rules. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2008-01-12 16:14:40 +01:00
type->size = max_size;
[PAHOLE]: Allow changing the architecture word-size Using a x86_64 binary: [acme@doppio pahole]$ build/pahole -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 8 */ union { struct { long unsigned int arg0; /* 8 8 */ long unsigned int arg1; /* 16 8 */ long unsigned int arg2; /* 24 8 */ long unsigned int arg3; /* 32 8 */ }; /* 32 */ struct { u32 * uaddr; /* 8 8 */ u32 val; /* 16 4 */ u32 flags; /* 20 4 */ u64 time; /* 24 8 */ } fu; /* 24 */ }; /* 8 32 */ /* size: 40, cachelines: 1 */ /* last cacheline: 40 bytes */ }; Changing the word-size from 8 to 4 bytes: [acme@doppio pahole]$ build/pahole -w 4 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 4 */ union { struct { long unsigned int arg0; /* 4 4 */ long unsigned int arg1; /* 8 4 */ long unsigned int arg2; /* 12 4 */ long unsigned int arg3; /* 16 4 */ }; /* 16 */ struct { u32 * uaddr; /* 4 4 */ u32 val; /* 8 4 */ u32 flags; /* 12 4 */ u64 time; /* 16 8 */ } fu; /* 20 */ }; /* 4 20 */ /* size: 24, cachelines: 1 */ /* last cacheline: 24 bytes */ }; And from 8 to 16: [acme@doppio pahole]$ build/pahole -w 16 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 16 */ union { struct { long unsigned int arg0; /* 16 16 */ long unsigned int arg1; /* 32 16 */ long unsigned int arg2; /* 48 16 */ long unsigned int arg3; /* 64 16 */ /* --- cacheline 1 boundary (64 bytes) --- */ }; /* 64 */ struct { u32 * uaddr; /* 16 16 */ u32 val; /* 32 4 */ u32 flags; /* 36 4 */ u64 time; /* 40 8 */ } fu; /* 32 */ }; /* 16 64 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ /* size: 80, cachelines: 2 */ /* last cacheline: 16 bytes */ }; More work is required to specify different alignment rules. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2008-01-12 16:14:40 +01:00
}
static void tag__fixup_word_size(struct tag *tag, struct cu *cu)
[PAHOLE]: Allow changing the architecture word-size Using a x86_64 binary: [acme@doppio pahole]$ build/pahole -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 8 */ union { struct { long unsigned int arg0; /* 8 8 */ long unsigned int arg1; /* 16 8 */ long unsigned int arg2; /* 24 8 */ long unsigned int arg3; /* 32 8 */ }; /* 32 */ struct { u32 * uaddr; /* 8 8 */ u32 val; /* 16 4 */ u32 flags; /* 20 4 */ u64 time; /* 24 8 */ } fu; /* 24 */ }; /* 8 32 */ /* size: 40, cachelines: 1 */ /* last cacheline: 40 bytes */ }; Changing the word-size from 8 to 4 bytes: [acme@doppio pahole]$ build/pahole -w 4 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 4 */ union { struct { long unsigned int arg0; /* 4 4 */ long unsigned int arg1; /* 8 4 */ long unsigned int arg2; /* 12 4 */ long unsigned int arg3; /* 16 4 */ }; /* 16 */ struct { u32 * uaddr; /* 4 4 */ u32 val; /* 8 4 */ u32 flags; /* 12 4 */ u64 time; /* 16 8 */ } fu; /* 20 */ }; /* 4 20 */ /* size: 24, cachelines: 1 */ /* last cacheline: 24 bytes */ }; And from 8 to 16: [acme@doppio pahole]$ build/pahole -w 16 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 16 */ union { struct { long unsigned int arg0; /* 16 16 */ long unsigned int arg1; /* 32 16 */ long unsigned int arg2; /* 48 16 */ long unsigned int arg3; /* 64 16 */ /* --- cacheline 1 boundary (64 bytes) --- */ }; /* 64 */ struct { u32 * uaddr; /* 16 16 */ u32 val; /* 32 4 */ u32 flags; /* 36 4 */ u64 time; /* 40 8 */ } fu; /* 32 */ }; /* 16 64 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ /* size: 80, cachelines: 2 */ /* last cacheline: 16 bytes */ }; More work is required to specify different alignment rules. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2008-01-12 16:14:40 +01:00
{
if (tag__is_struct(tag) || tag__is_union(tag)) {
[PAHOLE]: Allow changing the architecture word-size Using a x86_64 binary: [acme@doppio pahole]$ build/pahole -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 8 */ union { struct { long unsigned int arg0; /* 8 8 */ long unsigned int arg1; /* 16 8 */ long unsigned int arg2; /* 24 8 */ long unsigned int arg3; /* 32 8 */ }; /* 32 */ struct { u32 * uaddr; /* 8 8 */ u32 val; /* 16 4 */ u32 flags; /* 20 4 */ u64 time; /* 24 8 */ } fu; /* 24 */ }; /* 8 32 */ /* size: 40, cachelines: 1 */ /* last cacheline: 40 bytes */ }; Changing the word-size from 8 to 4 bytes: [acme@doppio pahole]$ build/pahole -w 4 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 4 */ union { struct { long unsigned int arg0; /* 4 4 */ long unsigned int arg1; /* 8 4 */ long unsigned int arg2; /* 12 4 */ long unsigned int arg3; /* 16 4 */ }; /* 16 */ struct { u32 * uaddr; /* 4 4 */ u32 val; /* 8 4 */ u32 flags; /* 12 4 */ u64 time; /* 16 8 */ } fu; /* 20 */ }; /* 4 20 */ /* size: 24, cachelines: 1 */ /* last cacheline: 24 bytes */ }; And from 8 to 16: [acme@doppio pahole]$ build/pahole -w 16 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 16 */ union { struct { long unsigned int arg0; /* 16 16 */ long unsigned int arg1; /* 32 16 */ long unsigned int arg2; /* 48 16 */ long unsigned int arg3; /* 64 16 */ /* --- cacheline 1 boundary (64 bytes) --- */ }; /* 64 */ struct { u32 * uaddr; /* 16 16 */ u32 val; /* 32 4 */ u32 flags; /* 36 4 */ u64 time; /* 40 8 */ } fu; /* 32 */ }; /* 16 64 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ /* size: 80, cachelines: 2 */ /* last cacheline: 16 bytes */ }; More work is required to specify different alignment rules. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2008-01-12 16:14:40 +01:00
struct tag *pos;
namespace__for_each_tag(tag__namespace(tag), pos)
tag__fixup_word_size(pos, cu);
[PAHOLE]: Allow changing the architecture word-size Using a x86_64 binary: [acme@doppio pahole]$ build/pahole -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 8 */ union { struct { long unsigned int arg0; /* 8 8 */ long unsigned int arg1; /* 16 8 */ long unsigned int arg2; /* 24 8 */ long unsigned int arg3; /* 32 8 */ }; /* 32 */ struct { u32 * uaddr; /* 8 8 */ u32 val; /* 16 4 */ u32 flags; /* 20 4 */ u64 time; /* 24 8 */ } fu; /* 24 */ }; /* 8 32 */ /* size: 40, cachelines: 1 */ /* last cacheline: 40 bytes */ }; Changing the word-size from 8 to 4 bytes: [acme@doppio pahole]$ build/pahole -w 4 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 4 */ union { struct { long unsigned int arg0; /* 4 4 */ long unsigned int arg1; /* 8 4 */ long unsigned int arg2; /* 12 4 */ long unsigned int arg3; /* 16 4 */ }; /* 16 */ struct { u32 * uaddr; /* 4 4 */ u32 val; /* 8 4 */ u32 flags; /* 12 4 */ u64 time; /* 16 8 */ } fu; /* 20 */ }; /* 4 20 */ /* size: 24, cachelines: 1 */ /* last cacheline: 24 bytes */ }; And from 8 to 16: [acme@doppio pahole]$ build/pahole -w 16 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 16 */ union { struct { long unsigned int arg0; /* 16 16 */ long unsigned int arg1; /* 32 16 */ long unsigned int arg2; /* 48 16 */ long unsigned int arg3; /* 64 16 */ /* --- cacheline 1 boundary (64 bytes) --- */ }; /* 64 */ struct { u32 * uaddr; /* 16 16 */ u32 val; /* 32 4 */ u32 flags; /* 36 4 */ u64 time; /* 40 8 */ } fu; /* 32 */ }; /* 16 64 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ /* size: 80, cachelines: 2 */ /* last cacheline: 16 bytes */ }; More work is required to specify different alignment rules. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2008-01-12 16:14:40 +01:00
}
switch (tag->tag) {
case DW_TAG_base_type: {
struct base_type *bt = tag__base_type(tag);
/*
* 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.
*/
if (!bt->name)
return;
char bf[64];
const char *name = base_type__name(bt, cu, bf, sizeof(bf));
if (strcmp(name, "long int") == 0 ||
strcmp(name, "long unsigned int") == 0)
bt->bit_size = word_size * 8;
[PAHOLE]: Allow changing the architecture word-size Using a x86_64 binary: [acme@doppio pahole]$ build/pahole -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 8 */ union { struct { long unsigned int arg0; /* 8 8 */ long unsigned int arg1; /* 16 8 */ long unsigned int arg2; /* 24 8 */ long unsigned int arg3; /* 32 8 */ }; /* 32 */ struct { u32 * uaddr; /* 8 8 */ u32 val; /* 16 4 */ u32 flags; /* 20 4 */ u64 time; /* 24 8 */ } fu; /* 24 */ }; /* 8 32 */ /* size: 40, cachelines: 1 */ /* last cacheline: 40 bytes */ }; Changing the word-size from 8 to 4 bytes: [acme@doppio pahole]$ build/pahole -w 4 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 4 */ union { struct { long unsigned int arg0; /* 4 4 */ long unsigned int arg1; /* 8 4 */ long unsigned int arg2; /* 12 4 */ long unsigned int arg3; /* 16 4 */ }; /* 16 */ struct { u32 * uaddr; /* 4 4 */ u32 val; /* 8 4 */ u32 flags; /* 12 4 */ u64 time; /* 16 8 */ } fu; /* 20 */ }; /* 4 20 */ /* size: 24, cachelines: 1 */ /* last cacheline: 24 bytes */ }; And from 8 to 16: [acme@doppio pahole]$ build/pahole -w 16 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 16 */ union { struct { long unsigned int arg0; /* 16 16 */ long unsigned int arg1; /* 32 16 */ long unsigned int arg2; /* 48 16 */ long unsigned int arg3; /* 64 16 */ /* --- cacheline 1 boundary (64 bytes) --- */ }; /* 64 */ struct { u32 * uaddr; /* 16 16 */ u32 val; /* 32 4 */ u32 flags; /* 36 4 */ u64 time; /* 40 8 */ } fu; /* 32 */ }; /* 16 64 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ /* size: 80, cachelines: 2 */ /* last cacheline: 16 bytes */ }; More work is required to specify different alignment rules. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
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;
}
return;
[PAHOLE]: Allow changing the architecture word-size Using a x86_64 binary: [acme@doppio pahole]$ build/pahole -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 8 */ union { struct { long unsigned int arg0; /* 8 8 */ long unsigned int arg1; /* 16 8 */ long unsigned int arg2; /* 24 8 */ long unsigned int arg3; /* 32 8 */ }; /* 32 */ struct { u32 * uaddr; /* 8 8 */ u32 val; /* 16 4 */ u32 flags; /* 20 4 */ u64 time; /* 24 8 */ } fu; /* 24 */ }; /* 8 32 */ /* size: 40, cachelines: 1 */ /* last cacheline: 40 bytes */ }; Changing the word-size from 8 to 4 bytes: [acme@doppio pahole]$ build/pahole -w 4 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 4 */ union { struct { long unsigned int arg0; /* 4 4 */ long unsigned int arg1; /* 8 4 */ long unsigned int arg2; /* 12 4 */ long unsigned int arg3; /* 16 4 */ }; /* 16 */ struct { u32 * uaddr; /* 4 4 */ u32 val; /* 8 4 */ u32 flags; /* 12 4 */ u64 time; /* 16 8 */ } fu; /* 20 */ }; /* 4 20 */ /* size: 24, cachelines: 1 */ /* last cacheline: 24 bytes */ }; And from 8 to 16: [acme@doppio pahole]$ build/pahole -w 16 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 16 */ union { struct { long unsigned int arg0; /* 16 16 */ long unsigned int arg1; /* 32 16 */ long unsigned int arg2; /* 48 16 */ long unsigned int arg3; /* 64 16 */ /* --- cacheline 1 boundary (64 bytes) --- */ }; /* 64 */ struct { u32 * uaddr; /* 16 16 */ u32 val; /* 32 4 */ u32 flags; /* 36 4 */ u64 time; /* 40 8 */ } fu; /* 32 */ }; /* 16 64 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ /* size: 80, cachelines: 2 */ /* last cacheline: 16 bytes */ }; More work is required to specify different alignment rules. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2008-01-12 16:14:40 +01:00
}
static void cu_fixup_word_size_iterator(struct cu *cu)
[PAHOLE]: Allow changing the architecture word-size Using a x86_64 binary: [acme@doppio pahole]$ build/pahole -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 8 */ union { struct { long unsigned int arg0; /* 8 8 */ long unsigned int arg1; /* 16 8 */ long unsigned int arg2; /* 24 8 */ long unsigned int arg3; /* 32 8 */ }; /* 32 */ struct { u32 * uaddr; /* 8 8 */ u32 val; /* 16 4 */ u32 flags; /* 20 4 */ u64 time; /* 24 8 */ } fu; /* 24 */ }; /* 8 32 */ /* size: 40, cachelines: 1 */ /* last cacheline: 40 bytes */ }; Changing the word-size from 8 to 4 bytes: [acme@doppio pahole]$ build/pahole -w 4 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 4 */ union { struct { long unsigned int arg0; /* 4 4 */ long unsigned int arg1; /* 8 4 */ long unsigned int arg2; /* 12 4 */ long unsigned int arg3; /* 16 4 */ }; /* 16 */ struct { u32 * uaddr; /* 4 4 */ u32 val; /* 8 4 */ u32 flags; /* 12 4 */ u64 time; /* 16 8 */ } fu; /* 20 */ }; /* 4 20 */ /* size: 24, cachelines: 1 */ /* last cacheline: 24 bytes */ }; And from 8 to 16: [acme@doppio pahole]$ build/pahole -w 16 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 16 */ union { struct { long unsigned int arg0; /* 16 16 */ long unsigned int arg1; /* 32 16 */ long unsigned int arg2; /* 48 16 */ long unsigned int arg3; /* 64 16 */ /* --- cacheline 1 boundary (64 bytes) --- */ }; /* 64 */ struct { u32 * uaddr; /* 16 16 */ u32 val; /* 32 4 */ u32 flags; /* 36 4 */ u64 time; /* 40 8 */ } fu; /* 32 */ }; /* 16 64 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ /* size: 80, cachelines: 2 */ /* last cacheline: 16 bytes */ }; More work is required to specify different alignment rules. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2008-01-12 16:14:40 +01:00
{
original_word_size = cu->addr_size;
cu->addr_size = word_size;
uint16_t id;
struct tag *pos;
cu__for_each_type(cu, id, pos)
tag__fixup_word_size(pos, cu);
}
static void cu__account_nr_methods(struct cu *cu)
{
struct function *pos_function;
struct structure *str;
uint32_t id;
cu__for_each_function(cu, id, pos_function) {
struct class_member *pos;
list_for_each_entry(pos, &pos_function->proto.parms, tag.node) {
struct tag *type = cu__type(cu, pos->tag.type);
if (type == NULL || type->tag != DW_TAG_pointer_type)
continue;
type = cu__type(cu, type->type);
if (type == NULL || !tag__is_struct(type))
continue;
struct type *ctype = tag__type(type);
if (ctype->namespace.name == 0)
continue;
struct class *class = tag__class(type);
if (!class__filter(class, cu, 0))
continue;
bool existing_entry;
str = structures__add(class, cu, &existing_entry);
if (str == NULL) {
fprintf(stderr, "pahole: insufficient memory "
"for processing %s, skipping it...\n",
cu->name);
return;
}
if (!existing_entry)
class__find_holes(class);
++str->nr_methods;
}
}
}
[PAHOLE]: Introduce --recursive For now only affects the --contains output. Example showing the structs that include struct list_head in a linux kernel module: [acme@filo pahole]$ pahole --recursive --contains list_head examples/ipv6.ko.debug.x86-64 inet_protosw proto sock_iocb key_type msg_queue msg_msg nf_hook_ops softnet_data net_device softnet_data dma_device dma_client dma_chan class_device net_device softnet_data dma_chan class klist_node device_driver device klist device_driver bus_type device file_system_type nfs_lock_info file_lock block_device address_space inode dquot mem_dqinfo super_block inode signal_struct page kioctx file kiocb work_struct delayed_work kioctx timer_list ifmcaddr6 inet6_dev inet6_ifaddr neigh_table neighbour net_device softnet_data sock inet_sock delayed_work kioctx plist_head task_struct sigpending signal_struct task_struct user_struct device dev_pm_info device mutex_waiter mutex seq_file block_device quota_info super_block dquot super_block inode zone per_cpu_pages free_area kset bus_type subsystem class bus_type __wait_queue_head __wait_queue rw_semaphore quota_info super_block super_block inode key blocking_notifier_head bus_type subsystem class bus_type mm_struct dentry vm_area_struct kobject class_device net_device softnet_data dma_chan device_driver module_kobject module device kset bus_type subsystem class bus_type lock_class module mm_struct task_struct Handling in multi-cu objects is not very precise, as the same struct has different dwarf offsets (id) in each CU. A mitigation for this problem will be provided with the --cu_list and --cu_name upcoming options, where one will be able to get a list of the object files in a, for instance, linux kernel .ko module and also to specify a cu name to be the only to be considered when processing multi-cu files (again, such as .ko linux kernel modules). This ends up being also useful to generate a reverse class hierarchy :-) Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-05-11 00:11:51 +02:00
static char tab[128];
static void print_structs_with_pointer_to(const struct cu *cu, uint16_t type)
{
struct class *pos;
struct class_member *pos_member;
uint16_t id;
cu__for_each_struct(cu, id, pos) {
bool looked = false;
struct structure *str;
if (pos->type.namespace.name == 0)
continue;
type__for_each_member(&pos->type, pos_member) {
struct tag *ctype = cu__type(cu, pos_member->tag.type);
tag__assert_search_result(ctype);
if (ctype->tag != DW_TAG_pointer_type || ctype->type != type)
continue;
if (!looked) {
bool existing_entry;
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;
}
printf("%s: %s\n", str->name,
class_member__name(pos_member, cu));
}
}
}
static void print_containers(const struct cu *cu, uint16_t type, int ident)
{
struct class *pos;
uint16_t id;
cu__for_each_struct(cu, id, pos) {
if (pos->type.namespace.name == 0)
continue;
const uint32_t n = type__nr_members_of_type(&pos->type, type);
if (n == 0)
continue;
if (ident == 0) {
bool existing_entry;
struct structure *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;
}
printf("%.*s%s", ident * 2, tab, class__name(pos, cu));
if (global_verbose)
printf(": %u", n);
putchar('\n');
if (recursive)
print_containers(cu, id, ident + 1);
}
}
/* Name and version of program. */
ARGP_PROGRAM_VERSION_HOOK_DEF = dwarves_print_version;
#define ARGP_flat_arrays 300
#define ARGP_show_private_classes 301
#define ARGP_fixup_silly_bitfields 302
#define ARGP_first_obj_only 303
#define ARGP_classes_as_structs 304
#define ARGP_hex_fmt 305
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"
},
{
.name = "class_name",
.key = 'C',
.arg = "CLASS_NAME",
.doc = "Show just this class"
},
{
.name = "find_pointers_to",
.key = 'f',
.arg = "CLASS_NAME",
.doc = "Find pointers to CLASS_NAME"
},
{
.name = "format_path",
.key = 'F',
.arg = "FORMAT_LIST",
.doc = "List of debugging formats to try"
},
{
.name = "contains",
.key = 'i',
.arg = "CLASS_NAME",
.doc = "Show classes that contains CLASS_NAME"
},
{
.name = "show_decl_info",
.key = 'I',
.doc = "Show the file and line number where the tags were defined"
},
{
.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",
},
{
.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',
.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',
.doc = "expand class members",
},
{
.name = "nr_members",
.key = 'n',
.doc = "show number of members",
},
{
.name = "rel_offset",
.key = 'r',
.doc = "show relative offsets of members in inner structs"
},
[PAHOLE]: Introduce --recursive For now only affects the --contains output. Example showing the structs that include struct list_head in a linux kernel module: [acme@filo pahole]$ pahole --recursive --contains list_head examples/ipv6.ko.debug.x86-64 inet_protosw proto sock_iocb key_type msg_queue msg_msg nf_hook_ops softnet_data net_device softnet_data dma_device dma_client dma_chan class_device net_device softnet_data dma_chan class klist_node device_driver device klist device_driver bus_type device file_system_type nfs_lock_info file_lock block_device address_space inode dquot mem_dqinfo super_block inode signal_struct page kioctx file kiocb work_struct delayed_work kioctx timer_list ifmcaddr6 inet6_dev inet6_ifaddr neigh_table neighbour net_device softnet_data sock inet_sock delayed_work kioctx plist_head task_struct sigpending signal_struct task_struct user_struct device dev_pm_info device mutex_waiter mutex seq_file block_device quota_info super_block dquot super_block inode zone per_cpu_pages free_area kset bus_type subsystem class bus_type __wait_queue_head __wait_queue rw_semaphore quota_info super_block super_block inode key blocking_notifier_head bus_type subsystem class bus_type mm_struct dentry vm_area_struct kobject class_device net_device softnet_data dma_chan device_driver module_kobject module device kset bus_type subsystem class bus_type lock_class module mm_struct task_struct Handling in multi-cu objects is not very precise, as the same struct has different dwarf offsets (id) in each CU. A mitigation for this problem will be provided with the --cu_list and --cu_name upcoming options, where one will be able to get a list of the object files in a, for instance, linux kernel .ko module and also to specify a cu name to be the only to be considered when processing multi-cu files (again, such as .ko linux kernel modules). This ends up being also useful to generate a reverse class hierarchy :-) Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-05-11 00:11:51 +02:00
{
.name = "recursive",
.key = 'd',
.doc = "recursive mode, affects several other flags",
},
{
.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',
.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",
},
{
.name = "show_first_biggest_size_base_type_member",
.key = 'l',
.doc = "show first biggest size base_type member",
},
{
.name = "nr_methods",
.key = 'm',
.doc = "show number of methods",
},
{
.name = "show_only_data_members",
.key = 'M',
.doc = "show only the members that use space in the class layout",
},
{
.name = "expand_pointers",
.key = 'p',
.doc = "expand class pointer members",
},
{
.name = "sizes",
.key = 's',
.doc = "show size of classes",
},
{
.name = "separator",
.key = 't',
.arg = "SEP",
.doc = "use SEP as the field separator",
},
{
.name = "nr_definitions",
.key = 'T',
.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",
},
{
.name = "prefix_filter",
.key = 'y',
.arg = "PREFIX",
.doc = "include PREFIXed classes",
},
{
.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",
},
{
.name = "quiet",
.key = 'q',
.doc = "be quieter",
},
{
.name = "defined_in",
.key = 'u',
.doc = "show CUs where CLASS_NAME (-C) is defined",
},
{
.name = "verbose",
.key = 'V',
.doc = "be verbose",
},
[PAHOLE]: Allow changing the architecture word-size Using a x86_64 binary: [acme@doppio pahole]$ build/pahole -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 8 */ union { struct { long unsigned int arg0; /* 8 8 */ long unsigned int arg1; /* 16 8 */ long unsigned int arg2; /* 24 8 */ long unsigned int arg3; /* 32 8 */ }; /* 32 */ struct { u32 * uaddr; /* 8 8 */ u32 val; /* 16 4 */ u32 flags; /* 20 4 */ u64 time; /* 24 8 */ } fu; /* 24 */ }; /* 8 32 */ /* size: 40, cachelines: 1 */ /* last cacheline: 40 bytes */ }; Changing the word-size from 8 to 4 bytes: [acme@doppio pahole]$ build/pahole -w 4 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 4 */ union { struct { long unsigned int arg0; /* 4 4 */ long unsigned int arg1; /* 8 4 */ long unsigned int arg2; /* 12 4 */ long unsigned int arg3; /* 16 4 */ }; /* 16 */ struct { u32 * uaddr; /* 4 4 */ u32 val; /* 8 4 */ u32 flags; /* 12 4 */ u64 time; /* 16 8 */ } fu; /* 20 */ }; /* 4 20 */ /* size: 24, cachelines: 1 */ /* last cacheline: 24 bytes */ }; And from 8 to 16: [acme@doppio pahole]$ build/pahole -w 16 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 16 */ union { struct { long unsigned int arg0; /* 16 16 */ long unsigned int arg1; /* 32 16 */ long unsigned int arg2; /* 48 16 */ long unsigned int arg3; /* 64 16 */ /* --- cacheline 1 boundary (64 bytes) --- */ }; /* 64 */ struct { u32 * uaddr; /* 16 16 */ u32 val; /* 32 4 */ u32 flags; /* 36 4 */ u64 time; /* 40 8 */ } fu; /* 32 */ }; /* 16 64 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ /* size: 80, cachelines: 2 */ /* last cacheline: 16 bytes */ }; More work is required to specify different alignment rules. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
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"
},
{
.name = "ctf_encode",
.key = 'Z',
.doc = "Encode as CTF",
},
{
.name = "flat_arrays",
.key = ARGP_flat_arrays,
.doc = "Flat arrays",
},
{
.name = "show_private_classes",
.key = ARGP_show_private_classes,
.doc = "Show classes that are defined inside other classes or in functions",
},
{
.name = "fixup_silly_bitfields",
.key = ARGP_fixup_silly_bitfields,
.doc = "Fix silly bitfields such as int foo:32",
},
{
.name = "first_obj_only",
.key = ARGP_first_obj_only,
.doc = "Only process the first object file in the binary",
},
{
.name = "classes_as_structs",
.key = ARGP_classes_as_structs,
.doc = "Use 'struct' when printing classes",
},
{
.name = "hex",
.key = ARGP_hex_fmt,
.doc = "Print offsets and sizes in hexadecimal",
},
{
.name = "btf_encode",
.key = 'J',
.doc = "Encode as BTF",
},
{
.name = NULL,
}
};
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)
{
switch (key) {
case ARGP_KEY_INIT:
if (state->child_inputs != NULL)
state->child_inputs[0] = state->input;
break;
case 'A': class__include_nested_anonymous = 1; break;
case 'a': class__include_anonymous = 1; break;
case 'B': nr_bit_holes = atoi(arg); break;
case 'C': class_name = arg; break;
case 'c': cacheline_size = atoi(arg); break;
case 'D': decl_exclude_prefix = arg;
decl_exclude_prefix_len = strlen(decl_exclude_prefix);
conf_load.extra_dbg_info = 1; break;
[PAHOLE]: Introduce --recursive For now only affects the --contains output. Example showing the structs that include struct list_head in a linux kernel module: [acme@filo pahole]$ pahole --recursive --contains list_head examples/ipv6.ko.debug.x86-64 inet_protosw proto sock_iocb key_type msg_queue msg_msg nf_hook_ops softnet_data net_device softnet_data dma_device dma_client dma_chan class_device net_device softnet_data dma_chan class klist_node device_driver device klist device_driver bus_type device file_system_type nfs_lock_info file_lock block_device address_space inode dquot mem_dqinfo super_block inode signal_struct page kioctx file kiocb work_struct delayed_work kioctx timer_list ifmcaddr6 inet6_dev inet6_ifaddr neigh_table neighbour net_device softnet_data sock inet_sock delayed_work kioctx plist_head task_struct sigpending signal_struct task_struct user_struct device dev_pm_info device mutex_waiter mutex seq_file block_device quota_info super_block dquot super_block inode zone per_cpu_pages free_area kset bus_type subsystem class bus_type __wait_queue_head __wait_queue rw_semaphore quota_info super_block super_block inode key blocking_notifier_head bus_type subsystem class bus_type mm_struct dentry vm_area_struct kobject class_device net_device softnet_data dma_chan device_driver module_kobject module device kset bus_type subsystem class bus_type lock_class module mm_struct task_struct Handling in multi-cu objects is not very precise, as the same struct has different dwarf offsets (id) in each CU. A mitigation for this problem will be provided with the --cu_list and --cu_name upcoming options, where one will be able to get a list of the object files in a, for instance, linux kernel .ko module and also to specify a cu name to be the only to be considered when processing multi-cu files (again, such as .ko linux kernel modules). This ends up being also useful to generate a reverse class hierarchy :-) Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-05-11 00:11:51 +02:00
case 'd': recursive = 1; break;
case 'E': conf.expand_types = 1; break;
case 'f': find_pointers_in_structs = 1;
class_name = arg; break;
case 'F': conf_load.format_path = arg; break;
case 'H': nr_holes = atoi(arg); break;
case 'I': conf.show_decl_info = 1;
conf_load.extra_dbg_info = 1; break;
case 'i': find_containers = 1;
class_name = arg; break;
btf: fix struct/union/fwd types with kind_flag This patch fixed two issues with BTF. One is related to struct/union bitfield encoding and the other is related to forward type. Issue #1 and solution: ====================== Current btf encoding of bitfield follows what pahole generates. For each bitfield, pahole will duplicate the type chain and put the bitfield size at the final int or enum type. Since the BTF enum type cannot encode bit size, commit b18354f64cc2 ("btf: Generate correct struct bitfield member types") workarounds the issue by generating an int type whenever the enum bit size is not 32. The above workaround is not ideal as we lost original type in BTF. Another undesiable fact is the type duplication as the pahole duplicates the type chain. To fix this issue, this patch implemented a compatible change for BTF struct type encoding: . the bit 31 of type->info, previously reserved, now is used to indicate whether bitfield_size is encoded in btf_member or not. . if bit 31 of struct_type->info is set, btf_member->offset will encode like: bit 0 - 23: bit offset bit 24 - 31: bitfield size if bit 31 is not set, the old behavior is preserved: bit 0 - 31: bit offset So if the struct contains a bit field, the maximum bit offset will be reduced to (2^24 - 1) instead of MAX_UINT. The maximum bitfield size will be 255 which is enough for today as maximum bitfield in compiler can be 128 where int128 type is supported. A new global, no_bitfield_type_recode, is introduced and which will be set to true if BTF encoding is enabled. This global will prevent pahole duplicating the bitfield types to avoid type duplication in BTF. Issue #2 and solution: ====================== Current forward type in BTF does not specify whether the original type is struct or union. This will not work for type pretty print and BTF-to-header-file conversion as struct/union must be specified. To fix this issue, similar to issue #1, type->info bit 31 is used. If the bit is set, it is union type. Otherwise, it is a struct type. Examples: ========= -bash-4.4$ cat t.c struct s; union u; typedef int ___int; enum A { A1, A2, A3 }; struct t { int a[5]; ___int b:4; volatile enum A c:4; struct s *p1; union u *p2; } g; -bash-4.4$ gcc -c -O2 -g t.c Without this patch: $ pahole -JV t.o [1] TYPEDEF ___int type_id=2 [2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED [3] ENUM A size=4 vlen=3 A1 val=0 A2 val=1 A3 val=2 [4] STRUCT t size=40 vlen=5 a type_id=5 bits_offset=0 b type_id=13 bits_offset=160 c type_id=15 bits_offset=164 p1 type_id=9 bits_offset=192 p2 type_id=11 bits_offset=256 [5] ARRAY (anon) type_id=2 index_type_id=2 nr_elems=5 [6] INT sizetype size=8 bit_offset=0 nr_bits=64 encoding=(none) [7] VOLATILE (anon) type_id=3 [8] FWD s type_id=0 [9] PTR (anon) type_id=8 [10] FWD u type_id=0 [11] PTR (anon) type_id=10 [12] INT int size=1 bit_offset=0 nr_bits=4 encoding=(none) [13] TYPEDEF ___int type_id=12 [14] INT (anon) size=1 bit_offset=0 nr_bits=4 encoding=SIGNED [15] VOLATILE (anon) type_id=14 With this patch: $ pahole -JV t.o File t.o: [1] TYPEDEF ___int type_id=2 [2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED [3] ENUM A size=4 vlen=3 A1 val=0 A2 val=1 A3 val=2 [4] STRUCT t kind_flag=1 size=40 vlen=5 a type_id=5 bitfield_size=0 bits_offset=0 b type_id=1 bitfield_size=4 bits_offset=160 c type_id=7 bitfield_size=4 bits_offset=164 p1 type_id=9 bitfield_size=0 bits_offset=192 p2 type_id=11 bitfield_size=0 bits_offset=256 [5] ARRAY (anon) type_id=2 index_type_id=2 nr_elems=5 [6] INT sizetype size=8 bit_offset=0 nr_bits=64 encoding=(none) [7] VOLATILE (anon) type_id=3 [8] FWD s struct [9] PTR (anon) type_id=8 [10] FWD u union [11] PTR (anon) type_id=10 The fix removed the type duplication, preserved the enum type for the bitfield, and have correct struct/union information for the forward type. Signed-off-by: Yonghong Song <yhs@fb.com> Acked-by: Martin KaFai Lau <kafai@fb.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Alexei Starovoitov <ast@fb.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-18 23:09:41 +01:00
case 'J': btf_encode = 1;
no_bitfield_type_recode = true; break;
case 'l': conf.show_first_biggest_size_base_type_member = 1; break;
case 'M': conf.show_only_data_members = 1; break;
case 'm': stats_formatter = nr_methods_formatter; break;
case 'N': formatter = class_name_len_formatter; break;
case 'n': formatter = nr_members_formatter; break;
case 'P': show_packable = 1;
conf_load.extra_dbg_info = 1; break;
case 'p': conf.expand_pointers = 1; break;
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;
case 'r': conf.rel_offset = 1; break;
case 'S': show_reorg_steps = 1; break;
case 's': formatter = size_formatter; break;
case 'T': stats_formatter = nr_definitions_formatter;
formatter = NULL; break;
case 't': separator = arg[0]; break;
case 'u': defined_in = 1; break;
case 'V': global_verbose = 1; break;
[PAHOLE]: Allow changing the architecture word-size Using a x86_64 binary: [acme@doppio pahole]$ build/pahole -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 8 */ union { struct { long unsigned int arg0; /* 8 8 */ long unsigned int arg1; /* 16 8 */ long unsigned int arg2; /* 24 8 */ long unsigned int arg3; /* 32 8 */ }; /* 32 */ struct { u32 * uaddr; /* 8 8 */ u32 val; /* 16 4 */ u32 flags; /* 20 4 */ u64 time; /* 24 8 */ } fu; /* 24 */ }; /* 8 32 */ /* size: 40, cachelines: 1 */ /* last cacheline: 40 bytes */ }; Changing the word-size from 8 to 4 bytes: [acme@doppio pahole]$ build/pahole -w 4 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 4 */ union { struct { long unsigned int arg0; /* 4 4 */ long unsigned int arg1; /* 8 4 */ long unsigned int arg2; /* 12 4 */ long unsigned int arg3; /* 16 4 */ }; /* 16 */ struct { u32 * uaddr; /* 4 4 */ u32 val; /* 8 4 */ u32 flags; /* 12 4 */ u64 time; /* 16 8 */ } fu; /* 20 */ }; /* 4 20 */ /* size: 24, cachelines: 1 */ /* last cacheline: 24 bytes */ }; And from 8 to 16: [acme@doppio pahole]$ build/pahole -w 16 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 16 */ union { struct { long unsigned int arg0; /* 16 16 */ long unsigned int arg1; /* 32 16 */ long unsigned int arg2; /* 48 16 */ long unsigned int arg3; /* 64 16 */ /* --- cacheline 1 boundary (64 bytes) --- */ }; /* 64 */ struct { u32 * uaddr; /* 16 16 */ u32 val; /* 32 4 */ u32 flags; /* 36 4 */ u64 time; /* 40 8 */ } fu; /* 32 */ }; /* 16 64 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ /* size: 80, cachelines: 2 */ /* last cacheline: 16 bytes */ }; More work is required to specify different alignment rules. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2008-01-12 16:14:40 +01:00
case 'w': word_size = atoi(arg); break;
case 'X': cu__exclude_prefix = arg;
cu__exclude_prefix_len = strlen(cu__exclude_prefix);
break;
case 'x': class__exclude_prefix = arg;
class__exclude_prefix_len = strlen(class__exclude_prefix);
break;
case 'y': class__include_prefix = arg;
class__include_prefix_len = strlen(class__include_prefix);
break;
case 'z':
hole_size_ge = atoi(arg);
if (!global_verbose)
formatter = class_name_formatter;
break;
case 'Z': ctf_encode = 1; break;
case ARGP_flat_arrays: conf.flat_arrays = 1; break;
case ARGP_show_private_classes:
show_private_classes = true;
conf.show_only_data_members = 1; break;
case ARGP_fixup_silly_bitfields:
conf_load.fixup_silly_bitfields = 1; break;
case ARGP_first_obj_only:
first_obj_only = true; break;
case ARGP_classes_as_structs:
conf.classes_as_structs = 1; break;
case ARGP_hex_fmt:
conf.hex_fmt = 1; break;
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
}
static const char pahole__args_doc[] = "FILE";
static struct argp pahole__argp = {
.options = pahole__options,
.parser = pahole__options_parser,
.args_doc = pahole__args_doc,
};
static void do_reorg(struct tag *class, struct cu *cu)
{
int savings;
const uint8_t reorg_verbose =
show_reorg_steps ? 2 : global_verbose;
struct class *clone = class__clone(tag__class(class), NULL, cu);
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));
printf(" /* saved %d byte%s", savings,
savings != 1 ? "s" : "");
if (cacheline_savings != 0)
printf(" and %zu cacheline%s",
cacheline_savings,
cacheline_savings != 1 ?
"s" : "");
puts("! */");
} else
putchar('\n');
/* FIXME: we need to free in the right order,
* cu->obstack is being corrupted...
class__delete(clone, cu);
*/
}
static enum load_steal_kind pahole_stealer(struct cu *cu,
struct conf_load *conf_load __unused)
{
int ret = LSK__DELETE;
if (!cu__filter(cu))
goto filter_it;
if (btf_encode) {
cu__encode_btf(cu, global_verbose);
btf: Allow multiple cu's in dwarf->btf conversion Currently, the pahole dwarf->btf conversion only supports one compilation unit. This is not ideal since we would like using pahole to generate BTF for vmlinux which has a lot of compilation units. This patch added support to process multiple compilation units per ELF file. Multiple ELF files are also supported properly. The following is a demonstration example: -bash-4.4$ cat t1.c struct t1 { int a1; } g1; int main(void) { return 0; } -bash-4.4$ cat t2.c struct t2 { char a2; } g2; int main() { return 0; } -bash-4.4$ cat t3.c struct t3 { unsigned char a1:4; } g1; int main(void) { return 0; } -bash-4.4$ cat t4.c struct t4 { volatile char a4; } g2; int main() { return 0; } -bash-4.4$ gcc -O2 -o t1 -g t1.c t2.c -bash-4.4$ gcc -O2 -o t3 -g t3.c t4.c Note that both the binary "t1" and "t3" have two compilation units in their respective dwarf debug_info sections. The following is the pahole verbose output for BTF conversion for these two binaries. -bash-4.4$ pahole -JV t1 t3 File t1: [1] STRUCT t1 size=4 vlen=1 a1 type_id=2 bits_offset=0 [2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED [3] STRUCT t2 size=1 vlen=1 a2 type_id=4 bits_offset=0 [4] INT char size=1 bit_offset=0 nr_bits=8 encoding=(none) [5] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED File t3: [1] STRUCT t3 size=1 vlen=1 a1 type_id=3 bits_offset=0 [2] INT unsigned char size=1 bit_offset=0 nr_bits=8 encoding=(none) [3] INT unsigned char size=1 bit_offset=0 nr_bits=4 encoding=(none) [4] INT (anon) size=4 bit_offset=0 nr_bits=32 encoding=(none) [5] STRUCT t4 size=1 vlen=1 a4 type_id=6 bits_offset=0 [6] VOLATILE (anon) type_id=7 [7] INT char size=1 bit_offset=0 nr_bits=8 encoding=(none) [8] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED Signed-off-by: Andrii Nakryiko <andriin@fb.com> Acked-by: Martin KaFai Lau <kafai@fb.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Alexei Starovoitov <ast@fb.com> Cc: Yonghong Song <yhs@fb.com> Signed-off-by: Yonghong Song <yhs@fb.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-18 23:09:39 +01:00
return LSK__KEEPIT;
}
if (ctf_encode) {
cu__encode_ctf(cu, global_verbose);
/*
* 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;
}
if (class_name == NULL) {
if (stats_formatter == nr_methods_formatter) {
cu__account_nr_methods(cu);
goto dump_it;
}
if (word_size != 0)
cu_fixup_word_size_iterator(cu);
memset(tab, ' ', sizeof(tab) - 1);
print_classes(cu);
goto dump_it;
}
[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 str_node *pos;
struct rb_node *next = rb_first(&class_names->entries);
[PAHOLE]: Allow changing the architecture word-size Using a x86_64 binary: [acme@doppio pahole]$ build/pahole -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 8 */ union { struct { long unsigned int arg0; /* 8 8 */ long unsigned int arg1; /* 16 8 */ long unsigned int arg2; /* 24 8 */ long unsigned int arg3; /* 32 8 */ }; /* 32 */ struct { u32 * uaddr; /* 8 8 */ u32 val; /* 16 4 */ u32 flags; /* 20 4 */ u64 time; /* 24 8 */ } fu; /* 24 */ }; /* 8 32 */ /* size: 40, cachelines: 1 */ /* last cacheline: 40 bytes */ }; Changing the word-size from 8 to 4 bytes: [acme@doppio pahole]$ build/pahole -w 4 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 4 */ union { struct { long unsigned int arg0; /* 4 4 */ long unsigned int arg1; /* 8 4 */ long unsigned int arg2; /* 12 4 */ long unsigned int arg3; /* 16 4 */ }; /* 16 */ struct { u32 * uaddr; /* 4 4 */ u32 val; /* 8 4 */ u32 flags; /* 12 4 */ u64 time; /* 16 8 */ } fu; /* 20 */ }; /* 4 20 */ /* size: 24, cachelines: 1 */ /* last cacheline: 24 bytes */ }; And from 8 to 16: [acme@doppio pahole]$ build/pahole -w 16 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 16 */ union { struct { long unsigned int arg0; /* 16 16 */ long unsigned int arg1; /* 32 16 */ long unsigned int arg2; /* 48 16 */ long unsigned int arg3; /* 64 16 */ /* --- cacheline 1 boundary (64 bytes) --- */ }; /* 64 */ struct { u32 * uaddr; /* 16 16 */ u32 val; /* 32 4 */ u32 flags; /* 36 4 */ u64 time; /* 40 8 */ } fu; /* 32 */ }; /* 16 64 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ /* size: 80, cachelines: 2 */ /* last cacheline: 16 bytes */ }; More work is required to specify different alignment rules. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2008-01-12 16:14:40 +01:00
while (next) {
pos = rb_entry(next, struct str_node, rb_node);
next = rb_next(&pos->rb_node);
[PAHOLE]: Introduce --recursive For now only affects the --contains output. Example showing the structs that include struct list_head in a linux kernel module: [acme@filo pahole]$ pahole --recursive --contains list_head examples/ipv6.ko.debug.x86-64 inet_protosw proto sock_iocb key_type msg_queue msg_msg nf_hook_ops softnet_data net_device softnet_data dma_device dma_client dma_chan class_device net_device softnet_data dma_chan class klist_node device_driver device klist device_driver bus_type device file_system_type nfs_lock_info file_lock block_device address_space inode dquot mem_dqinfo super_block inode signal_struct page kioctx file kiocb work_struct delayed_work kioctx timer_list ifmcaddr6 inet6_dev inet6_ifaddr neigh_table neighbour net_device softnet_data sock inet_sock delayed_work kioctx plist_head task_struct sigpending signal_struct task_struct user_struct device dev_pm_info device mutex_waiter mutex seq_file block_device quota_info super_block dquot super_block inode zone per_cpu_pages free_area kset bus_type subsystem class bus_type __wait_queue_head __wait_queue rw_semaphore quota_info super_block super_block inode key blocking_notifier_head bus_type subsystem class bus_type mm_struct dentry vm_area_struct kobject class_device net_device softnet_data dma_chan device_driver module_kobject module device kset bus_type subsystem class bus_type lock_class module mm_struct task_struct Handling in multi-cu objects is not very precise, as the same struct has different dwarf offsets (id) in each CU. A mitigation for this problem will be provided with the --cu_list and --cu_name upcoming options, where one will be able to get a list of the object files in a, for instance, linux kernel .ko module and also to specify a cu name to be the only to be considered when processing multi-cu files (again, such as .ko linux kernel modules). This ends up being also useful to generate a reverse class hierarchy :-) Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-05-11 00:11: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_or_union_by_name(cu, pos->s, include_decls, &class_id);
if (class == NULL)
continue;
if (defined_in) {
puts(cu->name);
goto dump_it;
}
/*
* Ok, found it, so remove from the list to avoid printing it
* twice, in another CU.
*/
strlist__remove(class_names, pos);
class__find_holes(tag__class(class));
if (reorganize) {
if (tag__is_struct(class))
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');
}
}
/*
* If we found all the entries in --class_name, stop
*/
if (strlist__empty(class_names)) {
dump_and_stop:
ret = LSK__STOP_LOADING;
}
dump_it:
if (first_obj_only)
ret = LSK__STOP_LOADING;
filter_it:
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;
}
int main(int argc, char *argv[])
{
int err, remaining, rc = EXIT_FAILURE;
if (argp_parse(&pahole__argp, argc, argv, 0, &remaining, NULL) ||
(remaining == argc && class_name == NULL)) {
argp_help(&pahole__argp, stderr, ARGP_HELP_SEE, argv[0]);
goto out;
}
class_names = strlist__new(true);
if (class_names == NULL || dwarves__init(cacheline_size)) {
fputs("pahole: insufficient memory\n", stderr);
goto out;
}
if (class_name && populate_class_names())
goto out_dwarves_exit;
struct cus *cus = cus__new();
if (cus == NULL) {
fputs("pahole: insufficient memory\n", stderr);
goto out_dwarves_exit;
}
conf_load.steal = pahole_stealer;
err = cus__load_files(cus, &conf_load, argv + remaining);
if (err != 0) {
cus__fprintf_load_files_err(cus, "pahole", argv + remaining, err, stderr);
goto out_cus_delete;
}
btf: Allow multiple cu's in dwarf->btf conversion Currently, the pahole dwarf->btf conversion only supports one compilation unit. This is not ideal since we would like using pahole to generate BTF for vmlinux which has a lot of compilation units. This patch added support to process multiple compilation units per ELF file. Multiple ELF files are also supported properly. The following is a demonstration example: -bash-4.4$ cat t1.c struct t1 { int a1; } g1; int main(void) { return 0; } -bash-4.4$ cat t2.c struct t2 { char a2; } g2; int main() { return 0; } -bash-4.4$ cat t3.c struct t3 { unsigned char a1:4; } g1; int main(void) { return 0; } -bash-4.4$ cat t4.c struct t4 { volatile char a4; } g2; int main() { return 0; } -bash-4.4$ gcc -O2 -o t1 -g t1.c t2.c -bash-4.4$ gcc -O2 -o t3 -g t3.c t4.c Note that both the binary "t1" and "t3" have two compilation units in their respective dwarf debug_info sections. The following is the pahole verbose output for BTF conversion for these two binaries. -bash-4.4$ pahole -JV t1 t3 File t1: [1] STRUCT t1 size=4 vlen=1 a1 type_id=2 bits_offset=0 [2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED [3] STRUCT t2 size=1 vlen=1 a2 type_id=4 bits_offset=0 [4] INT char size=1 bit_offset=0 nr_bits=8 encoding=(none) [5] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED File t3: [1] STRUCT t3 size=1 vlen=1 a1 type_id=3 bits_offset=0 [2] INT unsigned char size=1 bit_offset=0 nr_bits=8 encoding=(none) [3] INT unsigned char size=1 bit_offset=0 nr_bits=4 encoding=(none) [4] INT (anon) size=4 bit_offset=0 nr_bits=32 encoding=(none) [5] STRUCT t4 size=1 vlen=1 a4 type_id=6 bits_offset=0 [6] VOLATILE (anon) type_id=7 [7] INT char size=1 bit_offset=0 nr_bits=8 encoding=(none) [8] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED Signed-off-by: Andrii Nakryiko <andriin@fb.com> Acked-by: Martin KaFai Lau <kafai@fb.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Alexei Starovoitov <ast@fb.com> Cc: Yonghong Song <yhs@fb.com> Signed-off-by: Yonghong Song <yhs@fb.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-18 23:09:39 +01:00
if (btf_encode) {
err = btf_encoder__encode();
if (err) {
fputs("Failed to encode BTF\n", stderr);
goto out_cus_delete;
}
}
if (stats_formatter != NULL)
print_stats();
rc = EXIT_SUCCESS;
out_cus_delete:
#ifdef DEBUG_CHECK_LEAKS
cus__delete(cus);
structures__delete();
#endif
out_dwarves_exit:
#ifdef DEBUG_CHECK_LEAKS
dwarves__exit();
#endif
out:
#ifdef DEBUG_CHECK_LEAKS
strlist__delete(class_names);
#endif
return rc;
}