dwarves/dwarves.h

668 lines
19 KiB
C
Raw Normal View History

#ifndef _DWARVES_H_
#define _DWARVES_H_ 1
/*
Copyright (C) 2006 Mandriva Conectiva S.A.
Copyright (C) 2006 Arnaldo Carvalho de Melo <acme@mandriva.com>
This program is free software; you can redistribute it and/or modify it
under the terms of version 2 of the GNU General Public License as
published by the Free Software Foundation.
*/
#include <stdint.h>
#include <stdio.h>
#include <dwarf.h>
#include <elfutils/libdw.h>
#include "list.h"
#include "hash.h"
struct argp;
struct cus {
struct list_head cus;
struct list_head priv_definitions; /* struct type entries */
struct list_head priv_fwd_decls; /* struct class entries */
struct list_head *definitions;
struct list_head *fwd_decls;
};
#define HASHTAGS__BITS 8
#define HASHTAGS__SIZE (1UL << HASHTAGS__BITS)
#define hashtags__fn(key) hash_64(key, HASHTAGS__BITS)
struct tag;
void hashtags__hash(struct list_head *hashtable, struct tag *tag);
struct cu {
struct list_head node;
struct list_head tags;
struct list_head hash_tags[HASHTAGS__SIZE];
struct list_head tool_list; /* To be used by tools such as ctracer */
const char *name;
uint8_t addr_size;
uint16_t language;
unsigned long nr_inline_expansions;
size_t size_inline_expansions;
uint32_t nr_functions_changed;
uint32_t nr_structures_changed;
size_t max_len_changed_item;
size_t function_bytes_added;
size_t function_bytes_removed;
int build_id_len;
unsigned char build_id[0];
};
struct tag {
struct list_head node;
struct list_head hash_node;
Dwarf_Off type;
Dwarf_Off id;
const char *decl_file;
[LIB]: Reorganize struct tag Erm, eating my dog food now that I have access to a 64bit machine here at home: [acme@mica pahole]$ pahole build/libdwarves.so.1.0.0 tag /* <b7e> /home/acme/git/pahole/dwarves.h:48 */ struct tag { struct list_head node; /* 0 16 */ Dwarf_Off type; /* 16 8 */ Dwarf_Off id; /* 24 8 */ uint16_t tag; /* 32 2 */ uint16_t decl_line; /* 34 2 */ /* XXX 4 bytes hole, try to pack */ const char * decl_file; /* 40 8 */ uint32_t refcnt; /* 48 4 */ }; /* size: 56, cachelines: 1 */ /* sum members: 48, holes: 1, sum holes: 4 */ /* padding: 4 */ /* last cacheline: 56 bytes */ [acme@mica pahole]$ [acme@mica pahole]$ pahole --reorganize build/libdwarves.so.1.0.0 tag /* <b7e> /home/acme/git/pahole/dwarves.h:48 */ struct tag { struct list_head node; /* 0 16 */ Dwarf_Off type; /* 16 8 */ Dwarf_Off id; /* 24 8 */ uint16_t tag; /* 32 2 */ uint16_t decl_line; /* 34 2 */ uint32_t refcnt; /* 36 4 */ const char * decl_file; /* 40 8 */ }; /* size: 48, cachelines: 1 */ /* last cacheline: 48 bytes */ /* saved 8 bytes! */ [acme@mica pahole]$ [acme@mica pahole]$ codiff build/libdwarves.so.1.0.0.before build/libdwarves.so.1.0.0 /home/acme/git/pahole/dwarves.c: struct tag | -8 struct type | -8 struct class | -8 struct base_type | -8 struct array_type | -8 struct class_member | -8 struct lexblock | -8 struct ftype | -8 struct function | -16 struct parameter | -8 struct variable | -8 struct inline_expansion | -8 struct label | -8 struct enumerator | -8 14 structs changed class_member__clone | -8 class__clone | -8 2 functions changed, 16 bytes removed [acme@mica pahole]$ Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-03-07 16:10:56 +01:00
uint16_t decl_line;
uint16_t tag;
uint16_t refcnt;
uint16_t recursivity_level;
};
static inline int tag__is_enumeration(const struct tag *self)
{
return self->tag == DW_TAG_enumeration_type;
}
static inline int tag__is_namespace(const struct tag *self)
{
return self->tag == DW_TAG_namespace;
}
static inline int tag__is_struct(const struct tag *self)
{
return self->tag == DW_TAG_structure_type ||
self->tag == DW_TAG_class_type;
}
static inline int tag__is_typedef(const struct tag *self)
{
return self->tag == DW_TAG_typedef;
}
static inline int tag__is_union(const struct tag *self)
{
return self->tag == DW_TAG_union_type;
}
static inline int tag__is_type(const struct tag *self)
{
return tag__is_union(self) ||
tag__is_struct(self) ||
tag__is_typedef(self) ||
tag__is_enumeration(self);
}
struct ptr_to_member_type {
struct tag tag;
Dwarf_Off containing_type;
};
static inline struct ptr_to_member_type *
tag__ptr_to_member_type(const struct tag *self)
{
return (struct ptr_to_member_type *)self;
}
struct namespace {
struct tag tag;
const char *name;
struct list_head tags;
uint16_t nr_tags;
};
static inline struct namespace *tag__namespace(const struct tag *self)
{
return (struct namespace *)self;
}
/**
* namespace__for_each_tag - iterate thru all the tags
* @self: struct namespace instance to iterate
* @pos: struct tag iterator
*/
#define namespace__for_each_tag(self, pos) \
list_for_each_entry(pos, &(self)->tags, node)
/**
* namespace__for_each_tag_safe - safely iterate thru all the tags
* @self: struct namespace instance to iterate
* @pos: struct tag iterator
* @n: struct class_member temp iterator
*/
#define namespace__for_each_tag_safe(self, pos, n) \
list_for_each_entry_safe(pos, n, &(self)->tags, node)
/**
* struct type - base type for enumerations, structs and unions
*
* @nr_members: number of DW_TAG_member entries
* @nr_tags: number of tags
*/
struct type {
struct namespace namespace;
struct list_head node;
Dwarf_Off specification;
size_t 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
size_t size_diff;
uint16_t nr_members;
uint8_t declaration; /* only one bit used */
uint8_t definition_emitted:1;
uint8_t fwd_decl_emitted:1;
uint8_t resized:1;
};
static inline struct class *type__class(const struct type *self)
{
return (struct class *)self;
}
/**
* type__for_each_tag - iterate thru all the tags
* @self: struct type instance to iterate
* @pos: struct tag iterator
*/
#define type__for_each_tag(self, pos) \
list_for_each_entry(pos, &(self)->namespace.tags, node)
/**
* type__for_each_enumerator - iterate thru the enumerator entries
* @self: struct type instance to iterate
* @pos: struct enumerator iterator
*/
#define type__for_each_enumerator(self, pos) \
list_for_each_entry(pos, &(self)->namespace.tags, tag.node)
/**
* type__for_each_member - iterate thru the entries that use space
* (data members and inheritance entries)
* @self: struct type instance to iterate
* @pos: struct class_member iterator
*/
#define type__for_each_member(self, pos) \
list_for_each_entry(pos, &(self)->namespace.tags, tag.node) \
if (!(pos->tag.tag == DW_TAG_member || \
pos->tag.tag == DW_TAG_inheritance)) \
continue; \
else
/**
* type__for_each_data_member - iterate thru the data member entries
* @self: struct type instance to iterate
* @pos: struct class_member iterator
*/
#define type__for_each_data_member(self, pos) \
list_for_each_entry(pos, &(self)->namespace.tags, tag.node) \
if (pos->tag.tag != DW_TAG_member) \
continue; \
else
/**
* type__for_each_member_safe - safely iterate thru the entries that use space
* (data members and inheritance entries)
* @self: struct type instance to iterate
* @pos: struct class_member iterator
* @n: struct class_member temp iterator
*/
#define type__for_each_member_safe(self, pos, n) \
list_for_each_entry_safe(pos, n, &(self)->namespace.tags, tag.node) \
if (pos->tag.tag != DW_TAG_member) \
continue; \
else
/**
* type__for_each_data_member_safe - safely iterate thru the data member entries
* @self: struct type instance to iterate
* @pos: struct class_member iterator
* @n: struct class_member temp iterator
*/
#define type__for_each_data_member_safe(self, pos, n) \
list_for_each_entry_safe(pos, n, &(self)->namespace.tags, tag.node) \
if (pos->tag.tag != DW_TAG_member) \
continue; \
else
static inline struct type *tag__type(const struct tag *self)
{
return (struct type *)self;
}
struct class {
struct type type;
struct list_head vtable;
uint16_t nr_vtable_entries;
uint8_t nr_holes;
uint8_t nr_bit_holes;
uint16_t padding;
uint8_t bit_padding;
void *priv;
};
static inline struct class *tag__class(const struct tag *self)
{
return (struct class *)self;
}
static inline struct tag *class__tag(const struct class *self)
{
return (struct tag *)self;
}
extern struct class *class__clone(const struct class *from,
const char *new_class_name);
extern void class__delete(struct class *self);
static inline struct list_head *class__tags(struct class *self)
{
return &self->type.namespace.tags;
}
extern const char *type__name(struct type *self, const struct cu *cu);
static inline const char *class__name(struct class *self,
const struct cu *cu)
{
return type__name(&self->type, cu);
}
static inline int class__is_struct(const struct class *self)
{
return tag__is_struct(&self->type.namespace.tag);
}
struct base_type {
struct tag tag;
const char *name;
size_t bit_size;
};
static inline struct base_type *tag__base_type(const struct tag *self)
{
return (struct base_type *)self;
}
static inline size_t base_type__size(const struct tag *self)
{
return tag__base_type(self)->bit_size / 8;
}
struct array_type {
struct tag tag;
uint32_t *nr_entries;
uint8_t dimensions;
};
static inline struct array_type *tag__array_type(const struct tag *self)
{
return (struct array_type *)self;
}
struct class_member {
struct tag tag;
char *name;
uint32_t offset;
uint8_t bit_offset;
uint8_t bit_size;
uint8_t bit_hole; /* If there is a bit hole before the next
one (or the end of the struct) */
uint8_t bitfield_end:1; /* Is this the last entry in a bitfield? */
uint8_t visited:1;
uint8_t accessibility:2; /* DW_ACCESS_{public,protected,private} */
uint8_t virtuality:2; /* DW_VIRTUALITY_{none,virtual,pure_virtual} */
uint16_t hole; /* If there is a hole before the next
[CLASSES]: Find bit holes An example is worth a thousand words, look for "XXX ... bit hole, try to pack" and the stats at the bottom: [acme@newtoy net-2.6]$ pahole ../OUTPUT/qemu/net-2.6/fs/inode.o task_struct /* include2/asm/system.h:11 */ struct task_struct { volatile long int state; /* 0 4 */ struct thread_info * thread_info; /* 4 4 */ atomic_t usage; /* 8 4 */ long unsigned int flags; /* 12 4 */ long unsigned int ptrace; /* 16 4 */ int lock_depth; /* 20 4 */ int load_weight; /* 24 4 */ int prio; /* 28 4 */ /* --- cacheline 1 boundary (32 bytes) --- */ int static_prio; /* 32 4 */ int normal_prio; /* 36 4 */ struct list_head run_list; /* 40 8 */ struct prio_array * array; /* 48 4 */ short unsigned int ioprio; /* 52 2 */ /* XXX 2 bytes hole, try to pack */ long unsigned int sleep_avg; /* 56 4 */ long long unsigned int timestamp; /* 60 8 */ /* --- cacheline 2 boundary (64 bytes) was 4 bytes ago --- */ long long unsigned int last_ran; /* 68 8 */ long long unsigned int sched_time; /* 76 8 */ enum sleep_type sleep_type; /* 84 4 */ long unsigned int policy; /* 88 4 */ cpumask_t cpus_allowed; /* 92 4 */ /* --- cacheline 3 boundary (96 bytes) --- */ unsigned int time_slice; /* 96 4 */ unsigned int first_time_slice; /* 100 4 */ struct list_head tasks; /* 104 8 */ struct list_head ptrace_children; /* 112 8 */ struct list_head ptrace_list; /* 120 8 */ /* --- cacheline 4 boundary (128 bytes) --- */ struct mm_struct * mm; /* 128 4 */ struct mm_struct * active_mm; /* 132 4 */ struct linux_binfmt * binfmt; /* 136 4 */ long int exit_state; /* 140 4 */ int exit_code; /* 144 4 */ int exit_signal; /* 148 4 */ int pdeath_signal; /* 152 4 */ long unsigned int personality; /* 156 4 */ /* --- cacheline 5 boundary (160 bytes) --- */ unsigned int did_exec:1; /* 160 4 */ /* XXX 31 bits hole, try to pack */ pid_t pid; /* 164 4 */ pid_t tgid; /* 168 4 */ struct task_struct * real_parent; /* 172 4 */ struct task_struct * parent; /* 176 4 */ struct list_head children; /* 180 8 */ struct list_head sibling; /* 188 8 */ /* --- cacheline 6 boundary (192 bytes) was 4 bytes ago --- */ struct task_struct * group_leader; /* 196 4 */ struct pid_link pids[3]; /* 200 36 */ /* --- cacheline 7 boundary (224 bytes) was 12 bytes ago --- */ struct list_head thread_group; /* 236 8 */ struct completion * vfork_done; /* 244 4 */ int * set_child_tid; /* 248 4 */ int * clear_child_tid; /* 252 4 */ /* --- cacheline 8 boundary (256 bytes) --- */ long unsigned int rt_priority; /* 256 4 */ cputime_t utime; /* 260 4 */ cputime_t stime; /* 264 4 */ long unsigned int nvcsw; /* 268 4 */ long unsigned int nivcsw; /* 272 4 */ struct timespec start_time; /* 276 8 */ long unsigned int min_flt; /* 284 4 */ /* --- cacheline 9 boundary (288 bytes) --- */ long unsigned int maj_flt; /* 288 4 */ cputime_t it_prof_expires; /* 292 4 */ cputime_t it_virt_expires; /* 296 4 */ long long unsigned int it_sched_expires; /* 300 8 */ struct list_head cpu_timers[3]; /* 308 24 */ /* --- cacheline 10 boundary (320 bytes) was 12 bytes ago --- */ uid_t uid; /* 332 4 */ uid_t euid; /* 336 4 */ uid_t suid; /* 340 4 */ uid_t fsuid; /* 344 4 */ gid_t gid; /* 348 4 */ /* --- cacheline 11 boundary (352 bytes) --- */ gid_t egid; /* 352 4 */ gid_t sgid; /* 356 4 */ gid_t fsgid; /* 360 4 */ struct group_info * group_info; /* 364 4 */ kernel_cap_t cap_effective; /* 368 4 */ kernel_cap_t cap_inheritable; /* 372 4 */ kernel_cap_t cap_permitted; /* 376 4 */ unsigned int keep_capabilities:1; /* 380 4 */ /* XXX 31 bits hole, try to pack */ /* --- cacheline 12 boundary (384 bytes) --- */ struct user_struct * user; /* 384 4 */ struct key * request_key_auth; /* 388 4 */ struct key * thread_keyring; /* 392 4 */ unsigned char jit_keyring; /* 396 1 */ unsigned char fpu_counter; /* 397 1 */ /* XXX 2 bytes hole, try to pack */ int oomkilladj; /* 400 4 */ char comm[16]; /* 404 16 */ /* --- cacheline 13 boundary (416 bytes) was 4 bytes ago --- */ int link_count; /* 420 4 */ int total_link_count; /* 424 4 */ struct sysv_sem sysvsem; /* 428 4 */ struct thread_struct thread; /* 432 656 */ /* --- cacheline 34 boundary (1088 bytes) --- */ struct fs_struct * fs; /* 1088 4 */ struct files_struct * files; /* 1092 4 */ struct nsproxy * nsproxy; /* 1096 4 */ struct signal_struct * signal; /* 1100 4 */ struct sighand_struct * sighand; /* 1104 4 */ sigset_t blocked; /* 1108 8 */ sigset_t real_blocked; /* 1116 8 */ /* --- cacheline 35 boundary (1120 bytes) was 4 bytes ago --- */ sigset_t saved_sigmask; /* 1124 8 */ struct sigpending pending; /* 1132 16 */ long unsigned int sas_ss_sp; /* 1148 4 */ /* --- cacheline 36 boundary (1152 bytes) --- */ size_t sas_ss_size; /* 1152 4 */ int (*notifier)(); /* 1156 4 */ void * notifier_data; /* 1160 4 */ sigset_t * notifier_mask; /* 1164 4 */ void * security; /* 1168 4 */ struct audit_context * audit_context; /* 1172 4 */ seccomp_t seccomp; /* 1176 0 */ u32 parent_exec_id; /* 1176 4 */ u32 self_exec_id; /* 1180 4 */ /* --- cacheline 37 boundary (1184 bytes) --- */ spinlock_t alloc_lock; /* 1184 40 */ /* --- cacheline 38 boundary (1216 bytes) was 8 bytes ago --- */ spinlock_t pi_lock; /* 1224 40 */ /* --- cacheline 39 boundary (1248 bytes) was 16 bytes ago --- */ struct plist_head pi_waiters; /* 1264 20 */ /* --- cacheline 40 boundary (1280 bytes) was 4 bytes ago --- */ struct rt_mutex_waiter * pi_blocked_on; /* 1284 4 */ struct mutex_waiter * blocked_on; /* 1288 4 */ unsigned int irq_events; /* 1292 4 */ int hardirqs_enabled; /* 1296 4 */ long unsigned int hardirq_enable_ip; /* 1300 4 */ unsigned int hardirq_enable_event; /* 1304 4 */ long unsigned int hardirq_disable_ip; /* 1308 4 */ /* --- cacheline 41 boundary (1312 bytes) --- */ unsigned int hardirq_disable_event; /* 1312 4 */ int softirqs_enabled; /* 1316 4 */ long unsigned int softirq_disable_ip; /* 1320 4 */ unsigned int softirq_disable_event; /* 1324 4 */ long unsigned int softirq_enable_ip; /* 1328 4 */ unsigned int softirq_enable_event; /* 1332 4 */ int hardirq_context; /* 1336 4 */ int softirq_context; /* 1340 4 */ /* --- cacheline 42 boundary (1344 bytes) --- */ u64 curr_chain_key; /* 1344 8 */ int lockdep_depth; /* 1352 4 */ struct held_lock held_locks[30]; /* 1356 1200 */ /* --- cacheline 79 boundary (2528 bytes) was 28 bytes ago --- */ unsigned int lockdep_recursion; /* 2556 4 */ /* --- cacheline 80 boundary (2560 bytes) --- */ void * journal_info; /* 2560 4 */ struct reclaim_state * reclaim_state; /* 2564 4 */ struct backing_dev_info * backing_dev_info; /* 2568 4 */ struct io_context * io_context; /* 2572 4 */ long unsigned int ptrace_message; /* 2576 4 */ siginfo_t * last_siginfo; /* 2580 4 */ wait_queue_t * io_wait; /* 2584 4 */ u64 rchar; /* 2588 8 */ /* --- cacheline 81 boundary (2592 bytes) was 4 bytes ago --- */ u64 wchar; /* 2596 8 */ u64 syscr; /* 2604 8 */ u64 syscw; /* 2612 8 */ struct robust_list_head * robust_list; /* 2620 4 */ /* --- cacheline 82 boundary (2624 bytes) --- */ struct list_head pi_state_list; /* 2624 8 */ struct futex_pi_state * pi_state_cache; /* 2632 4 */ atomic_t fs_excl; /* 2636 4 */ struct rcu_head rcu; /* 2640 8 */ struct pipe_inode_info * splice_pipe; /* 2648 4 */ }; /* size: 2656, cachelines: 83 */ /* sum members: 2648, holes: 2, sum holes: 4 */ /* bit holes: 2, sum bit holes: 62 bits */ /* padding: 4 */ Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-07 15:26:50 +01:00
one (or the end of the struct) */
};
static inline struct class_member *tag__class_member(const struct tag *self)
{
return (struct class_member *)self;
}
extern size_t class_member__size(const struct class_member *self,
const struct cu *cu);
extern void class_member__delete(struct class_member *self);
struct lexblock {
struct tag tag;
struct list_head tags;
Dwarf_Addr low_pc;
Dwarf_Addr high_pc;
uint16_t nr_inline_expansions;
uint16_t nr_labels;
uint16_t nr_variables;
uint16_t nr_lexblocks;
size_t size_inline_expansions;
};
static inline struct lexblock *tag__lexblock(const struct tag *self)
{
return (struct lexblock *)self;
}
/*
* tag.tag can be DW_TAG_subprogram_type or DW_TAG_subroutine_type.
*/
struct ftype {
struct tag tag;
struct list_head parms;
uint16_t nr_parms;
uint8_t unspec_parms; /* just one bit is needed */
};
static inline struct ftype *tag__ftype(const struct tag *self)
{
return (struct ftype *)self;
}
/**
* ftype__for_each_parameter - iterate thru all the parameters
* @self: struct ftype instance to iterate
* @pos: struct parameter iterator
*/
#define ftype__for_each_parameter(self, pos) \
list_for_each_entry(pos, &(self)->parms, tag.node)
struct function {
struct ftype proto;
struct lexblock lexblock;
const char *name;
char *linkage_name;
Dwarf_Off abstract_origin;
Dwarf_Off specification;
size_t cu_total_size_inline_expansions;
uint16_t cu_total_nr_inline_expansions;
uint8_t inlined:2;
uint8_t external:1;
uint8_t accessibility:2; /* DW_ACCESS_{public,protected,private} */
uint8_t virtuality:2; /* DW_VIRTUALITY_{none,virtual,pure_virtual} */
int16_t vtable_entry;
struct list_head vtable_node;
/* fields used by tools */
struct list_head tool_node;
void *priv;
};
static inline struct function *tag__function(const struct tag *self)
{
return (struct function *)self;
}
static inline struct tag *function__tag(const struct function *self)
{
return (struct tag *)self;
}
/**
* function__for_each_parameter - iterate thru all the parameters
* @self: struct function instance to iterate
* @pos: struct parameter iterator
*/
#define function__for_each_parameter(self, pos) \
ftype__for_each_parameter(&self->proto, pos)
struct parameter {
struct tag tag;
char *name;
Dwarf_Off abstract_origin;
};
static inline struct parameter *tag__parameter(const struct tag *self)
{
return (struct parameter *)self;
}
extern Dwarf_Off parameter__type(struct parameter *self, const struct cu *cu);
extern const char *parameter__name(struct parameter *self, const struct cu *cu);
enum vlocation {
LOCATION_UNKNOWN,
LOCATION_LOCAL,
LOCATION_GLOBAL,
LOCATION_REGISTER,
LOCATION_OPTIMIZED
};
struct variable {
struct tag tag;
char *name;
Dwarf_Off abstract_origin;
uint8_t external:1;
uint8_t declaration:1;
enum vlocation location;
};
static inline struct variable *tag__variable(const struct tag *self)
{
return (struct variable *)self;
}
[CLASSES]: Add support for DW_TAG_inlined_subroutine Output of pfunct using this information (all for a make allyesconfig build): Top 5 functions by size of inlined functions in net/ipv4: [acme@newtoy guinea_pig-2.6]$ pfunct -I net/ipv4/built-in.o | sort -k3 -nr | head -5 ip_route_input: 19 7086 tcp_ack: 33 6415 do_ip_vs_set_ctl: 23 4193 q931_help: 8 3822 ip_defrag: 19 3318 [acme@newtoy guinea_pig-2.6]$ And by number of inline expansions: [acme@newtoy guinea_pig-2.6]$ pfunct -I net/ipv4/built-in.o | sort -k2 -nr | head -5 dump_packet: 35 905 tcp_v4_rcv: 34 1773 tcp_recvmsg: 34 928 tcp_ack: 33 6415 tcp_rcv_established: 31 1195 [acme@newtoy guinea_pig-2.6]$ And the list of expansions on a specific function: [acme@newtoy guinea_pig-2.6]$ pfunct -i net/ipv4/built-in.o tcp_v4_rcv /* net/ipv4/tcp_ipv4.c:1054 */ int tcp_v4_rcv(struct sk_buff * skb); /* size: 2189, variables: 8, goto labels: 6, inline expansions: 34 (1773 bytes) */ /* inline expansions in tcp_v4_rcv: current_thread_info: 8 pskb_may_pull: 36 pskb_may_pull: 29 tcp_v4_checksum_init: 139 __fswab32: 2 __fswab32: 2 inet_iif: 12 __inet_lookup: 292 __fswab16: 20 inet_ehashfn: 25 inet_ehash_bucket: 18 prefetch: 4 prefetch: 4 prefetch: 4 sock_hold: 4 xfrm4_policy_check: 59 nf_reset: 66 sk_filter: 135 __skb_trim: 20 get_softnet_dma: 68 tcp_prequeue: 257 sk_add_backlog: 40 sock_put: 27 xfrm4_policy_check: 46 tcp_checksum_complete: 29 current_thread_info: 8 sock_put: 20 xfrm4_policy_check: 50 tcp_checksum_complete: 29 current_thread_info: 8 inet_iif: 9 inet_lookup_listener: 36 inet_twsk_put: 114 tcp_v4_timewait_ack: 153 */ [acme@newtoy guinea_pig-2.6]$ Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-03 16:41:19 +01:00
struct inline_expansion {
struct tag tag;
size_t size;
Dwarf_Addr low_pc;
Dwarf_Addr high_pc;
[CLASSES]: Add support for DW_TAG_inlined_subroutine Output of pfunct using this information (all for a make allyesconfig build): Top 5 functions by size of inlined functions in net/ipv4: [acme@newtoy guinea_pig-2.6]$ pfunct -I net/ipv4/built-in.o | sort -k3 -nr | head -5 ip_route_input: 19 7086 tcp_ack: 33 6415 do_ip_vs_set_ctl: 23 4193 q931_help: 8 3822 ip_defrag: 19 3318 [acme@newtoy guinea_pig-2.6]$ And by number of inline expansions: [acme@newtoy guinea_pig-2.6]$ pfunct -I net/ipv4/built-in.o | sort -k2 -nr | head -5 dump_packet: 35 905 tcp_v4_rcv: 34 1773 tcp_recvmsg: 34 928 tcp_ack: 33 6415 tcp_rcv_established: 31 1195 [acme@newtoy guinea_pig-2.6]$ And the list of expansions on a specific function: [acme@newtoy guinea_pig-2.6]$ pfunct -i net/ipv4/built-in.o tcp_v4_rcv /* net/ipv4/tcp_ipv4.c:1054 */ int tcp_v4_rcv(struct sk_buff * skb); /* size: 2189, variables: 8, goto labels: 6, inline expansions: 34 (1773 bytes) */ /* inline expansions in tcp_v4_rcv: current_thread_info: 8 pskb_may_pull: 36 pskb_may_pull: 29 tcp_v4_checksum_init: 139 __fswab32: 2 __fswab32: 2 inet_iif: 12 __inet_lookup: 292 __fswab16: 20 inet_ehashfn: 25 inet_ehash_bucket: 18 prefetch: 4 prefetch: 4 prefetch: 4 sock_hold: 4 xfrm4_policy_check: 59 nf_reset: 66 sk_filter: 135 __skb_trim: 20 get_softnet_dma: 68 tcp_prequeue: 257 sk_add_backlog: 40 sock_put: 27 xfrm4_policy_check: 46 tcp_checksum_complete: 29 current_thread_info: 8 sock_put: 20 xfrm4_policy_check: 50 tcp_checksum_complete: 29 current_thread_info: 8 inet_iif: 9 inet_lookup_listener: 36 inet_twsk_put: 114 tcp_v4_timewait_ack: 153 */ [acme@newtoy guinea_pig-2.6]$ Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-03 16:41:19 +01:00
};
static inline struct inline_expansion *
tag__inline_expansion(const struct tag *self)
{
return (struct inline_expansion *)self;
}
struct label {
struct tag tag;
char *name;
Dwarf_Addr low_pc;
};
struct enumerator {
struct tag tag;
const char *name;
uint32_t value;
};
struct conf_fprintf {
const char *prefix;
const char *suffix;
int32_t type_spacing;
int32_t name_spacing;
uint32_t base_offset;
uint8_t indent;
uint8_t expand_types:1;
uint8_t expand_pointers:1;
uint8_t rel_offset:1;
uint8_t emit_stats:1;
uint8_t suppress_comments:1;
uint8_t suppress_offset_comment:1;
uint8_t show_decl_info:1;
uint8_t show_only_data_members:1;
uint8_t no_semicolon:1;
uint8_t show_first_biggest_size_base_type_member:1;
};
extern void dwarves__init(size_t user_cacheline_size);
[PAHOLE]: Print cacheline boundaries Cacheline size defaults to 32, sample output changing the default to 64 bytes: pahole --cacheline=64 ../../acme/OUTPUT/qemu/net-2.6/net/ipv4/tcp.o inode /* /pub/scm/linux/kernel/git/acme/net-2.6/include/linux/dcache.h:86 */ struct inode { struct hlist_node i_hash; /* 0 8 */ struct list_head i_list; /* 8 8 */ struct list_head i_sb_list; /* 16 8 */ struct list_head i_dentry; /* 24 8 */ long unsigned int i_ino; /* 32 4 */ atomic_t i_count; /* 36 4 */ umode_t i_mode; /* 40 2 */ /* XXX 2 bytes hole, try to pack */ unsigned int i_nlink; /* 44 4 */ uid_t i_uid; /* 48 4 */ gid_t i_gid; /* 52 4 */ dev_t i_rdev; /* 56 4 */ loff_t i_size; /* 60 8 */ struct timespec i_atime; /* 68 8 */ struct timespec i_mtime; /* 76 8 */ struct timespec i_ctime; /* 84 8 */ unsigned int i_blkbits; /* 92 4 */ long unsigned int i_version; /* 96 4 */ blkcnt_t i_blocks; /* 100 4 */ short unsigned int i_bytes; /* 104 2 */ spinlock_t i_lock; /* 106 0 */ /* XXX 2 bytes hole, try to pack */ struct mutex i_mutex; /* 108 24 */ /* ---------- cacheline 2 boundary ---------- */ struct rw_semaphore i_alloc_sem; /* 132 12 */ struct inode_operations * i_op; /* 144 4 */ const struct file_operations * i_fop; /* 148 4 */ struct super_block * i_sb; /* 152 4 */ struct file_lock * i_flock; /* 156 4 */ struct address_space * i_mapping; /* 160 4 */ struct address_space i_data; /* 164 72 */ struct list_head i_devices; /* 236 8 */ union ; /* 244 4 */ int i_cindex; /* 248 4 */ __u32 i_generation; /* 252 4 */ long unsigned int i_dnotify_mask; /* 256 4 */ /* ---------- cacheline 4 boundary ---------- */ struct dnotify_struct * i_dnotify; /* 260 4 */ struct list_head inotify_watches; /* 264 8 */ struct mutex inotify_mutex; /* 272 24 */ long unsigned int i_state; /* 296 4 */ long unsigned int dirtied_when; /* 300 4 */ unsigned int i_flags; /* 304 4 */ atomic_t i_writecount; /* 308 4 */ void * i_private; /* 312 4 */ }; /* size: 316, sum members: 312, holes: 2, sum holes: 4 */ Has to be improved to show the other cacheline boundaries, that may be buried into a included struct or union. Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 18:34:54 +01:00
extern void class__find_holes(struct class *self, const struct cu *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
extern int class__has_hole_ge(const struct class *self, const uint16_t size);
extern size_t class__fprintf(struct class *self, const struct cu *cu,
const struct conf_fprintf *conf, FILE *fp);
void enumeration__add(struct type *self, struct enumerator *enumerator);
extern size_t enumeration__fprintf(const struct tag *tag_self,
const struct cu *cu,
const struct conf_fprintf *conf, FILE *fp);
extern size_t typedef__fprintf(const struct tag *tag_self, const struct cu *cu,
const struct conf_fprintf *conf, FILE *fp);
extern size_t tag__fprintf_decl_info(const struct tag *self, FILE *fp);
extern size_t tag__fprintf(struct tag *self, const struct cu *cu,
const struct conf_fprintf *conf, FILE *fp);
extern const char *function__name(struct function *self, const struct cu *cu);
extern size_t function__fprintf_stats(const struct tag *tag_self,
const struct cu *cu,
FILE *fp);
extern const char *function__prototype(const struct function *self,
const struct cu *cu,
char *bf, size_t len);
void lexblock__add_inline_expansion(struct lexblock *self,
struct inline_expansion *exp);
void lexblock__add_label(struct lexblock *self, struct label *label);
void lexblock__add_lexblock(struct lexblock *self, struct lexblock *child);
void lexblock__add_tag(struct lexblock *self, struct tag *tag);
void lexblock__add_variable(struct lexblock *self, struct variable *var);
extern size_t lexblock__fprintf(const struct lexblock *self,
const struct cu *cu, struct function *function,
uint16_t indent, FILE *fp);
extern struct cus *cus__new(struct list_head *definitions,
struct list_head *fwd_decls);
extern int cus__loadfl(struct cus *self, struct argp *argp,
int argc, char *argv[]);
extern int cus__load(struct cus *self, const char *filename);
extern int cus__load_dir(struct cus *self, const char *dirname,
const char *filename_mask, const int recursive);
void cus__add(struct cus *self, struct cu *cu);
extern void cus__print_error_msg(const char *progname, const struct cus *cus,
const char *filename, const int err);
extern struct cu *cus__find_cu_by_name(const struct cus *self,
const char *name);
extern struct tag *cu__find_base_type_by_name(const struct cu *self,
const char *name);
extern struct tag *cus__find_struct_by_name(const struct cus *self,
struct cu **cu,
const char *name,
const int include_decls);
extern struct tag *cus__find_function_by_name(const struct cus *self,
struct cu **cu,
const char *name);
extern struct tag *cus__find_tag_by_id(const struct cus *self,
struct cu **cu, const Dwarf_Off id);
struct cu *cu__new(const char *name, uint8_t addr_size,
const unsigned char *build_id, int build_id_len);
extern void cu__delete(struct cu *self);
void cu__add_tag(struct cu *self, struct tag *tag);
extern struct tag *cu__find_tag_by_id(const struct cu *self,
const Dwarf_Off id);
extern struct tag *cu__find_first_typedef_of_type(const struct cu *self,
const Dwarf_Off type);
extern struct tag *cu__find_struct_by_name(const struct cu *cu,
const char *name,
const int include_decls);
extern bool cu__same_build_id(const struct cu *self, const struct cu *other);
extern void cu__account_inline_expansions(struct cu *self);
extern int cu__for_each_tag(struct cu *self,
int (*iterator)(struct tag *tag,
struct cu *cu,
void *cookie),
void *cookie,
struct tag *(*filter)(struct tag *tag,
struct cu *cu,
void *cookie));
extern void cus__for_each_cu(struct cus *self,
int (*iterator)(struct cu *cu,
void *cookie),
void *cookie,
struct cu *(*filter)(struct cu *cu));
extern const struct class_member *
class__find_bit_hole(const struct class *self,
const struct class_member *trailer,
const size_t bit_hole_size);
extern struct tag *cu__find_function_by_name(const struct cu *cu,
const char *name);
static inline size_t function__size(const struct function *self)
{
return self->lexblock.high_pc - self->lexblock.low_pc;
}
static inline int function__declared_inline(const struct function *self)
{
return (self->inlined == DW_INL_declared_inlined ||
self->inlined == DW_INL_declared_not_inlined);
}
static inline int function__inlined(const struct function *self)
{
return (self->inlined == DW_INL_inlined ||
self->inlined == DW_INL_declared_inlined);
}
void ftype__add_parameter(struct ftype *self, struct parameter *parm);
extern size_t ftype__fprintf(const struct ftype *self, const struct cu *cu,
const char *name, const int inlined,
const int is_pointer, const int type_spacing,
FILE *fp);
extern int ftype__has_parm_of_type(const struct ftype *self,
const struct tag *target,
const struct cu *cu);
void type__add_member(struct type *self, struct class_member *member);
extern struct class_member *
type__find_first_biggest_size_base_type_member(struct type *self,
const struct cu *cu);
extern const char *tag__name(const struct tag *self, const struct cu *cu,
char *bf, size_t len);
extern void tag__not_found_die(const char *file, int line, const char *func);
#define tag__assert_search_result(tag) \
do { if (!tag) tag__not_found_die(__FILE__,\
__LINE__, __func__); } while (0)
extern size_t tag__size(const struct tag *self, const struct cu *cu);
extern size_t tag__nr_cachelines(const struct tag *self, const struct cu *cu);
extern struct tag *tag__follow_typedef(struct tag *tag, const struct cu *cu);
extern struct class_member *type__find_member_by_name(const struct type *self,
const char *name);
extern uint32_t type__nr_members_of_type(const struct type *self,
const Dwarf_Off type);
extern struct class_member *type__last_member(struct type *self);
void class__add_vtable_entry(struct class *self, struct function *vtable_entry);
static inline struct class_member *
class__find_member_by_name(const struct class *self, const char *name)
{
return type__find_member_by_name(&self->type, name);
}
static inline uint16_t class__nr_members(const struct class *self)
{
return self->type.nr_members;
}
static inline size_t class__size(const struct class *self)
{
return self->type.size;
}
static inline int class__is_declaration(const struct class *self)
{
return self->type.declaration;
}
[CODIFF]: Detect and print all sorts of changes in structs [acme@newtoy examples]$ cat struct.c static struct foo { char a:2; unsigned int b; unsigned long c; unsigned long d; unsigned long e; } bar; int main(int argc, char *argv[]) { printf("%d", bar.a); } [acme@newtoy examples]$ Then change "a:2" to "a:4": [acme@newtoy examples]$ codiff -V old_struct new_struct struct.c: struct foo | +0 a:2; from: char /* 0(6) 1(2) */ to: char /* 0(4) 1(4) */ 1 struct changed Now, on top of that move a after b: [acme@newtoy examples]$ codiff -V old_struct new_struct struct.c: struct foo | +0 a:2; from: char /* 0(6) 1(2) */ to: char /* 4(4) 1(4) */ b; from: unsigned int /* 4(0) 4(0) */ to: unsigned int /* 0(0) 4(0) */ 1 struct changed [acme@newtoy examples]$ Move it back a to before b and change the type of e without changing its size, i.e. from unsigned long to long: [acme@newtoy examples]$ codiff -V old_struct new_struct struct.c: struct foo | +0 a:2; from: char /* 0(6) 1(2) */ to: char /* 0(4) 1(4) */ e; from: long unsigned int /* 16(0) 4(0) */ to: long int /* 16(0) 4(0) */ 1 struct changed [acme@newtoy examples]$ Now on top of this lets delete the c member: [acme@newtoy examples]$ codiff -V old_struct new_struct struct.c: struct foo | -4 nr_members: -1 -long unsigned int c; /* 8 4 */ a:2; from: char /* 0(6) 1(2) */ to: char /* 0(4) 1(4) */ d; from: long unsigned int /* 12(0) 4(0) */ to: long unsigned int /* 8(0) 4(0) */ e; from: long unsigned int /* 16(0) 4(0) */ to: long int /* 12(0) 4(0) */ 1 struct changed [acme@newtoy examples]$ WOW, many changes, what an ABI breakage, no? :-) It started as: [acme@newtoy examples]$ pahole old_struct foo /* /home/acme/pahole/examples/struct.c:3 */ struct foo { char a:2; /* 0 1 */ /* XXX 3 bytes hole, try to pack */ unsigned int b; /* 4 4 */ long unsigned int c; /* 8 4 */ long unsigned int d; /* 12 4 */ long unsigned int e; /* 16 4 */ }; /* size: 20, sum members: 17, holes: 1, sum holes: 3 */ And ended up as: [acme@newtoy examples]$ pahole new_struct foo /* /home/acme/pahole/examples/struct.c:3 */ struct foo { char a:4; /* 0 1 */ /* XXX 3 bytes hole, try to pack */ unsigned int b; /* 4 4 */ long unsigned int d; /* 8 4 */ long int e; /* 12 4 */ }; /* size: 16, sum members: 13, holes: 1, sum holes: 3 */ [acme@newtoy examples]$ Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 18:07:21 +01:00
void namespace__add_tag(struct namespace *self, struct tag *tag);
extern const char *variable__name(const struct variable *self,
const struct cu *cu);
extern const char *variable__type_name(const struct variable *self,
const struct cu *cu,
char *bf, size_t len);
extern const char *dwarf_tag_name(const uint32_t tag);
char *strings__add(const char *str);
#endif /* _DWARVES_H_ */