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-10-28 18:45:59 +02:00
|
|
|
|
|
|
|
#include "list.h"
|
|
|
|
|
2006-11-11 19:31:04 +01:00
|
|
|
struct cus {
|
|
|
|
struct list_head cus;
|
|
|
|
const char *filename;
|
|
|
|
};
|
|
|
|
|
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-11-03 18:38:43 +01:00
|
|
|
const char *name;
|
2006-10-31 20:12:42 +01:00
|
|
|
unsigned int id;
|
2006-11-03 18:38:43 +01:00
|
|
|
unsigned long nr_inline_expansions;
|
|
|
|
unsigned long size_inline_expansions;
|
2006-11-11 19:31:04 +01:00
|
|
|
unsigned int nr_functions_changed;
|
2006-11-12 15:29:33 +01:00
|
|
|
unsigned int nr_structures_changed;
|
|
|
|
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-11-18 14:54:02 +01:00
|
|
|
uint64_t type;
|
|
|
|
uint64_t id;
|
|
|
|
uint16_t tag;
|
|
|
|
uint16_t decl_line;
|
|
|
|
const char *decl_file;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct class {
|
|
|
|
struct tag tag;
|
|
|
|
struct cu *cu;
|
2006-10-28 18:45:59 +02:00
|
|
|
struct list_head members;
|
2006-11-02 17:48:35 +01:00
|
|
|
const char *name;
|
2006-11-03 18:32:32 +01:00
|
|
|
uint64_t size;
|
2006-11-11 17:15:50 +01:00
|
|
|
uint64_t nr_entries; /* For arrays */
|
2006-11-01 14:34:42 +01:00
|
|
|
unsigned short nr_members;
|
2006-10-28 23:10:47 +02:00
|
|
|
unsigned short nr_holes;
|
|
|
|
unsigned short padding;
|
2006-11-10 22:19:58 +01:00
|
|
|
unsigned int refcnt;
|
2006-11-11 19:31:04 +01:00
|
|
|
signed int diff;
|
2006-11-12 15:56:52 +01:00
|
|
|
struct class *class_to_diff;
|
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-11-05 03:46:22 +01:00
|
|
|
uint64_t offset;
|
2006-10-28 18:45:59 +02:00
|
|
|
unsigned int bit_size;
|
|
|
|
unsigned int bit_offset;
|
2006-11-10 22:19:58 +01:00
|
|
|
unsigned char visited:1;
|
2006-10-28 23:10:47 +02:00
|
|
|
unsigned short hole; /* If there is a hole before the next
|
|
|
|
one (or the end of the struct) */
|
2006-10-28 18:45:59 +02:00
|
|
|
};
|
|
|
|
|
2006-11-18 17:33:48 +01:00
|
|
|
struct function {
|
|
|
|
struct tag tag;
|
|
|
|
struct cu *cu;
|
|
|
|
struct list_head parameters;
|
|
|
|
struct list_head inline_expansions;
|
|
|
|
struct list_head variables;
|
|
|
|
const char *name;
|
|
|
|
uint64_t low_pc;
|
|
|
|
uint64_t high_pc;
|
|
|
|
unsigned short nr_parameters;
|
|
|
|
unsigned short nr_labels;
|
|
|
|
unsigned short nr_variables;
|
|
|
|
unsigned short inlined;
|
|
|
|
unsigned short nr_inline_expansions;
|
|
|
|
unsigned char external:1;
|
2006-11-19 00:15:36 +01:00
|
|
|
unsigned char unspecified_parameters;
|
2006-11-18 17:33:48 +01:00
|
|
|
unsigned int refcnt;
|
|
|
|
unsigned int size_inline_expansions;
|
|
|
|
signed int diff;
|
|
|
|
unsigned int cu_total_nr_inline_expansions;
|
|
|
|
unsigned long cu_total_size_inline_expansions;
|
|
|
|
struct class *class_to_diff;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct parameter {
|
|
|
|
struct tag tag;
|
|
|
|
char *name;
|
|
|
|
struct function *function;
|
|
|
|
};
|
|
|
|
|
[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;
|
|
|
|
struct cu *cu;
|
[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;
|
|
|
|
uint64_t abstract_origin;
|
|
|
|
};
|
|
|
|
|
2006-11-03 16:41:19 +01:00
|
|
|
struct inline_expansion {
|
2006-11-18 14:54:02 +01:00
|
|
|
struct tag tag;
|
2006-11-18 17:33:48 +01:00
|
|
|
struct function *function;
|
2006-11-18 14:54:02 +01:00
|
|
|
uint32_t size;
|
2006-11-03 16:41:19 +01:00
|
|
|
};
|
|
|
|
|
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);
|
|
|
|
extern void class__print(struct class *self);
|
2006-11-20 18:43:39 +01:00
|
|
|
extern void function__print(const struct function *self, int show_stats,
|
|
|
|
const int show_variables,
|
|
|
|
const int show_inline_expansions);
|
2006-10-28 23:22:42 +02:00
|
|
|
|
2006-11-11 19:31:04 +01:00
|
|
|
extern struct cus *cus__new(const char *filename);
|
|
|
|
extern int cus__load(struct cus *self);
|
2006-11-13 03:31:48 +01:00
|
|
|
extern struct cu *cus__find_cu_by_name(const struct cus *self,
|
|
|
|
const char *name);
|
2006-10-31 21:23:16 +01:00
|
|
|
extern struct class *cu__find_class_by_id(const struct cu *cu,
|
2006-11-05 03:46:22 +01:00
|
|
|
const uint64_t type);
|
2006-11-13 03:31:48 +01:00
|
|
|
extern struct class *cu__find_class_by_name(const struct cu *cu,
|
|
|
|
const char *name);
|
2006-11-05 05:17:19 +01:00
|
|
|
extern int class__is_struct(const struct class *self,
|
|
|
|
struct class **typedef_alias);
|
2006-11-11 19:31:04 +01:00
|
|
|
extern void cus__print_classes(struct cus *cus,
|
|
|
|
const unsigned int tag);
|
2006-11-18 17:33:48 +01:00
|
|
|
extern void cus__print_functions(struct cus *cus);
|
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-10-31 21:23:16 +01:00
|
|
|
extern int cu__for_each_class(struct cu *cu,
|
2006-11-12 20:33:37 +01:00
|
|
|
int (*iterator)(struct class *class,
|
2006-10-31 21:23:16 +01:00
|
|
|
void *cookie),
|
|
|
|
void *cookie);
|
2006-11-18 17:33:48 +01:00
|
|
|
extern int cu__for_each_function(struct cu *cu,
|
|
|
|
int (*iterator)(struct function *func,
|
|
|
|
void *cookie),
|
|
|
|
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-10-29 03:55:56 +01:00
|
|
|
void *cookie);
|
2006-10-28 23:22:42 +02:00
|
|
|
|
2006-11-20 18:43:39 +01:00
|
|
|
extern struct function *cu__find_function_by_id(const struct cu *self,
|
|
|
|
const uint64_t id);
|
2006-11-18 17:33:48 +01:00
|
|
|
extern struct function *cu__find_function_by_name(const struct cu *cu,
|
|
|
|
const char *name);
|
|
|
|
|
|
|
|
static inline uint32_t function__size(const struct function *self)
|
2006-11-11 19:31:04 +01:00
|
|
|
{
|
|
|
|
return self->high_pc - self->low_pc;
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
[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);
|
|
|
|
|
|
|
|
extern uint64_t class_member__names(const struct class_member *self,
|
|
|
|
char *class_name,
|
|
|
|
size_t class_name_size,
|
|
|
|
char *member_name,
|
|
|
|
size_t member_name_size);
|
2006-11-05 18:34:54 +01:00
|
|
|
extern unsigned int cacheline_size;
|
|
|
|
|
2006-11-20 18:43:39 +01:00
|
|
|
extern const char *variable__name(const struct variable *self);
|
|
|
|
extern const char *variable__type_name(const struct variable *self,
|
|
|
|
char *bf, size_t len);
|
|
|
|
|
|
|
|
extern const char *dwarf_tag_name(const unsigned int tag);
|
|
|
|
|
2006-10-28 18:45:59 +02:00
|
|
|
#endif /* _PAHOLE_CLASSES_H_ */
|