2006-10-28 18:45:59 +02:00
|
|
|
#ifndef _PAHOLE_CLASSES_H_
|
|
|
|
#define _PAHOLE_CLASSES_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>
|
2006-11-18 22:02:55 +01:00
|
|
|
#include <dwarf.h>
|
2006-12-24 15:07:41 +01:00
|
|
|
#include <elfutils/libdw.h>
|
2006-10-28 18:45:59 +02:00
|
|
|
|
|
|
|
#include "list.h"
|
|
|
|
|
2006-11-11 19:31:04 +01:00
|
|
|
struct cus {
|
|
|
|
struct list_head cus;
|
2006-12-27 17:39:37 +01:00
|
|
|
struct list_head priv_definitions;
|
|
|
|
struct list_head priv_fwd_decls;
|
|
|
|
struct list_head *definitions;
|
|
|
|
struct list_head *fwd_decls;
|
2006-11-11 19:31:04 +01:00
|
|
|
};
|
|
|
|
|
2006-10-31 20:12:42 +01:00
|
|
|
struct cu {
|
|
|
|
struct list_head node;
|
|
|
|
struct list_head classes;
|
2006-11-18 17:33:48 +01:00
|
|
|
struct list_head functions;
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
struct list_head variables;
|
2006-12-20 15:07:09 +01:00
|
|
|
struct list_head tool_list; /* To be used by tools such as ctracer */
|
2006-11-03 18:38:43 +01:00
|
|
|
const char *name;
|
2006-12-29 19:34:11 +01:00
|
|
|
uint8_t addr_size;
|
2006-12-28 14:18:43 +01:00
|
|
|
uint16_t language;
|
2006-12-24 15:00:07 +01:00
|
|
|
uint32_t id;
|
2006-11-03 18:38:43 +01:00
|
|
|
unsigned long nr_inline_expansions;
|
2006-12-25 01:27:22 +01:00
|
|
|
size_t size_inline_expansions;
|
2006-12-28 14:18:43 +01:00
|
|
|
uint32_t nr_functions_changed;
|
|
|
|
uint32_t nr_structures_changed;
|
2006-11-12 15:29:33 +01:00
|
|
|
size_t max_len_changed_item;
|
2006-11-11 19:31:04 +01:00
|
|
|
size_t function_bytes_added;
|
|
|
|
size_t function_bytes_removed;
|
2006-10-28 18:45:59 +02:00
|
|
|
};
|
|
|
|
|
2006-11-18 14:54:02 +01:00
|
|
|
struct tag {
|
2006-10-28 18:45:59 +02:00
|
|
|
struct list_head node;
|
2006-12-24 15:18:14 +01:00
|
|
|
Dwarf_Off type;
|
2006-12-24 15:07:41 +01:00
|
|
|
Dwarf_Off id;
|
2006-11-18 14:54:02 +01:00
|
|
|
uint16_t tag;
|
|
|
|
uint16_t decl_line;
|
|
|
|
const char *decl_file;
|
2006-12-29 18:28:58 +01:00
|
|
|
uint32_t refcnt;
|
2006-11-18 14:54:02 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
struct class {
|
|
|
|
struct tag tag;
|
|
|
|
struct cu *cu;
|
2006-10-28 18:45:59 +02:00
|
|
|
struct list_head members;
|
2006-12-23 21:30:48 +01:00
|
|
|
struct list_head node;
|
2006-11-02 17:48:35 +01:00
|
|
|
const char *name;
|
2006-12-25 01:27:22 +01:00
|
|
|
size_t size;
|
2006-12-28 14:18:43 +01:00
|
|
|
uint16_t nr_members;
|
2006-12-28 15:00:21 +01:00
|
|
|
uint8_t nr_holes;
|
|
|
|
uint8_t nr_bit_holes;
|
2006-12-28 14:18:43 +01:00
|
|
|
uint16_t padding;
|
2006-12-28 15:00:21 +01:00
|
|
|
uint8_t bit_padding;
|
2006-12-20 16:49:51 +01:00
|
|
|
uint8_t declaration:1;
|
|
|
|
uint8_t visited:1;
|
2006-12-23 22:29:27 +01:00
|
|
|
uint8_t fwd_decl_emitted:1;
|
2006-12-28 15:00:21 +01:00
|
|
|
int32_t diff;
|
|
|
|
struct class *class_to_diff;
|
2006-10-28 18:45:59 +02:00
|
|
|
};
|
|
|
|
|
2007-01-02 05:11:38 +01:00
|
|
|
static inline struct class *tag__class(const struct tag *self)
|
2006-12-29 18:28:58 +01:00
|
|
|
{
|
|
|
|
return (struct class *)self;
|
|
|
|
}
|
|
|
|
|
2006-12-29 23:58:03 +01:00
|
|
|
struct base_type {
|
|
|
|
struct tag tag;
|
|
|
|
const char *name;
|
|
|
|
size_t size;
|
|
|
|
};
|
|
|
|
|
2007-01-02 05:11:38 +01:00
|
|
|
static inline struct base_type *tag__base_type(const struct tag *self)
|
2006-12-29 23:58:03 +01:00
|
|
|
{
|
|
|
|
return (struct base_type *)self;
|
|
|
|
}
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
struct array_type {
|
|
|
|
struct tag tag;
|
|
|
|
const char *name;
|
|
|
|
uint32_t *nr_entries;
|
|
|
|
uint8_t dimensions;
|
|
|
|
};
|
|
|
|
|
2007-01-02 05:11:38 +01:00
|
|
|
static inline struct array_type *tag__array_type(const struct tag *self)
|
2006-12-29 18:28:58 +01:00
|
|
|
{
|
|
|
|
return (struct array_type *)self;
|
|
|
|
}
|
|
|
|
|
2006-10-28 18:45:59 +02:00
|
|
|
struct class_member {
|
2006-11-18 14:54:02 +01:00
|
|
|
struct tag tag;
|
2006-11-02 17:48:35 +01:00
|
|
|
char *name;
|
2006-11-12 20:52:03 +01:00
|
|
|
struct class *class;
|
2006-12-28 13:09:18 +01:00
|
|
|
uint16_t offset;
|
|
|
|
uint8_t bit_offset;
|
|
|
|
uint8_t bit_size;
|
|
|
|
uint8_t bit_hole; /* If there is a bit hole before the next
|
2006-10-28 23:10:47 +02:00
|
|
|
one (or the end of the struct) */
|
2006-12-28 13:09:18 +01:00
|
|
|
uint8_t visited:1;
|
|
|
|
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) */
|
2006-10-28 18:45:59 +02:00
|
|
|
};
|
|
|
|
|
2006-11-20 19:38:47 +01:00
|
|
|
struct lexblock {
|
2007-01-02 16:25:56 +01:00
|
|
|
struct tag tag;
|
2007-01-03 01:26:01 +01:00
|
|
|
struct list_head tags;
|
2007-01-02 16:25:56 +01:00
|
|
|
Dwarf_Addr low_pc;
|
|
|
|
Dwarf_Addr high_pc;
|
2006-12-28 14:18:43 +01:00
|
|
|
uint16_t nr_inline_expansions;
|
|
|
|
uint16_t nr_labels;
|
|
|
|
uint16_t nr_variables;
|
2007-01-02 16:25:56 +01:00
|
|
|
uint16_t nr_lexblocks;
|
2006-12-25 01:27:22 +01:00
|
|
|
size_t size_inline_expansions;
|
2006-11-20 19:38:47 +01:00
|
|
|
};
|
|
|
|
|
2007-01-03 01:26:01 +01:00
|
|
|
static inline struct lexblock *tag__lexblock(const struct tag *self)
|
|
|
|
{
|
|
|
|
return (struct lexblock *)self;
|
|
|
|
}
|
|
|
|
|
2006-12-30 19:34:20 +01:00
|
|
|
/*
|
|
|
|
* tag.tag can be DW_TAG_subprogram_type or DW_TAG_subroutine_type.
|
|
|
|
*/
|
|
|
|
struct ftype {
|
2006-11-18 17:33:48 +01:00
|
|
|
struct tag tag;
|
2006-12-30 19:34:20 +01:00
|
|
|
struct list_head parms;
|
|
|
|
uint16_t nr_parms;
|
[CLASSES]: Introduce DW_TAG_subroutine_type specific parser
So that we handle DW_TAG_formal_parameters in this tag, fixing
these cases:
--- /tmp/ctracer.c.before 2006-12-29 13:27:24.000000000 -0200
+++ /tmp/ctracer.c 2007-01-02 02:34:18.000000000 -0200
<SNIP>
@@ -62,7 +62,7 @@
}; /* size: 68, cachelines: 3 */
/* last cacheline: 4 bytes */
-typedef int (*kretprobe_handler_t)(void /* FIXME: add parm list */);
+typedef int (*kretprobe_handler_t)(struct kretprobe_instance *, struct pt_regs *);
/* /pub/scm/linux/kernel/git/acme/linux-2.6/include/linux/list.h:607 */
struct hlist_head {
struct hlist_node * first; /* 0 4 */
[acme@newtoy ctracer_example]$
--- /tmp/pfunct.before 2006-12-30 16:18:25.000000000 -0200
+++ /tmp/pfunct.after 2007-01-02 02:08:50.000000000 -0200
@@ -249,7 +249,7 @@
/* definitions: 1 */
/* /pub/scm/linux/kernel/git/acme/linux-2.6/lib/klist.c:57 */
-void klist_init(struct klist * k, * get, * put);
+void klist_init(struct klist * k, void (*get)(struct klist_node *), void (*put)(struct klist_node *));
/* size: 12, inline expansions: 1 (5 bytes) */
/* definitions: 1 */
The struct/union case still needs fixing, but we're getting there...
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-02 05:42:33 +01:00
|
|
|
uint8_t unspec_parms; /* just one bit is needed */
|
2006-12-30 19:34:20 +01:00
|
|
|
};
|
|
|
|
|
[CLASSES]: Introduce DW_TAG_subroutine_type specific parser
So that we handle DW_TAG_formal_parameters in this tag, fixing
these cases:
--- /tmp/ctracer.c.before 2006-12-29 13:27:24.000000000 -0200
+++ /tmp/ctracer.c 2007-01-02 02:34:18.000000000 -0200
<SNIP>
@@ -62,7 +62,7 @@
}; /* size: 68, cachelines: 3 */
/* last cacheline: 4 bytes */
-typedef int (*kretprobe_handler_t)(void /* FIXME: add parm list */);
+typedef int (*kretprobe_handler_t)(struct kretprobe_instance *, struct pt_regs *);
/* /pub/scm/linux/kernel/git/acme/linux-2.6/include/linux/list.h:607 */
struct hlist_head {
struct hlist_node * first; /* 0 4 */
[acme@newtoy ctracer_example]$
--- /tmp/pfunct.before 2006-12-30 16:18:25.000000000 -0200
+++ /tmp/pfunct.after 2007-01-02 02:08:50.000000000 -0200
@@ -249,7 +249,7 @@
/* definitions: 1 */
/* /pub/scm/linux/kernel/git/acme/linux-2.6/lib/klist.c:57 */
-void klist_init(struct klist * k, * get, * put);
+void klist_init(struct klist * k, void (*get)(struct klist_node *), void (*put)(struct klist_node *));
/* size: 12, inline expansions: 1 (5 bytes) */
/* definitions: 1 */
The struct/union case still needs fixing, but we're getting there...
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-02 05:42:33 +01:00
|
|
|
static inline struct ftype *tag__ftype(const struct tag *self)
|
|
|
|
{
|
|
|
|
return (struct ftype *)self;
|
|
|
|
}
|
|
|
|
|
2006-12-30 19:34:20 +01:00
|
|
|
struct function {
|
|
|
|
struct ftype proto;
|
2006-11-18 17:33:48 +01:00
|
|
|
struct cu *cu;
|
2006-11-20 19:38:47 +01:00
|
|
|
struct lexblock lexblock;
|
2006-11-18 17:33:48 +01:00
|
|
|
const char *name;
|
2006-12-28 15:27:12 +01:00
|
|
|
size_t cu_total_size_inline_expansions;
|
2006-12-30 19:34:20 +01:00
|
|
|
uint16_t cu_total_nr_inline_expansions;
|
2006-12-28 15:27:12 +01:00
|
|
|
uint8_t inlined:2;
|
2006-12-28 14:18:43 +01:00
|
|
|
uint8_t external:1;
|
2006-12-28 15:27:12 +01:00
|
|
|
/* fields used by tools */
|
|
|
|
struct list_head tool_node;
|
2006-12-28 14:18:43 +01:00
|
|
|
int32_t diff;
|
2006-11-18 17:33:48 +01:00
|
|
|
struct class *class_to_diff;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct parameter {
|
|
|
|
struct tag tag;
|
|
|
|
char *name;
|
|
|
|
};
|
|
|
|
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
struct variable {
|
2006-11-18 14:54:02 +01:00
|
|
|
struct tag tag;
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
struct list_head cu_node;
|
|
|
|
char *name;
|
2006-12-28 12:38:40 +01:00
|
|
|
Dwarf_Off abstract_origin;
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
};
|
|
|
|
|
2007-01-03 01:26:01 +01:00
|
|
|
static inline struct variable *tag__variable(const struct tag *self)
|
|
|
|
{
|
|
|
|
return (struct variable *)self;
|
|
|
|
}
|
|
|
|
|
2006-11-03 16:41:19 +01:00
|
|
|
struct inline_expansion {
|
2006-11-18 14:54:02 +01:00
|
|
|
struct tag tag;
|
2006-12-25 01:27:22 +01:00
|
|
|
size_t size;
|
2006-12-26 14:44:05 +01:00
|
|
|
Dwarf_Addr low_pc;
|
|
|
|
Dwarf_Addr high_pc;
|
2006-11-03 16:41:19 +01:00
|
|
|
};
|
|
|
|
|
2007-01-03 01:26:01 +01:00
|
|
|
static inline struct inline_expansion *
|
|
|
|
tag__inline_expansion(const struct tag *self)
|
|
|
|
{
|
|
|
|
return (struct inline_expansion *)self;
|
|
|
|
}
|
|
|
|
|
2006-11-20 19:17:42 +01:00
|
|
|
struct label {
|
|
|
|
struct tag tag;
|
|
|
|
char *name;
|
2006-12-28 12:36:39 +01:00
|
|
|
Dwarf_Addr low_pc;
|
2006-11-20 19:17:42 +01:00
|
|
|
};
|
|
|
|
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
struct enumerator {
|
|
|
|
struct tag tag;
|
|
|
|
const char *name;
|
|
|
|
uint32_t value;
|
|
|
|
};
|
|
|
|
|
2006-11-05 18:34:54 +01:00
|
|
|
#define DEFAULT_CACHELINE_SIZE 32
|
|
|
|
|
2006-11-12 20:33:37 +01:00
|
|
|
extern void class__find_holes(struct class *self);
|
2006-12-29 18:28:58 +01:00
|
|
|
extern void tag__print(const struct tag *self, const struct cu *cu,
|
|
|
|
const char *prefix, const char *suffix);
|
2006-12-28 14:18:43 +01:00
|
|
|
extern void function__print(const struct function *self, const int show_stats,
|
2006-11-20 18:43:39 +01:00
|
|
|
const int show_variables,
|
|
|
|
const int show_inline_expansions);
|
2006-10-28 23:22:42 +02:00
|
|
|
|
2006-12-27 17:39:37 +01:00
|
|
|
extern struct cus *cus__new(struct list_head *definitions,
|
|
|
|
struct list_head *fwd_decls);
|
|
|
|
extern int cus__load(struct cus *self, const char *filename);
|
2006-12-27 17:57:19 +01:00
|
|
|
extern int cus__load_dir(struct cus *self, const char *dirname,
|
|
|
|
const char *filename_mask, const int recursive);
|
2006-12-27 17:39:37 +01:00
|
|
|
extern struct cu *cus__find_cu_by_name(const struct cus *self,
|
|
|
|
const char *name);
|
2006-12-23 21:46:05 +01:00
|
|
|
extern struct function *cus__find_function_by_name(const struct cus *self,
|
|
|
|
const char *name);
|
2006-12-30 19:34:20 +01:00
|
|
|
extern int cus__emit_ftype_definitions(struct cus *self, struct cu *cu,
|
|
|
|
struct ftype *ftype);
|
2006-12-23 22:29:27 +01:00
|
|
|
extern int cus__emit_struct_definitions(struct cus *self, struct class *class,
|
|
|
|
const char *prefix,
|
|
|
|
const char *suffix);
|
2006-12-24 02:33:37 +01:00
|
|
|
extern int cus__emit_fwd_decl(struct cus *self, struct class *class);
|
2006-12-23 22:29:27 +01:00
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
extern struct tag *cu__find_tag_by_id(const struct cu *self,
|
|
|
|
const Dwarf_Off id);
|
2006-11-13 03:31:48 +01:00
|
|
|
extern struct class *cu__find_class_by_name(const struct cu *cu,
|
|
|
|
const char *name);
|
2006-12-29 18:28:58 +01:00
|
|
|
extern int tag__is_struct(const struct tag *self, struct tag **typedef_alias,
|
|
|
|
const struct cu *cu);
|
2006-11-13 03:31:48 +01:00
|
|
|
extern struct class *cus__find_class_by_name(const struct cus *self,
|
2006-11-11 19:31:04 +01:00
|
|
|
const char *name);
|
2006-11-03 18:38:43 +01:00
|
|
|
extern void cu__account_inline_expansions(struct cu *self);
|
2006-12-29 18:28:58 +01:00
|
|
|
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));
|
2006-11-18 17:33:48 +01:00
|
|
|
extern int cu__for_each_function(struct cu *cu,
|
|
|
|
int (*iterator)(struct function *func,
|
|
|
|
void *cookie),
|
2006-12-18 18:35:31 +01:00
|
|
|
void *cookie,
|
2006-12-20 15:05:29 +01:00
|
|
|
struct function *(*filter)(struct function *function,
|
|
|
|
void *cookie));
|
2006-11-11 19:31:04 +01:00
|
|
|
extern void cus__for_each_cu(struct cus *self,
|
|
|
|
int (*iterator)(struct cu *cu,
|
2006-10-31 21:23:16 +01:00
|
|
|
void *cookie),
|
2006-12-01 02:48:34 +01:00
|
|
|
void *cookie,
|
|
|
|
struct cu *(*filter)(struct cu *cu));
|
2006-10-28 23:22:42 +02:00
|
|
|
|
2006-12-07 19:11:47 +01:00
|
|
|
extern const struct class_member *
|
|
|
|
class__find_bit_hole(const struct class *self,
|
|
|
|
const struct class_member *trailer,
|
|
|
|
const size_t bit_hole_size);
|
|
|
|
|
2006-11-20 18:43:39 +01:00
|
|
|
extern struct function *cu__find_function_by_id(const struct cu *self,
|
2006-12-24 15:07:41 +01:00
|
|
|
const Dwarf_Off id);
|
2006-11-18 17:33:48 +01:00
|
|
|
extern struct function *cu__find_function_by_name(const struct cu *cu,
|
|
|
|
const char *name);
|
|
|
|
|
2006-12-25 01:27:22 +01:00
|
|
|
static inline size_t function__size(const struct function *self)
|
2006-11-11 19:31:04 +01:00
|
|
|
{
|
2007-01-02 16:25:56 +01:00
|
|
|
return self->lexblock.high_pc - self->lexblock.low_pc;
|
2006-11-11 19:31:04 +01:00
|
|
|
}
|
|
|
|
|
2006-11-18 22:02:55 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2007-01-02 06:18:33 +01:00
|
|
|
extern size_t ftype__snprintf(const struct ftype *self, const struct cu *cu,
|
|
|
|
char *bf, const size_t len,
|
|
|
|
const char *name, const int inlined,
|
|
|
|
const int is_pointer,
|
|
|
|
const size_t type_spacing);
|
2007-01-02 05:37:24 +01:00
|
|
|
extern int ftype__has_parm_of_type(const struct ftype *self,
|
|
|
|
const struct tag *target,
|
|
|
|
const struct cu *cu);
|
2006-12-20 15:03:12 +01:00
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
extern const char *tag__name(const struct tag *self, const struct cu *cu,
|
|
|
|
char *bf, size_t len);
|
2006-12-19 12:11:17 +01:00
|
|
|
|
[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
|
|
|
extern struct class_member *class__find_member_by_name(const struct class *self,
|
|
|
|
const char *name);
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
extern size_t class_member__names(const struct tag *type,
|
2006-12-25 01:27:22 +01:00
|
|
|
const struct class_member *self,
|
|
|
|
char *class_name, size_t class_name_size,
|
|
|
|
char *member_name, size_t member_name_size);
|
|
|
|
extern size_t cacheline_size;
|
2006-11-05 18:34:54 +01:00
|
|
|
|
2007-01-03 01:26:01 +01:00
|
|
|
extern const char *variable__name(const struct variable *self,
|
|
|
|
const struct cu *cu);
|
2006-11-20 18:43:39 +01:00
|
|
|
extern const char *variable__type_name(const struct variable *self,
|
2007-01-03 01:26:01 +01:00
|
|
|
const struct cu *cu,
|
2006-11-20 18:43:39 +01:00
|
|
|
char *bf, size_t len);
|
|
|
|
|
2006-12-28 14:18:43 +01:00
|
|
|
extern const char *dwarf_tag_name(const uint32_t tag);
|
2006-11-20 18:43:39 +01:00
|
|
|
|
2006-12-20 23:40:13 +01:00
|
|
|
extern size_t parameter__names(const struct parameter *self,
|
2006-12-30 19:34:20 +01:00
|
|
|
const struct cu *cu,
|
2006-12-20 23:40:13 +01:00
|
|
|
char *class_name, size_t class_name_size,
|
|
|
|
char *parameter_name,
|
|
|
|
size_t parameter_name_size);
|
|
|
|
|
2006-10-28 18:45:59 +02:00
|
|
|
#endif /* _PAHOLE_CLASSES_H_ */
|