Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/acme/pahole

This commit is contained in:
Arnaldo Carvalho de Melo 2009-03-09 15:56:19 -03:00
commit 9f05162b3f
23 changed files with 2119 additions and 972 deletions

View File

@ -26,7 +26,7 @@ if (NOT CMAKE_BUILD_TYPE)
FORCE)
endif (NOT CMAKE_BUILD_TYPE)
add_definitions(-D_GNU_SOURCE)
add_definitions(-D_GNU_SOURCE -DDWARVES_VERSION=\\"v1.7\\")
find_package(DWARF REQUIRED)
find_package(ZLIB REQUIRED)
@ -89,6 +89,7 @@ install(TARGETS codiff ctracer dtagnames pahole pdwtags
install(TARGETS dwarves LIBRARY DESTINATION ${LIB_INSTALL_DIR})
install(TARGETS dwarves dwarves_emit dwarves_reorganize LIBRARY DESTINATION ${LIB_INSTALL_DIR})
install(FILES dwarves.h dwarves_emit.h dwarves_reorganize.h DESTINATION ${CMAKE_INSTALL_PREFIX}/include)
install(FILES man-pages/pahole.1 DESTINATION ${CMAKE_INSTALL_PREFIX}/share/man/man1/)
install(PROGRAMS ostra/ostra-cg DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
install(FILES ostra/python/ostra.py DESTINATION ${CMAKE_INSTALL_PREFIX}/share/dwarves/runtime/python)
install(FILES lib/Makefile lib/ctracer_relay.c lib/ctracer_relay.h lib/linux.blacklist.cu

View File

@ -1,3 +1,4 @@
config.h.cmake
ctf_loader.c
ctf_loader.h
dwarf_loader.c
@ -13,15 +14,20 @@ CMakeLists.txt
codiff.c
ctracer.c
dtagnames.c
gobuffer.c
gobuffer.h
hash.h
list.h
MANIFEST
man-pages/pahole.1
pahole.c
pdwtags.c
pfunct.c
pglobal.c
prefcnt.c
syscse.c
strings.c
strings.h
dutil.c
dutil.h
NEWS

162
codiff.c
View File

@ -33,6 +33,9 @@ static struct strlist *structs_printed;
#define TCHANGEF__OFFSET (1 << 3)
#define TCHANGEF__BIT_OFFSET (1 << 4)
#define TCHANGEF__BIT_SIZE (1 << 5)
#define TCHANGEF__PADDING (1 << 6)
#define TCHANGEF__NR_HOLES (1 << 7)
#define TCHANGEF__NR_BIT_HOLES (1 << 8)
static uint32_t terse_type_changes;
@ -69,8 +72,6 @@ static void diff_function(const struct cu *new_cu, struct function *function,
struct tag *new_tag;
const char *name;
assert(function->proto.tag.tag == DW_TAG_subprogram);
if (function->inlined || function->abstract_origin != 0)
return;
@ -126,8 +127,8 @@ static int check_print_change(const struct class_member *old,
{
size_t old_size, new_size;
char old_type_name[128], new_type_name[128];
const struct tag *old_type = cu__find_tag_by_id(old_cu, old->tag.type);
const struct tag *new_type = cu__find_tag_by_id(new_cu, new->tag.type);
const struct tag *old_type = cu__find_type_by_id(old_cu, old->tag.type);
const struct tag *new_type = cu__find_type_by_id(new_cu, new->tag.type);
int changes = 0;
if (old_type == NULL || new_type == NULL)
@ -163,8 +164,8 @@ static int check_print_change(const struct class_member *old,
if (changes && print && !show_terse_type_changes)
printf(" %s\n"
" from: %-21s /* %5u(%u) %5zd(%d) */\n"
" to: %-21s /* %5u(%u) %5zd(%u) */\n",
" from: %-21s /* %5u(%2u) %5zd(%2d) */\n"
" to: %-21s /* %5u(%2u) %5zd(%2u) */\n",
class_member__name(old),
old_type_name, old->offset, old->bit_offset,
old_size, old->bit_size,
@ -182,15 +183,54 @@ static int check_print_members_changes(const struct class *structure,
{
int changes = 0;
struct class_member *member;
uint16_t nr_twins_found = 0;
type__for_each_member(&structure->type, member) {
const char *member_name = class_member__name(member);
struct class_member *twin =
class__find_member_by_name(new_structure,
class_member__name(member));
if (twin != NULL)
class__find_member_by_name(new_structure, member_name);
if (twin != NULL) {
twin->tag.visited = 1;
++nr_twins_found;
if (check_print_change(member, cu, twin, new_cu, print))
changes = 1;
} else {
changes = 1;
if (print) {
char name[128];
struct tag *type;
type = cu__find_type_by_id(cu, member->tag.type);
printf(" %s\n"
" removed: %-21s /* %5u(%2u) %5zd(%2d) */\n",
class_member__name(member),
tag__name(type, cu, name, sizeof(name)),
member->offset, member->bit_offset,
tag__size(type, cu), member->bit_size);
}
}
}
if (nr_twins_found == new_structure->type.nr_members)
goto out;
changes = 1;
if (!print)
goto out;
type__for_each_member(&new_structure->type, member) {
if (!member->tag.visited) {
char name[128];
struct tag *type;
type = cu__find_type_by_id(new_cu, member->tag.type);
printf(" %s\n"
" added: %-21s /* %5u(%2u) %5zd(%2d) */\n",
class_member__name(member),
tag__name(type, new_cu, name, sizeof(name)),
member->offset, member->bit_offset,
tag__size(type, new_cu), member->bit_size);
}
}
out:
return changes;
}
@ -204,10 +244,11 @@ static void diff_struct(const struct cu *new_cu, struct class *structure,
assert(class__is_struct(structure));
if (class__size(structure) == 0 || class__name(structure, cu) == NULL)
if (class__size(structure) == 0 || class__name(structure) == NULL)
return;
new_tag = cu__find_struct_by_name(new_cu, class__name(structure, cu), 0);
new_tag = cu__find_struct_by_name(new_cu,
class__name(structure), 0, NULL);
if (new_tag == NULL)
return;
@ -220,12 +261,16 @@ static void diff_struct(const struct cu *new_cu, struct class *structure,
diff = class__size(structure) != class__size(new_structure) ||
class__nr_members(structure) != class__nr_members(new_structure) ||
check_print_members_changes(structure, cu,
new_structure, new_cu, 0);
new_structure, new_cu, 0) ||
structure->padding != new_structure->padding ||
structure->nr_holes != new_structure->nr_holes ||
structure->nr_bit_holes != new_structure->nr_bit_holes;
if (diff == 0)
return;
++cu->nr_structures_changed;
len = strlen(class__name(structure, cu)) + sizeof("struct");
len = strlen(class__name(structure)) + sizeof("struct");
if (len > cu->max_len_changed_item)
cu->max_len_changed_item = len;
structure->priv = diff_info__new(class__tag(new_structure),
@ -236,7 +281,7 @@ static int diff_tag_iterator(struct tag *tag, struct cu *cu, void *new_cu)
{
if (tag__is_struct(tag))
diff_struct(new_cu, tag__class(tag), cu);
else if (tag->tag == DW_TAG_subprogram)
else if (tag__is_function(tag))
diff_function(new_cu, tag__function(tag), cu);
return 0;
@ -249,8 +294,6 @@ static int find_new_functions_iterator(struct tag *tfunction, struct cu *cu,
struct tag *old_function;
const char *name;
assert(function->proto.tag.tag == DW_TAG_subprogram);
if (function->inlined)
return 0;
@ -280,19 +323,20 @@ static int find_new_classes_iterator(struct tag *tag, struct cu *cu, void *old_c
return 0;
class = tag__class(tag);
if (class__name(class, cu) == NULL)
if (class__name(class) == NULL)
return 0;
if (class__size(class) == 0)
return 0;
if (cu__find_struct_by_name(old_cu, class__name(class, cu), 0) != NULL)
if (cu__find_struct_by_name(old_cu,
class__name(class), 0, NULL) != NULL)
return 0;
class->priv = diff_info__new(NULL, NULL, 1);
++cu->nr_structures_changed;
len = strlen(class__name(class, cu)) + sizeof("struct");
len = strlen(class__name(class)) + sizeof("struct");
if (len > cu->max_len_changed_item)
cu->max_len_changed_item = len;
return 0;
@ -300,7 +344,7 @@ static int find_new_classes_iterator(struct tag *tag, struct cu *cu, void *old_c
static int find_new_tags_iterator(struct tag *tag, struct cu *cu, void *old_cu)
{
if (tag->tag == DW_TAG_subprogram) {
if (tag__is_function(tag)) {
/*
* We're not interested in aliases, just real function definitions,
* where we'll know if the kind of inlining
@ -319,8 +363,7 @@ static int cu_find_new_tags_iterator(struct cu *new_cu, void *old_cus)
if (old_cu != NULL && cu__same_build_id(old_cu, new_cu))
return 0;
cu__for_each_tag(new_cu, find_new_tags_iterator,
old_cu, NULL);
cu__for_each_tag(new_cu, find_new_tags_iterator, old_cu, NULL);
return 0;
}
@ -396,7 +439,7 @@ static void show_diffs_function(struct function *function, const struct cu *cu,
static void show_changed_member(char change, const struct class_member *member,
const struct cu *cu)
{
const struct tag *type = cu__find_tag_by_id(cu, member->tag.type);
const struct tag *type = cu__find_type_by_id(cu, member->tag.type);
char bf[128];
tag__assert_search_result(type);
@ -432,12 +475,11 @@ static void show_nr_members_changes(const struct class *structure,
}
}
static void print_terse_type_changes(struct class *structure,
const struct cu *cu)
static void print_terse_type_changes(struct class *structure)
{
const char *sep = "";
printf("struct %s: ", class__name(structure, cu));
printf("struct %s: ", class__name(structure));
if (terse_type_changes & TCHANGEF__SIZE) {
fputs("size", stdout);
@ -459,8 +501,20 @@ static void print_terse_type_changes(struct class *structure,
printf("%sbit_offset", sep);
sep = ", ";
}
if (terse_type_changes & TCHANGEF__BIT_SIZE)
if (terse_type_changes & TCHANGEF__BIT_SIZE) {
printf("%sbit_size", sep);
sep = ", ";
}
if (terse_type_changes & TCHANGEF__PADDING) {
printf("%spadding", sep);
sep = ", ";
}
if (terse_type_changes & TCHANGEF__NR_HOLES) {
printf("%snr_holes", sep);
sep = ", ";
}
if (terse_type_changes & TCHANGEF__NR_BIT_HOLES)
printf("%snr_bit_holes", sep);
putchar('\n');
}
@ -495,7 +549,7 @@ static void show_diffs_structure(struct class *structure,
printf(" struct %-*.*s | %+4d\n",
(int)(cu->max_len_changed_item - sizeof("struct")),
(int)(cu->max_len_changed_item - sizeof("struct")),
class__name(structure, cu), diff);
class__name(structure), diff);
if (diff != 0)
terse_type_changes |= TCHANGEF__SIZE;
@ -517,11 +571,31 @@ static void show_diffs_structure(struct class *structure,
new_structure, di->cu);
}
}
if (new_structure != NULL)
if (new_structure != NULL) {
diff = (int)new_structure->padding - (int)structure->padding;
if (diff) {
terse_type_changes |= TCHANGEF__PADDING;
if (!show_terse_type_changes)
printf(" padding: %+d\n", diff);
}
diff = (int)new_structure->nr_holes - (int)structure->nr_holes;
if (diff) {
terse_type_changes |= TCHANGEF__NR_HOLES;
if (!show_terse_type_changes)
printf(" nr_holes: %+d\n", diff);
}
diff = ((int)new_structure->nr_bit_holes -
(int)structure->nr_bit_holes);
if (structure->nr_bit_holes != new_structure->nr_bit_holes) {
terse_type_changes |= TCHANGEF__NR_BIT_HOLES;
if (!show_terse_type_changes)
printf(" nr_bit_holes: %+d\n", diff);
}
check_print_members_changes(structure, cu,
new_structure, di->cu, 1);
}
if (show_terse_type_changes)
print_terse_type_changes(structure, cu);
print_terse_type_changes(structure);
}
static int show_function_diffs_iterator(struct tag *tag, struct cu *cu,
@ -529,7 +603,7 @@ static int show_function_diffs_iterator(struct tag *tag, struct cu *cu,
{
struct function *function = tag__function(tag);
if (tag->tag == DW_TAG_subprogram && function->priv != NULL)
if (tag__is_function(tag) && function->priv != NULL)
show_diffs_function(function, cu, cookie);
return 0;
}
@ -544,7 +618,7 @@ static int show_structure_diffs_iterator(struct tag *tag, struct cu *cu,
class = tag__class(tag);
if (class->priv != NULL) {
const char *name = class__name(class, cu);
const char *name = class__name(class);
if (!strlist__has_entry(structs_printed, name)) {
show_diffs_structure(class, cu);
strlist__add(structs_printed, name);
@ -624,6 +698,9 @@ static void print_total_function_diff(const char *filename)
putchar('\n');
}
/* Name and version of program. */
ARGP_PROGRAM_VERSION_HOOK_DEF = dwarves_print_version;
static const struct argp_option codiff__options[] = {
{
.key = 's',
@ -676,7 +753,7 @@ int main(int argc, char *argv[])
int remaining, err;
struct cus *old_cus, *new_cus;
char *old_filename, *new_filename;
char *dwfl_argv[4];
char *filenames[2];
struct stat st;
if (dwarves__init(0)) {
@ -684,9 +761,8 @@ int main(int argc, char *argv[])
return EXIT_FAILURE;
}
argp_parse(&codiff__argp, argc, argv, 0, &remaining, NULL);
if (remaining < argc) {
if (argp_parse(&codiff__argp, argc, argv, 0, &remaining, NULL) ||
remaining < argc) {
switch (argc - remaining) {
case 2: old_filename = argv[remaining++];
new_filename = argv[remaining++]; break;
@ -695,7 +771,7 @@ int main(int argc, char *argv[])
}
} else {
failure:
argp_help(&codiff__argp, stderr, ARGP_HELP_SEE, "codiff");
argp_help(&codiff__argp, stderr, ARGP_HELP_SEE, argv[0]);
return EXIT_FAILURE;
}
@ -716,14 +792,12 @@ failure:
return EXIT_FAILURE;
}
dwfl_argv[0] = argv[0];
dwfl_argv[1] = "-e";
dwfl_argv[3] = NULL;
filenames[1] = NULL;
/* If old_file is a character device, leave its cus empty */
if (!S_ISCHR(st.st_mode)) {
dwfl_argv[2] = old_filename;
err = cus__loadfl(old_cus, NULL, 3, dwfl_argv);
filenames[0] = old_filename;
err = cus__loadfl(old_cus, filenames);
if (err != 0) {
cus__print_error_msg("codiff", old_cus, old_filename, err);
return EXIT_FAILURE;
@ -737,8 +811,8 @@ failure:
/* If old_file is a character device, leave its cus empty */
if (!S_ISCHR(st.st_mode)) {
dwfl_argv[2] = new_filename;
err = cus__loadfl(new_cus, NULL, 3, dwfl_argv);
filenames[0] = new_filename;
err = cus__loadfl(new_cus, filenames);
if (err != 0) {
cus__print_error_msg("codiff", new_cus, new_filename, err);
return EXIT_FAILURE;

View File

@ -14,7 +14,6 @@
#include <string.h>
#include <limits.h>
#include <libgen.h>
#include <argp.h>
#include <zlib.h>
#include <gelf.h>
@ -38,6 +37,16 @@ static void *zalloc(const size_t size)
return s;
}
static void *tag__alloc(const size_t size)
{
struct tag *self = zalloc(size);
if (self != NULL)
self->top_level = 1;
return self;
}
static void oom(const char *msg)
{
fprintf(stderr, "libclasses: out of memory(%s)\n", msg);
@ -130,7 +139,7 @@ static void elf_symbol_iterate(struct ctf_state *sp,
}
#endif
static int parse_elf(struct ctf_state *sp)
static int parse_elf(struct ctf_state *sp, int *wordsizep)
{
GElf_Ehdr ehdr;
GElf_Shdr shdr;
@ -163,6 +172,12 @@ static int parse_elf(struct ctf_state *sp)
else
sec = elf_section_by_name(sp->elf, &ehdr, &shdr, ".symtab");
switch (ehdr.e_ident[EI_CLASS]) {
case ELFCLASS32: *wordsizep = 4; break;
case ELFCLASS64: *wordsizep = 8; break;
default: *wordsizep = 0; break;
}
if (!sec)
return 0;
@ -321,7 +336,7 @@ static void dump_funcs(struct ctf_state *sp)
static struct base_type *base_type__new(const char *name, size_t size)
{
struct base_type *self = zalloc(sizeof(*self));
struct base_type *self = tag__alloc(sizeof(*self));
if (self != NULL) {
self->name = strings__add(strings, name);
@ -330,34 +345,32 @@ static struct base_type *base_type__new(const char *name, size_t size)
return self;
}
static void type__init(struct type *self, uint16_t tag, unsigned int id,
static void type__init(struct type *self, uint16_t tag,
const char *name, size_t size)
{
INIT_LIST_HEAD(&self->node);
INIT_LIST_HEAD(&self->namespace.tags);
self->size = size;
self->namespace.tag.id = id;
self->namespace.tag.tag = tag;
self->namespace.name = strings__add(strings, name[0] == '(' ? NULL : name);
}
static struct type *type__new(uint16_t tag, unsigned int id,
const char *name, size_t size)
static struct type *type__new(uint16_t tag, const char *name, size_t size)
{
struct type *self = zalloc(sizeof(*self));
struct type *self = tag__alloc(sizeof(*self));
if (self != NULL)
type__init(self, tag, id, name, size);
type__init(self, tag, name, size);
return self;
}
static struct class *class__new(const char *name, unsigned int id, size_t size)
static struct class *class__new(const char *name, size_t size)
{
struct class *self = zalloc(sizeof(*self));
struct class *self = tag__alloc(sizeof(*self));
if (self != NULL) {
type__init(&self->type, DW_TAG_structure_type, id, name, size);
type__init(&self->type, DW_TAG_structure_type, name, size);
INIT_LIST_HEAD(&self->vtable);
}
@ -366,7 +379,7 @@ static struct class *class__new(const char *name, unsigned int id, size_t size)
static int create_new_base_type(struct ctf_state *sp, void *ptr,
int vlen __unused, struct ctf_full_type *tp,
unsigned int id)
long id)
{
uint32_t *enc = ptr, name_idx;
char name[64], *buf = name;
@ -376,8 +389,6 @@ static int create_new_base_type(struct ctf_state *sp, void *ptr,
if (attrs & CTF_TYPE_INT_SIGNED)
buf += sprintf(buf, "signed ");
if (attrs & CTF_TYPE_INT_CHAR)
buf += sprintf(buf, "char ");
if (attrs & CTF_TYPE_INT_BOOL)
buf += sprintf(buf, "bool ");
if (attrs & CTF_TYPE_INT_VARARGS)
@ -390,8 +401,7 @@ static int create_new_base_type(struct ctf_state *sp, void *ptr,
oom("base_type__new");
base->tag.tag = DW_TAG_base_type;
base->tag.id = id;
cu__add_tag(sp->cu, &base->tag);
cu__add_tag(sp->cu, &base->tag, &id);
return sizeof(*enc);
}
@ -399,7 +409,7 @@ static int create_new_base_type(struct ctf_state *sp, void *ptr,
static int create_new_base_type_float(struct ctf_state *sp, void *ptr,
int vlen __unused,
struct ctf_full_type *tp,
unsigned int id)
long id)
{
uint32_t *enc = ptr, eval;
char name[64];
@ -414,8 +424,7 @@ static int create_new_base_type_float(struct ctf_state *sp, void *ptr,
oom("base_type__new");
base->tag.tag = DW_TAG_base_type;
base->tag.id = id;
cu__add_tag(sp->cu, &base->tag);
cu__add_tag(sp->cu, &base->tag, &id);
return sizeof(*enc);
}
@ -423,10 +432,10 @@ static int create_new_base_type_float(struct ctf_state *sp, void *ptr,
static int create_new_array(struct ctf_state *sp, void *ptr,
int vlen __unused,
struct ctf_full_type *tp __unused,
unsigned int id)
long id)
{
struct ctf_array *ap = ptr;
struct array_type *self = zalloc(sizeof(*self));
struct array_type *self = tag__alloc(sizeof(*self));
if (self == NULL)
oom("array_type");
@ -441,23 +450,22 @@ static int create_new_array(struct ctf_state *sp, void *ptr,
self->nr_entries[0] = ctf__get32(sp->ctf, &ap->ctf_array_nelems);
self->tag.tag = DW_TAG_array_type;
self->tag.id = id;
self->tag.type = ctf__get16(sp->ctf, &ap->ctf_array_type);
cu__add_tag(sp->cu, &self->tag);
cu__add_tag(sp->cu, &self->tag, &id);
return sizeof(*ap);
}
static int create_new_subroutine_type(struct ctf_state *sp, void *ptr,
int vlen, struct ctf_full_type *tp,
unsigned int id)
long id)
{
uint16_t *args = ptr;
uint16_t i;
const char *name = ctf_string(ctf__get32(sp->ctf, &tp->base.ctf_name), sp);
unsigned int type = ctf__get16(sp->ctf, &tp->base.ctf_type);
struct function *self = zalloc(sizeof(*self));
struct function *self = tag__alloc(sizeof(*self));
if (self == NULL)
oom("function__new");
@ -467,12 +475,11 @@ static int create_new_subroutine_type(struct ctf_state *sp, void *ptr,
INIT_LIST_HEAD(&self->tool_node);
INIT_LIST_HEAD(&self->proto.parms);
self->proto.tag.tag = DW_TAG_subroutine_type;
self->proto.tag.id = id;
self->proto.tag.type = type;
INIT_LIST_HEAD(&self->lexblock.tags);
for (i = 0; i < vlen; i++) {
struct parameter *p = zalloc(sizeof(*p));
struct parameter *p = tag__alloc(sizeof(*p));
p->tag.tag = DW_TAG_formal_parameter;
p->tag.type = ctf__get16(sp->ctf, &args[i]);
@ -487,7 +494,7 @@ static int create_new_subroutine_type(struct ctf_state *sp, void *ptr,
if (vlen & 0x2)
vlen += 0x2;
cu__add_tag(sp->cu, &self->proto.tag);
cu__add_tag(sp->cu, &self->proto.tag, &id);
return vlen;
}
@ -513,7 +520,6 @@ static unsigned long create_full_members(struct ctf_state *sp, void *ptr,
member->offset = bit_offset / 8;
member->bit_offset = bit_offset % 8;
type__add_member(class, member);
hashtags__hash(sp->cu->hash_tags, &member->tag);
}
return sizeof(*mp);
@ -540,7 +546,6 @@ static unsigned long create_short_members(struct ctf_state *sp, void *ptr,
member->bit_offset = bit_offset % 8;
type__add_member(class, member);
hashtags__hash(sp->cu->hash_tags, &member->tag);
}
return sizeof(*mp);
@ -548,11 +553,11 @@ static unsigned long create_short_members(struct ctf_state *sp, void *ptr,
static int create_new_class(struct ctf_state *sp, void *ptr,
int vlen, struct ctf_full_type *tp,
uint64_t size, unsigned int id)
uint64_t size, long id)
{
unsigned long member_size;
const char *name = ctf_string(ctf__get32(sp->ctf, &tp->base.ctf_name), sp);
struct class *self = class__new(name, id, size);
struct class *self = class__new(name, size);
if (size >= CTF_SHORT_MEMBER_LIMIT) {
member_size = create_full_members(sp, ptr, vlen, &self->type);
@ -560,18 +565,18 @@ static int create_new_class(struct ctf_state *sp, void *ptr,
member_size = create_short_members(sp, ptr, vlen, &self->type);
}
cu__add_tag(sp->cu, &self->type.namespace.tag);
cu__add_tag(sp->cu, &self->type.namespace.tag, &id);
return (vlen * member_size);
}
static int create_new_union(struct ctf_state *sp, void *ptr,
int vlen, struct ctf_full_type *tp,
uint64_t size, unsigned int id)
uint64_t size, long id)
{
unsigned long member_size;
const char *name = ctf_string(ctf__get32(sp->ctf, &tp->base.ctf_name), sp);
struct type *self = type__new(DW_TAG_union_type, id, name, size);
struct type *self = type__new(DW_TAG_union_type, name, size);
if (size >= CTF_SHORT_MEMBER_LIMIT) {
member_size = create_full_members(sp, ptr, vlen, self);
@ -579,7 +584,7 @@ static int create_new_union(struct ctf_state *sp, void *ptr,
member_size = create_short_members(sp, ptr, vlen, self);
}
cu__add_tag(sp->cu, &self->namespace.tag);
cu__add_tag(sp->cu, &self->namespace.tag, &id);
return (vlen * member_size);
}
@ -587,7 +592,7 @@ static int create_new_union(struct ctf_state *sp, void *ptr,
static struct enumerator *enumerator__new(const char *name,
uint32_t value)
{
struct enumerator *self = zalloc(sizeof(*self));
struct enumerator *self = tag__alloc(sizeof(*self));
if (self != NULL) {
self->name = strings__add(strings, name);
@ -600,11 +605,11 @@ static struct enumerator *enumerator__new(const char *name,
static int create_new_enumeration(struct ctf_state *sp, void *ptr,
int vlen, struct ctf_full_type *tp,
unsigned int id)
long id)
{
struct ctf_enum *ep = ptr;
uint16_t i;
struct type *enumeration = type__new(DW_TAG_enumeration_type, id,
struct type *enumeration = type__new(DW_TAG_enumeration_type,
ctf_string(ctf__get32(sp->ctf,
&tp->base.ctf_name), sp),
sizeof(int)); /* FIXME: is this always the case? */
@ -621,32 +626,31 @@ static int create_new_enumeration(struct ctf_state *sp, void *ptr,
oom("enumerator__new");
enumeration__add(enumeration, enumerator);
hashtags__hash(sp->cu->hash_tags, &enumerator->tag);
}
cu__add_tag(sp->cu, &enumeration->namespace.tag);
cu__add_tag(sp->cu, &enumeration->namespace.tag, &id);
return (vlen * sizeof(*ep));
}
static int create_new_forward_decl(struct ctf_state *sp, void *ptr __unused,
int vlen __unused, struct ctf_full_type *tp,
uint64_t size, unsigned int id)
uint64_t size, long id)
{
char *name = ctf_string(ctf__get32(sp->ctf, &tp->base.ctf_name), sp);
struct class *self = class__new(name, id, size);
struct class *self = class__new(name, size);
if (self == NULL)
oom("class foward decl");
self->type.declaration = 1;
cu__add_tag(sp->cu, &self->type.namespace.tag);
cu__add_tag(sp->cu, &self->type.namespace.tag, &id);
return 0;
}
static int create_new_typedef(struct ctf_state *sp, int type,
void *ptr __unused, int vlen __unused,
struct ctf_full_type *tp,
uint64_t size, unsigned int id)
uint64_t size, long id)
{
const char *name = ctf_string(ctf__get32(sp->ctf, &tp->base.ctf_name), sp);
unsigned int type_id = ctf__get16(sp->ctf, &tp->base.ctf_type);
@ -660,18 +664,18 @@ static int create_new_typedef(struct ctf_state *sp, int type,
return 0;
}
self = type__new(tag, id, name, size);
self = type__new(tag, name, size);
if (self == NULL)
oom("type__new");
self->namespace.tag.type = type_id;
cu__add_tag(sp->cu, &self->namespace.tag);
cu__add_tag(sp->cu, &self->namespace.tag, &id);
return 0;
}
static int create_new_tag(struct ctf_state *sp, int type,
void *ptr __unused, int vlen __unused,
struct ctf_full_type *tp, unsigned int id)
struct ctf_full_type *tp, long id)
{
unsigned int type_id = ctf__get16(sp->ctf, &tp->base.ctf_type);
struct tag *self = zalloc(sizeof(*self));
@ -689,9 +693,8 @@ static int create_new_tag(struct ctf_state *sp, int type,
return 0;
}
self->id = id;
self->type = type_id;
cu__add_tag(sp->cu, self);
cu__add_tag(sp->cu, self, &id);
return 0;
}
@ -759,6 +762,7 @@ static void load_types(struct ctf_state *sp)
type == CTF_TYPE_KIND_RESTRICT) {
vlen = create_new_tag(sp, type, ptr, vlen, type_ptr, type_index);
} else if (type == CTF_TYPE_KIND_UNKN) {
cu__table_nullify_type_entry(sp->cu, type_index);
printf("CTF: [%#6x] %1d Unknown\n", type_index, CTF_ISROOT(val));
vlen = 0;
} else {
@ -788,18 +792,101 @@ static void open_files(struct ctf_state *sp, const char *in_filename)
}
}
int ctf__load(struct cus *self, struct argp *argp, int argc, char *argv[],
bool parsed)
static size_t base_type__name_to_size(struct base_type *self)
{
if (strcmp(base_type__name(self), "unsigned") == 0)
return 32;
/* FIXME */
return 0;
}
static int class__fixup_ctf_bitfields(struct tag *self, struct cu *cu)
{
struct class_member *pos;
struct type *type_self = tag__type(self);
uint16_t bit_offset = 0;
long last_offset = -1;
type__for_each_data_member(type_self, pos) {
struct tag *type = cu__find_type_by_id(cu, pos->tag.type);
if (type->tag != DW_TAG_base_type)
continue;
struct base_type *bt = tag__base_type(type);
size_t bit_size = base_type__name_to_size(bt);
if (bit_size == 0 || bt->bit_size == bit_size) {
bit_offset = 0;
last_offset = -1;
continue;
}
if (last_offset == -1)
last_offset = pos->offset;
uint16_t fixed_tag_id;
if (cu__find_base_type_by_name_and_size(cu, base_type__name(bt),
bit_size, &fixed_tag_id) == NULL) {
fprintf(stderr,
"%s: BRAIN FART ALERT!: class: %s, member: %s\n",
__func__, type__name(type_self),
class_member__name(pos));
continue;
}
pos->offset = last_offset;
pos->tag.type = fixed_tag_id;
pos->bit_size = bt->bit_size;
pos->bit_offset = bit_offset;
bit_offset += bt->bit_size;
if (bit_offset == bit_size) {
bit_offset = 0;
last_offset = -1;
}
}
return 0;
}
static int cu__fixup_ctf_bitfields(struct cu *self)
{
int err = 0;
struct tag *pos;
list_for_each_entry(pos, &self->tags, node)
if (tag__is_struct(pos)) {
err = class__fixup_ctf_bitfields(pos, self);
if (err)
break;
}
return err;
}
static int cus__fixup_ctf_bitfields(struct cus *self)
{
int err = 0;
struct cu *pos;
list_for_each_entry(pos, &self->cus, node) {
err = cu__fixup_ctf_bitfields(pos);
if (err)
break;
}
return err;
}
int ctf__load(struct cus *self, char *filenames[])
{
struct ctf_state state;
int wordsize;
memset(&state, 0, sizeof(state));
if (argc > 2 && !parsed &&
argp_parse(argp, argc - 1, argv, 0, NULL, NULL))
return -1;
open_files(&state, argv[argc - 1]);
open_files(&state, filenames[0]);
if (elf_version(EV_CURRENT) == EV_NONE) {
fprintf(stderr, "Cannot set libelf version.\n");
@ -812,10 +899,10 @@ int ctf__load(struct cus *self, struct argp *argp, int argc, char *argv[],
return -1;
}
if (parse_elf(&state))
if (parse_elf(&state, &wordsize))
return -1;
state.cu = cu__new("FIXME.c", 8, NULL, 0);
state.cu = cu__new("FIXME.c", wordsize, NULL, 0);
if (state.cu == NULL)
oom("cu__new");
@ -827,5 +914,5 @@ int ctf__load(struct cus *self, struct argp *argp, int argc, char *argv[],
close(state.in_fd);
return 0;
return cus__fixup_ctf_bitfields(self);
}

View File

@ -8,12 +8,8 @@
published by the Free Software Foundation.
*/
#include <stdbool.h>
struct cus;
struct argp;
int ctf__load(struct cus *self, struct argp *argp, int argc, char *argv[],
bool parsed);
int ctf__load(struct cus *self, char *filenames[]);
#endif /* _CTF_LOADER_H_ */

242
ctracer.c
View File

@ -125,7 +125,7 @@ static struct structure *structures__find(struct list_head *list, const char *na
return NULL;
list_for_each_entry(pos, list, node)
if (strcmp(class__name(tag__class(pos->class), pos->cu), name) == 0)
if (strcmp(class__name(tag__class(pos->class)), name) == 0)
return pos;
return NULL;
@ -165,59 +165,51 @@ static int methods__add(void **table, const char *str)
return 0;
}
static void method__add(struct cu *cu, struct function *function)
static void method__add(struct cu *cu, struct function *function, uint32_t id)
{
list_add(&function->tool_node, &cu->tool_list);
function->priv = (void *)(long)id;
}
/*
* We want just the DW_TAG_subprogram tags that have as one of its parameters
* We want just the function tags that have as one of its parameters
* a pointer to the specified "class" (a struct, unions can be added later).
*/
static struct tag *function__filter(struct tag *tag, struct cu *cu, void *cookie)
static struct function *function__filter(struct function *function,
struct cu *cu, uint16_t target_type_id)
{
struct function *function;
if (tag->tag != DW_TAG_subprogram)
return NULL;
function = tag__function(tag);
if (function__inlined(function) ||
function->abstract_origin != 0 ||
!list_empty(&function->tool_node) ||
!ftype__has_parm_of_type(&function->proto, cookie, cu))
!ftype__has_parm_of_type(&function->proto, target_type_id, cu))
return NULL;
return tag;
}
/*
* Add the function to the list of methods since it matches function__filter
* criteria.
*/
static int find_methods_iterator(struct tag *tag, struct cu *cu,
void *cookie __unused)
{
struct function *function = tag__function(tag);
method__add(cu, function);
return 0;
return function;
}
/*
* Iterate thru all the tags in the compilation unit, looking just for the
* DW_TAG_subprogram tags that have as one of its parameters a pointer to
* function tags that have as one of its parameters a pointer to
* the specified "class" (struct).
*/
static int cu_find_methods_iterator(struct cu *cu, void *cookie)
{
struct tag *target = cu__find_struct_by_name(cu, cookie, 0);
uint16_t target_type_id;
uint32_t function_id;
struct function *function;
struct tag *target = cu__find_struct_by_name(cu, cookie, 0,
&target_type_id);
INIT_LIST_HEAD(&cu->tool_list);
if (target == NULL)
return 0;
return cu__for_each_tag(cu, find_methods_iterator, target, function__filter);
cu__for_each_function(cu, function_id, function)
if (function__filter(function, cu, target_type_id))
method__add(cu, function, function_id);
return 0;
}
static struct class_member *class_member__bitfield_tail(struct class_member *head,
@ -316,8 +308,7 @@ static size_t class__find_biggest_member_name(const struct class *self)
}
static void class__emit_class_state_collector(struct class *self,
struct class *clone,
const struct cu *cu)
struct class *clone)
{
struct class_member *pos;
int len = class__find_biggest_member_name(clone);
@ -327,7 +318,7 @@ static void class__emit_class_state_collector(struct class *self,
"{\n"
"\tconst struct %s *obj = from;\n"
"\tstruct %s *mini_obj = to;\n\n",
class__name(self, cu), class__name(clone, cu));
class__name(self), class__name(clone));
type__for_each_data_member(&clone->type, pos)
fprintf(fp_collector, "\tmini_obj->%-*s = obj->%s;\n",
len, class_member__name(pos), class_member__name(pos));
@ -341,7 +332,7 @@ static int tag__is_base_type(const struct tag *self, const struct cu *cu)
return 1;
case DW_TAG_typedef: {
const struct tag *type = cu__find_tag_by_id(cu, self->type);
const struct tag *type = cu__find_type_by_id(cu, self->type);
if (type == NULL)
return 0;
@ -362,10 +353,8 @@ static struct class *class__clone_base_types(const struct tag *tag_self,
if (clone == NULL)
return NULL;
class__find_holes(clone, cu);
type__for_each_data_member_safe(&clone->type, pos, next) {
struct tag *member_type = cu__find_tag_by_id(cu, pos->tag.type);
struct tag *member_type = cu__find_type_by_id(cu, pos->tag.type);
tag__assert_search_result(member_type);
if (!tag__is_base_type(member_type, cu)) {
@ -373,7 +362,6 @@ static struct class *class__clone_base_types(const struct tag *tag_self,
class_member__delete(pos);
}
}
class__find_holes(clone, cu);
class__fixup_alignment(clone, cu);
class__reorganize(clone, cu, 0, NULL);
return clone;
@ -398,8 +386,7 @@ static void emit_struct_member_table_entry(FILE *fp,
* ostra-cg to preprocess the raw data collected from the debugfs/relay
* channel.
*/
static int class__emit_ostra_converter(struct tag *tag_self,
struct cu *cu)
static int class__emit_ostra_converter(struct tag *tag_self)
{
struct class *self = tag__class(tag_self);
struct class_member *pos;
@ -411,7 +398,7 @@ static int class__emit_ostra_converter(struct tag *tag_self,
size_t n;
size_t plen = sizeof(parm_list);
FILE *fp_fields, *fp_converter;
const char *name = class__name(self, cu);
const char *name = class__name(self);
snprintf(filename, sizeof(filename), "%s/%s.fields", src_dir, name);
fp_fields = fopen(filename, "w");
@ -489,9 +476,10 @@ static int class__emit_ostra_converter(struct tag *tag_self,
* We want just the DW_TAG_structure_type tags that have a member that is a pointer
* to the target class.
*/
static struct tag *pointer_filter(struct tag *tag, struct cu *cu, void *target_tag)
static struct tag *pointer_filter(struct tag *tag, struct cu *cu,
uint16_t target_type_id)
{
struct type *type, *target_type;
struct type *type;
struct class_member *pos;
const char *class_name;
@ -502,45 +490,40 @@ static struct tag *pointer_filter(struct tag *tag, struct cu *cu, void *target_t
if (type->nr_members == 0)
return NULL;
class_name = class__name(tag__class(tag), cu);
class_name = class__name(tag__class(tag));
if (class_name == NULL || structures__find(&pointers, class_name))
return NULL;
target_type = tag__type(target_tag);
type__for_each_member(type, pos) {
struct tag *ctype = cu__find_tag_by_id(cu, pos->tag.type);
struct tag *ctype = cu__find_type_by_id(cu, pos->tag.type);
tag__assert_search_result(ctype);
if (ctype->tag == DW_TAG_pointer_type && ctype->type == target_type->namespace.tag.id)
if (ctype->tag == DW_TAG_pointer_type &&
ctype->type == target_type_id)
return tag;
}
return NULL;
}
/*
* Add the struct to the list of pointers since it matches pointer_filter
* criteria.
*/
static int find_pointers_iterator(struct tag *tag, struct cu *cu,
void *cookie __unused)
{
structures__add(&pointers, tag, cu);
return 0;
}
/*
* Iterate thru all the tags in the compilation unit, looking for classes
* that have as one member that is a pointer to the target type.
*/
static int cu_find_pointers_iterator(struct cu *cu, void *class_name)
{
struct tag *target = cu__find_struct_by_name(cu, class_name, 0);
uint16_t target_type_id, id;
struct tag *target = cu__find_struct_by_name(cu, class_name, 0,
&target_type_id), *pos;
if (target == NULL)
return 0;
return cu__for_each_tag(cu, find_pointers_iterator, target, pointer_filter);
cu__for_each_type(cu, id, pos)
if (pointer_filter(pos, cu, target_type_id))
structures__add(&pointers, pos, cu);
return 0;
}
static void class__find_pointers(const char *class_name)
@ -552,9 +535,9 @@ static void class__find_pointers(const char *class_name)
* We want just the DW_TAG_structure_type tags that have as its first member
* a struct of type target.
*/
static struct tag *alias_filter(struct tag *tag, struct cu *cu, void *target_tag)
static struct tag *alias_filter(struct tag *tag, uint16_t target_type_id)
{
struct type *type, *target_type;
struct type *type;
struct class_member *first_member;
if (!tag__is_struct(tag))
@ -566,11 +549,10 @@ static struct tag *alias_filter(struct tag *tag, struct cu *cu, void *target_tag
first_member = list_first_entry(&type->namespace.tags,
struct class_member, tag.node);
target_type = tag__type(target_tag);
if (first_member->tag.type != target_type->namespace.tag.id)
if (first_member->tag.type != target_type_id)
return NULL;
if (structures__find(&aliases, class__name(tag__class(tag), cu)))
if (structures__find(&aliases, class__name(tag__class(tag))))
return NULL;
return tag;
@ -578,45 +560,41 @@ static struct tag *alias_filter(struct tag *tag, struct cu *cu, void *target_tag
static void class__find_aliases(const char *class_name);
/*
* Add the struct to the list of aliases since it matches alias_filter
* criteria.
*/
static int find_aliases_iterator(struct tag *tag, struct cu *cu,
void *cookie __unused)
{
const char *alias_name = class__name(tag__class(tag), cu);
structures__add(&aliases, tag, cu);
/*
* Now find aliases to this alias, e.g.:
*
* struct tcp_sock {
* struct inet_connection_sock {
* struct inet_sock {
* struct sock {
* }
* }
* }
* }
*/
class__find_aliases(alias_name);
return 0;
}
/*
* Iterate thru all the tags in the compilation unit, looking for classes
* that have as its first member the specified "class" (struct).
*/
static int cu_find_aliases_iterator(struct cu *cu, void *class_name)
{
struct tag *target = cu__find_struct_by_name(cu, class_name, 0);
uint16_t target_type_id, id;
struct tag *target = cu__find_struct_by_name(cu, class_name, 0,
&target_type_id), *pos;
if (target == NULL)
return 0;
return cu__for_each_tag(cu, find_aliases_iterator, target, alias_filter);
cu__for_each_type(cu, id, pos) {
if (alias_filter(pos, target_type_id)) {
const char *alias_name = class__name(tag__class(pos));
structures__add(&aliases, pos, cu);
/*
* Now find aliases to this alias, e.g.:
*
* struct tcp_sock {
* struct inet_connection_sock {
* struct inet_sock {
* struct sock {
* }
* }
* }
* }
*/
class__find_aliases(alias_name);
}
}
return 0;
}
static void class__find_aliases(const char *class_name)
@ -635,8 +613,7 @@ static void emit_list_of_types(struct list_head *list)
* emmited this one
*/
if (type_emissions__find_definition(&emissions,
class__name(tag__class(pos->class),
pos->cu))) {
class__name(tag__class(pos->class)))) {
type->definition_emitted = 1;
continue;
}
@ -656,7 +633,7 @@ static int class__emit_classes(struct tag *tag_self, struct cu *cu)
char mini_class_name[128];
snprintf(mini_class_name, sizeof(mini_class_name), "ctracer__mini_%s",
class__name(self, cu));
class__name(self));
mini_class = class__clone_base_types(tag_self, cu, mini_class_name);
if (mini_class == NULL)
@ -675,7 +652,7 @@ static int class__emit_classes(struct tag *tag_self, struct cu *cu)
class__fprintf(mini_class, cu, NULL, fp_classes);
fputs(";\n\n", fp_classes);
class__emit_class_state_collector(self, mini_class, cu);
class__emit_class_state_collector(self, mini_class);
err = 0;
out:
return err;
@ -688,8 +665,9 @@ out:
* This marks the function entry, function__emit_kretprobes will emit the
* probe for the function exit.
*/
static int function__emit_probes(struct function *self, const struct cu *cu,
const struct tag *target, int probe_type,
static int function__emit_probes(struct function *self, uint32_t function_id,
const struct cu *cu,
const uint16_t target_type_id, int probe_type,
const char *member)
{
struct parameter *pos;
@ -708,25 +686,22 @@ static int function__emit_probes(struct function *self, const struct cu *cu,
probe_type == 0 ? "" : "__return");
list_for_each_entry(pos, &self->proto.parms, tag.node) {
struct tag *type = cu__find_tag_by_id(cu, pos->tag.type);
struct tag *type = cu__find_type_by_id(cu, pos->tag.type);
tag__assert_search_result(type);
if (type->tag != DW_TAG_pointer_type)
continue;
type = cu__find_tag_by_id(cu, type->type);
if (type == NULL || type->id != target->id)
if (type->tag != DW_TAG_pointer_type ||
type->type != target_type_id)
continue;
if (member != NULL)
fprintf(fp_methods, "\tif ($%s)\n\t",
parameter__name(pos, cu));
parameter__name(pos));
fprintf(fp_methods,
"\tctracer__method_hook(%d, %#llx, $%s%s%s, %zd);\n",
"\tctracer__method_hook(%d, %d, $%s%s%s, %zd);\n",
probe_type,
(unsigned long long)self->proto.tag.id,
parameter__name(pos, cu),
function_id,
parameter__name(pos),
member ? "->" : "", member ?: "",
class__size(mini_class));
break;
@ -744,16 +719,18 @@ static int function__emit_probes(struct function *self, const struct cu *cu,
*/
static int cu_emit_probes_iterator(struct cu *cu, void *cookie)
{
struct tag *target = cu__find_struct_by_name(cu, cookie, 0);
uint16_t target_type_id;
struct tag *target = cu__find_struct_by_name(cu, cookie, 0, &target_type_id);
struct function *pos;
tag__assert_search_result(target);
list_for_each_entry(pos, &cu->tool_list, tool_node) {
uint32_t function_id = (long)pos->priv;
if (methods__add(&probes_emitted, function__name(pos, cu)) != 0)
continue;
pos->priv = (void *)1; /* Mark as visited, for the table iterator */
function__emit_probes(pos, cu, target, 0, NULL); /* entry */
function__emit_probes(pos, cu, target, 1, NULL); /* exit */
function__emit_probes(pos, function_id, cu, target_type_id, 0, NULL); /* entry */
function__emit_probes(pos, function_id, cu, target_type_id, 1, NULL); /* exit */
}
return 0;
@ -765,6 +742,7 @@ static int cu_emit_probes_iterator(struct cu *cu, void *cookie)
*/
static int cu_emit_pointer_probes_iterator(struct cu *cu, void *cookie)
{
uint16_t target_type_id, pointer_id;
struct tag *target, *pointer;
struct function *pos_tag;
struct class_member *pos_member;
@ -773,28 +751,29 @@ static int cu_emit_pointer_probes_iterator(struct cu *cu, void *cookie)
if (list_empty(&cu->tool_list))
return 0;
target = cu__find_struct_by_name(cu, class_name, 1);
pointer = cu__find_struct_by_name(cu, cookie, 0);
target = cu__find_struct_by_name(cu, class_name, 1, &target_type_id);
pointer = cu__find_struct_by_name(cu, cookie, 0, &pointer_id);
tag__assert_search_result(target);
tag__assert_search_result(pointer);
/* for now just for the first member that is a pointer */
type__for_each_member(tag__type(pointer), pos_member) {
struct tag *ctype = cu__find_tag_by_id(cu, pos_member->tag.type);
struct tag *ctype = cu__find_type_by_id(cu, pos_member->tag.type);
tag__assert_search_result(ctype);
if (ctype->tag == DW_TAG_pointer_type && ctype->type == target->id)
if (ctype->tag == DW_TAG_pointer_type && ctype->type == target_type_id)
break;
}
list_for_each_entry(pos_tag, &cu->tool_list, tool_node) {
uint32_t function_id = (long)pos_tag->priv;
if (methods__add(&probes_emitted, function__name(pos_tag, cu)) != 0)
continue;
pos_tag->priv = (void *)1; /* Mark as visited, for the table iterator */
function__emit_probes(pos_tag, cu, pointer, 0,
function__emit_probes(pos_tag, function_id, cu, target_type_id, 0,
class_member__name(pos_member)); /* entry */
function__emit_probes(pos_tag, cu, pointer, 1,
function__emit_probes(pos_tag, function_id, cu, target_type_id, 1,
class_member__name(pos_member)); /* exit */
}
@ -812,8 +791,8 @@ static int cu_emit_functions_table(struct cu *cu, void *fp)
list_for_each_entry(pos, &cu->tool_list, tool_node)
if (pos->priv != NULL) {
fprintf(fp, "%llu:%s\n",
(unsigned long long)pos->proto.tag.id,
uint32_t function_id = (long)pos->priv;
fprintf(fp, "%d:%s\n", function_id,
function__name(pos, cu));
pos->priv = NULL;
}
@ -821,6 +800,9 @@ static int cu_emit_functions_table(struct cu *cu, void *fp)
return 0;
}
/* Name and version of program. */
ARGP_PROGRAM_VERSION_HOOK_DEF = dwarves_print_version;
static const struct argp_option ctracer__options[] = {
{
.key = 'd',
@ -899,9 +881,8 @@ int main(int argc, char *argv[])
return EXIT_FAILURE;
}
argp_parse(&ctracer__argp, argc, argv, 0, &remaining, NULL);
if (remaining < argc) {
if (argp_parse(&ctracer__argp, argc, argv, 0, &remaining, NULL) ||
remaining < argc) {
switch (argc - remaining) {
case 1: goto failure;
case 2: filename = argv[remaining++];
@ -910,7 +891,7 @@ int main(int argc, char *argv[])
}
} else {
failure:
argp_help(&ctracer__argp, stderr, ARGP_HELP_SEE, "ctracer");
argp_help(&ctracer__argp, stderr, ARGP_HELP_SEE, argv[0]);
return EXIT_FAILURE;
}
@ -956,15 +937,14 @@ failure:
/*
* See if the specified struct exists:
*/
class = cus__find_struct_by_name(methods_cus, &cu, class_name, 0);
class = cus__find_struct_by_name(methods_cus, &cu, class_name, 0, NULL);
if (class == NULL) {
fprintf(stderr, "ctracer: struct %s not found!\n", class_name);
return EXIT_FAILURE;
}
snprintf(functions_filename, sizeof(functions_filename),
"%s/%s.functions", src_dir,
class__name(tag__class(class), cu));
"%s/%s.functions", src_dir, class__name(tag__class(class)));
fp_functions = fopen(functions_filename, "w");
if (fp_functions == NULL) {
fprintf(stderr, "ctracer: couldn't create %s\n",
@ -1017,7 +997,7 @@ failure:
class__emit_classes(class, cu);
fputc('\n', fp_collector);
class__emit_ostra_converter(class, cu);
class__emit_ostra_converter(class);
cu_blacklist = strlist__new(true);
if (cu_blacklist != NULL)
@ -1031,7 +1011,7 @@ failure:
fp_functions, cu_filter);
list_for_each_entry(pos, &aliases, node) {
const char *alias_name = class__name(tag__class(pos->class), pos->cu);
const char *alias_name = class__name(tag__class(pos->class));
cus__for_each_cu(methods_cus, cu_find_methods_iterator,
(void *)alias_name, cu_filter);
@ -1042,7 +1022,7 @@ failure:
}
list_for_each_entry(pos, &pointers, node) {
const char *pointer_name = class__name(tag__class(pos->class), pos->cu);
const char *pointer_name = class__name(tag__class(pos->class));
cus__for_each_cu(methods_cus, cu_find_methods_iterator,
(void *)pointer_name, cu_filter);
cus__for_each_cu(methods_cus, cu_emit_pointer_probes_iterator,

View File

@ -39,7 +39,7 @@ static void cus__dump_class_tag_names(struct cus *self)
cus__for_each_cu(self, cu__dump_class_tag_names, NULL, NULL);
}
int main(int argc, char *argv[])
int main(int argc __unused, char *argv[])
{
int err;
struct cus *cus = cus__new();
@ -49,7 +49,7 @@ int main(int argc, char *argv[])
return EXIT_FAILURE;
}
err = cus__loadfl(cus, NULL, argc, argv);
err = cus__loadfl(cus, argv + 1);
if (err != 0)
return EXIT_FAILURE;

17
dutil.h
View File

@ -14,6 +14,23 @@
#define __unused __attribute__ ((unused))
#endif
#ifndef __pure
#define __pure __attribute__ ((pure))
#endif
#define roundup(x,y) ((((x) + ((y) - 1)) / (y)) * (y))
/* We need define two variables, argp_program_version_hook and
argp_program_bug_address, in all programs. argp.h declares these
variables as non-const (which is correct in general). But we can
do better, it is not going to change. So we want to move them into
the .rodata section. Define macros to do the trick. */
#define ARGP_PROGRAM_VERSION_HOOK_DEF \
void (*const apvh) (FILE *, struct argp_state *) \
__asm ("argp_program_version_hook")
#define ARGP_PROGRAM_BUG_ADDRESS_DEF \
const char *const apba__ __asm ("argp_program_bug_address")
struct strlist {
void *entries;
bool dupstr;

File diff suppressed because it is too large Load Diff

View File

@ -9,10 +9,8 @@
*/
struct cus;
struct argp;
int dwarf__load_filename(struct cus *self, const char *filename);
int dwarf__load(struct cus *self, struct argp *argp, int argc, char *argv[],
bool parsed);
int dwarf__load(struct cus *self, char *filenames[]);
#endif /* _DWARF_LOADER_H_ */

634
dwarves.c

File diff suppressed because it is too large Load Diff

209
dwarves.h
View File

@ -15,34 +15,94 @@
#include <dwarf.h>
#include <elfutils/libdw.h>
#include "dutil.h"
#include "list.h"
#include "hash.h"
#include "strings.h"
extern struct strings *strings;
struct argp;
struct cus {
struct list_head cus;
};
struct cus *cus__new(void);
#define HASHTAGS__BITS 8
#define HASHTAGS__SIZE (1UL << HASHTAGS__BITS)
#define hashtags__fn(key) hash_64(key, HASHTAGS__BITS)
struct ptr_table {
void **entries;
uint32_t nr_entries;
uint32_t allocated_entries;
};
/**
* cu__for_each_type - iterate thru all the type tags
* @cu: struct cu instance to iterate
* @pos: struct tag iterator
* @id: uint16_t tag id
*
* See cu__table_nullify_type_entry and users for the reason for
* the NULL test (hint: CTF Unknown types)
*/
#define cu__for_each_type(cu, id, pos) \
for (id = 1, pos = cu->types_table.entries[id]; \
id < cu->types_table.nr_entries; \
pos = cu->types_table.entries[++id]) \
if (pos == NULL) \
continue; \
else
/**
* cu__for_each_struct - iterate thru all the struct tags
* @cu: struct cu instance to iterate
* @pos: struct class iterator
* @id: uint16_t tag id
*/
#define cu__for_each_struct(cu, id, pos) \
for (id = 0, pos = tag__class(cu->types_table.entries[id]); \
id < cu->types_table.nr_entries; \
pos = tag__class(cu->types_table.entries[++id])) \
if (pos == NULL || \
!tag__is_struct(class__tag(pos))) \
continue; \
else
/**
* cu__for_each_function - iterate thru all the function tags
* @cu: struct cu instance to iterate
* @pos: struct function iterator
* @id: uint32_t tag id
*/
#define cu__for_each_function(cu, id, pos) \
for (id = 0, pos = tag__function(cu->tags_table.entries[id]); \
id < cu->tags_table.nr_entries; \
pos = tag__function(cu->tags_table.entries[++id])) \
if (pos == NULL || \
pos->proto.tag.tag != DW_TAG_subprogram) \
continue; \
else
struct tag;
struct cu;
void hashtags__hash(struct list_head *hashtable, struct tag *tag);
struct cu_orig_info {
const char *(*tag__decl_file)(const struct tag *self,
const struct cu *cu);
uint32_t (*tag__decl_line)(const struct tag *self,
const struct cu *cu);
unsigned long long (*tag__orig_id)(const struct tag *self,
const struct cu *cu);
unsigned long long (*tag__orig_type)(const struct tag *self,
const struct cu *cu);
};
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;
struct ptr_table types_table;
struct ptr_table tags_table;
char *name;
void *priv;
struct cu_orig_info *orig_info;
uint8_t addr_size;
uint16_t language;
unsigned long nr_inline_expansions;
@ -56,16 +116,18 @@ struct cu {
unsigned char build_id[0];
};
/** struct tag - basic representation of a debug info element
* @priv - extra data, for instance, DWARF offset, id, decl_{file,line}
* @top_level -
*/
struct tag {
struct list_head node;
struct list_head hash_node;
Dwarf_Off type;
Dwarf_Off id;
strings_t decl_file;
uint16_t decl_line;
uint16_t type;
uint16_t tag;
uint16_t refcnt;
uint16_t visited:1;
uint16_t top_level:1;
uint16_t recursivity_level;
void *priv;
};
static inline int tag__is_enumeration(const struct tag *self)
@ -94,6 +156,18 @@ static inline int tag__is_union(const struct tag *self)
return self->tag == DW_TAG_union_type;
}
static inline bool tag__has_namespace(const struct tag *self)
{
return tag__is_struct(self) ||
tag__is_union(self) ||
tag__is_namespace(self) ||
tag__is_enumeration(self);
}
/**
* tag__is_tag_type - is this tag derived from the 'type' class?
* @tag - tag queried
*/
static inline int tag__is_type(const struct tag *self)
{
return tag__is_union(self) ||
@ -101,10 +175,47 @@ static inline int tag__is_type(const struct tag *self)
tag__is_typedef(self) ||
tag__is_enumeration(self);
}
static inline const char *tag__decl_file(const struct tag *self)
/**
* tag__is_tag_type - is this one of the possible types for a tag?
* @tag - tag queried
*/
static inline int tag__is_tag_type(const struct tag *self)
{
return strings__ptr(strings, self->decl_file);
return tag__is_type(self) ||
tag__is_enumeration(self) ||
self->tag == DW_TAG_array_type ||
self->tag == DW_TAG_base_type ||
self->tag == DW_TAG_const_type ||
self->tag == DW_TAG_pointer_type ||
self->tag == DW_TAG_ptr_to_member_type ||
self->tag == DW_TAG_reference_type ||
self->tag == DW_TAG_subroutine_type ||
self->tag == DW_TAG_volatile_type;
}
static inline const char *tag__decl_file(const struct tag *self,
const struct cu *cu)
{
return cu->orig_info ? cu->orig_info->tag__decl_file(self, cu) : NULL;
}
static inline uint32_t tag__decl_line(const struct tag *self,
const struct cu *cu)
{
return cu->orig_info ? cu->orig_info->tag__decl_line(self, cu) : 0;
}
static inline unsigned long long tag__orig_id(const struct tag *self,
const struct cu *cu)
{
return cu->orig_info ? cu->orig_info->tag__orig_id(self, cu) : 0;
}
static inline unsigned long long tag__orig_type(const struct tag *self,
const struct cu *cu)
{
return cu->orig_info ? cu->orig_info->tag__orig_type(self, cu) : 0;
}
struct ptr_to_member_type {
@ -271,12 +382,14 @@ 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)
static __pure inline const char *type__name(const struct type *self)
{
return type__name(&self->type, cu);
return strings__ptr(strings, self->namespace.name);
}
static __pure inline const char *class__name(struct class *self)
{
return strings__ptr(strings, self->type.namespace.name);
}
static inline int class__is_struct(const struct class *self)
@ -417,6 +530,11 @@ static inline struct tag *function__tag(const struct function *self)
return (struct tag *)self;
}
static __pure inline int tag__is_function(const struct tag *self)
{
return self->tag == DW_TAG_subprogram;
}
/**
* function__for_each_parameter - iterate thru all the parameters
* @self: struct function instance to iterate
@ -436,8 +554,10 @@ 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);
static inline const char *parameter__name(const struct parameter *self)
{
return strings__ptr(strings, self->name);
}
enum vlocation {
LOCATION_UNKNOWN,
@ -478,8 +598,14 @@ struct label {
struct tag tag;
strings_t name;
Dwarf_Addr low_pc;
Dwarf_Off abstract_origin;
};
static inline struct label *tag__label(const struct tag *self)
{
return (struct label *)self;
}
struct enumerator {
struct tag tag;
strings_t name;
@ -513,11 +639,11 @@ 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);
size_t tag__fprintf_decl_info(const struct tag *self,
const struct cu *cu, FILE *fp);
extern size_t tag__fprintf(struct tag *self, const struct cu *cu,
const struct conf_fprintf *conf, FILE *fp);
@ -539,8 +665,7 @@ extern size_t lexblock__fprintf(const struct lexblock *self,
const struct cu *cu, struct function *function,
uint16_t indent, FILE *fp);
extern int cus__loadfl(struct cus *self, struct argp *argp,
int argc, char *argv[]);
extern int cus__loadfl(struct cus *self, char *filenames[]);
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);
@ -550,11 +675,17 @@ extern void cus__print_error_msg(const char *progname, const struct cus *cus,
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);
const char *name,
uint16_t *id);
struct tag *cu__find_base_type_by_name_and_size(const struct cu *self,
const char *name,
size_t bit_size,
uint16_t *id);
extern struct tag *cus__find_struct_by_name(const struct cus *self,
struct cu **cu,
const char *name,
const int include_decls);
const int include_decls,
uint16_t *id);
extern struct tag *cus__find_function_by_name(const struct cus *self,
struct cu **cu,
const char *name);
@ -565,14 +696,18 @@ 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);
int cu__add_tag(struct cu *self, struct tag *tag, long *id);
int cu__table_add_tag(struct cu *self, struct tag *tag, long *id);
int cu__table_nullify_type_entry(struct cu *self, uint32_t id);
extern struct tag *cu__find_tag_by_id(const struct cu *self,
const Dwarf_Off id);
const uint32_t id);
struct tag *cu__find_type_by_id(const struct cu *self, const uint16_t 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);
const int include_decls,
uint16_t *id);
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,
@ -620,7 +755,7 @@ extern size_t ftype__fprintf(const struct ftype *self, const struct cu *cu,
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 uint16_t target,
const struct cu *cu);
void type__add_member(struct type *self, struct class_member *member);
@ -678,4 +813,8 @@ extern const char *variable__type_name(const struct variable *self,
extern const char *dwarf_tag_name(const uint32_t tag);
struct argp_state;
void dwarves_print_version(FILE *fp, struct argp_state *state);
#endif /* _DWARVES_H_ */

View File

@ -47,8 +47,8 @@ struct type *type_emissions__find_definition(const struct type_emissions *self,
return NULL;
list_for_each_entry(pos, &self->definitions, node)
if (type__name(pos, NULL) != NULL &&
strcmp(type__name(pos, NULL), name) == 0)
if (type__name(pos) != NULL &&
strcmp(type__name(pos), name) == 0)
return pos;
return NULL;
@ -60,14 +60,13 @@ static struct type *type_emissions__find_fwd_decl(const struct type_emissions *s
struct type *pos;
list_for_each_entry(pos, &self->fwd_decls, node)
if (strcmp(type__name(pos, NULL), name) == 0)
if (strcmp(type__name(pos), name) == 0)
return pos;
return NULL;
}
static int enumeration__emit_definitions(struct tag *self,
const struct cu *cu,
struct type_emissions *emissions,
const struct conf_fprintf *conf,
FILE *fp)
@ -80,7 +79,7 @@ static int enumeration__emit_definitions(struct tag *self,
/* Ok, lets look at the previous CUs: */
if (type_emissions__find_definition(emissions,
type__name(etype, cu)) != NULL) {
type__name(etype)) != NULL) {
/*
* Yes, so lets mark it visited on this CU too,
* to speed up the lookup.
@ -89,7 +88,7 @@ static int enumeration__emit_definitions(struct tag *self,
return 0;
}
enumeration__fprintf(self, cu, conf, fp);
enumeration__fprintf(self, conf, fp);
fputs(";\n", fp);
type_emissions__add_definition(emissions, etype);
return 1;
@ -111,7 +110,7 @@ static int typedef__emit_definitions(struct tag *tdef, struct cu *cu,
/* Ok, lets look at the previous CUs: */
if (type_emissions__find_definition(emissions,
type__name(def, cu)) != NULL) {
type__name(def)) != NULL) {
/*
* Yes, so lets mark it visited on this CU too,
* to speed up the lookup.
@ -120,7 +119,7 @@ static int typedef__emit_definitions(struct tag *tdef, struct cu *cu,
return 0;
}
type = cu__find_tag_by_id(cu, tdef->type);
type = cu__find_type_by_id(cu, tdef->type);
tag__assert_search_result(type);
switch (type->tag) {
@ -131,7 +130,7 @@ static int typedef__emit_definitions(struct tag *tdef, struct cu *cu,
typedef__emit_definitions(type, cu, emissions, fp);
break;
case DW_TAG_pointer_type:
ptr_type = cu__find_tag_by_id(cu, type->type);
ptr_type = cu__find_type_by_id(cu, type->type);
tag__assert_search_result(ptr_type);
if (ptr_type->tag != DW_TAG_subroutine_type)
break;
@ -147,23 +146,23 @@ static int typedef__emit_definitions(struct tag *tdef, struct cu *cu,
.suffix = NULL,
};
if (type__name(ctype, cu) == NULL) {
if (type__name(ctype) == NULL) {
fputs("typedef ", fp);
conf.suffix = type__name(def, cu);
enumeration__emit_definitions(type, cu, emissions, &conf, fp);
conf.suffix = type__name(def);
enumeration__emit_definitions(type, emissions, &conf, fp);
goto out;
} else
enumeration__emit_definitions(type, cu, emissions, &conf, fp);
enumeration__emit_definitions(type, emissions, &conf, fp);
}
break;
case DW_TAG_structure_type:
case DW_TAG_union_type: {
struct type *ctype = tag__type(type);
if (type__name(ctype, cu) == NULL) {
if (type__name(ctype) == NULL) {
if (type__emit_definitions(type, cu, emissions, fp))
type__emit(type, cu, "typedef",
type__name(def, cu), fp);
type__name(def), fp);
goto out;
} else if (type__emit_definitions(type, cu, emissions, fp))
type__emit(type, cu, NULL, NULL, fp);
@ -187,7 +186,7 @@ out:
return 1;
}
int type__emit_fwd_decl(struct type *ctype, const struct cu *cu,
int type__emit_fwd_decl(struct type *ctype,
struct type_emissions *emissions, FILE *fp)
{
/* Have we already emitted this in this CU? */
@ -196,7 +195,7 @@ int type__emit_fwd_decl(struct type *ctype, const struct cu *cu,
/* Ok, lets look at the previous CUs: */
if (type_emissions__find_fwd_decl(emissions,
type__name(ctype, cu)) != NULL) {
type__name(ctype)) != NULL) {
/*
* Yes, so lets mark it visited on this CU too,
* to speed up the lookup.
@ -207,7 +206,7 @@ int type__emit_fwd_decl(struct type *ctype, const struct cu *cu,
fprintf(fp, "%s %s;\n",
tag__is_union(&ctype->namespace.tag) ? "union" : "struct",
type__name(ctype, cu));
type__name(ctype));
type_emissions__add_fwd_decl(emissions, ctype);
return 1;
}
@ -215,7 +214,7 @@ int type__emit_fwd_decl(struct type *ctype, const struct cu *cu,
static int tag__emit_definitions(struct tag *self, struct cu *cu,
struct type_emissions *emissions, FILE *fp)
{
struct tag *type = cu__find_tag_by_id(cu, self->type);
struct tag *type = cu__find_type_by_id(cu, self->type);
int pointer = 0;
if (type == NULL)
@ -229,26 +228,25 @@ next_indirection:
case DW_TAG_array_type:
case DW_TAG_const_type:
case DW_TAG_volatile_type:
type = cu__find_tag_by_id(cu, type->type);
type = cu__find_type_by_id(cu, type->type);
if (type == NULL)
return 0;
goto next_indirection;
case DW_TAG_typedef:
return typedef__emit_definitions(type, cu, emissions, fp);
case DW_TAG_enumeration_type:
if (type__name(tag__type(type), cu) != NULL) {
if (type__name(tag__type(type)) != NULL) {
struct conf_fprintf conf = {
.suffix = NULL,
};
return enumeration__emit_definitions(type, cu,
emissions,
return enumeration__emit_definitions(type, emissions,
&conf, fp);
}
break;
case DW_TAG_structure_type:
case DW_TAG_union_type:
if (pointer)
return type__emit_fwd_decl(tag__type(type), cu,
return type__emit_fwd_decl(tag__type(type),
emissions, fp);
if (type__emit_definitions(type, cu, emissions, fp))
type__emit(type, cu, NULL, NULL, fp);
@ -289,7 +287,7 @@ int type__emit_definitions(struct tag *self, struct cu *cu,
/* Ok, lets look at the previous CUs: */
if (type_emissions__find_definition(emissions,
type__name(ctype, cu)) != NULL) {
type__name(ctype)) != NULL) {
ctype->definition_emitted = 1;
return 0;
}
@ -308,10 +306,7 @@ void type__emit(struct tag *tag_self, struct cu *cu,
{
struct type *ctype = tag__type(tag_self);
if (tag__is_struct(tag_self))
class__find_holes(tag__class(tag_self), cu);
if (type__name(ctype, cu) != NULL ||
if (type__name(ctype) != NULL ||
suffix != NULL || prefix != NULL) {
struct conf_fprintf conf = {
.prefix = prefix,

View File

@ -29,7 +29,7 @@ int ftype__emit_definitions(struct ftype *self, struct cu *cu,
struct type_emissions *emissions, FILE *fp);
int type__emit_definitions(struct tag *self, struct cu *cu,
struct type_emissions *emissions, FILE *fp);
int type__emit_fwd_decl(struct type *ctype, const struct cu *cu,
int type__emit_fwd_decl(struct type *ctype,
struct type_emissions *emissions, FILE *fp);
void type__emit(struct tag *tag_self, struct cu *cu,
const char *prefix, const char *suffix, FILE *fp);

View File

@ -446,7 +446,8 @@ static void class__demote_bitfield_members(struct class *class,
struct class_member *from,
struct class_member *to,
const struct base_type *old_type,
const struct base_type *new_type)
const struct base_type *new_type,
uint16_t new_type_id)
{
const uint8_t bit_diff = old_type->bit_size - new_type->bit_size;
struct class_member *member =
@ -459,7 +460,7 @@ static void class__demote_bitfield_members(struct class *class,
* Assume IA32 bitfield layout
*/
member->bit_offset -= bit_diff;
member->tag.type = new_type->tag.id;
member->tag.type = new_type_id;
if (member == to)
break;
member->bit_hole = 0;
@ -467,28 +468,34 @@ static void class__demote_bitfield_members(struct class *class,
}
static struct tag *cu__find_base_type_of_size(const struct cu *cu,
const size_t size)
const size_t size, uint16_t *id)
{
const char *type_name;
const char *type_name, *type_name_alt = NULL;
switch (size) {
case sizeof(unsigned char):
type_name = "unsigned char"; break;
case sizeof(unsigned short int):
type_name = "short unsigned int"; break;
type_name = "short unsigned int";
type_name = "unsigned short"; break;
case sizeof(unsigned int):
type_name = "unsigned int"; break;
type_name = "unsigned int";
type_name_alt = "unsigned"; break;
case sizeof(unsigned long long):
if (cu->addr_size == 8)
if (cu->addr_size == 8) {
type_name = "long unsigned int";
else
type_name_alt = "unsigned long";
} else {
type_name = "long long unsigned int";
type_name_alt = "unsigned long long";
}
break;
default:
return NULL;
}
return cu__find_base_type_by_name(cu, type_name);
struct tag *ret = cu__find_base_type_by_name(cu, type_name, id);
return ret ?: cu__find_base_type_by_name(cu, type_name_alt, id);
}
static int class__demote_bitfields(struct class *class, const struct cu *cu,
@ -537,8 +544,10 @@ static int class__demote_bitfields(struct class *class, const struct cu *cu,
if (bytes_needed == size)
continue;
old_type_tag = cu__find_tag_by_id(cu, member->tag.type);
new_type_tag = cu__find_base_type_of_size(cu, bytes_needed);
uint16_t new_type_id;
old_type_tag = cu__find_type_by_id(cu, member->tag.type);
new_type_tag = cu__find_base_type_of_size(cu, bytes_needed,
&new_type_id);
if (new_type_tag == NULL) {
fprintf(fp, "/* BRAIN FART ALERT! couldn't find a "
@ -556,7 +565,8 @@ static int class__demote_bitfields(struct class *class, const struct cu *cu,
class__demote_bitfield_members(class,
bitfield_head, member,
tag__base_type(old_type_tag),
tag__base_type(new_type_tag));
tag__base_type(new_type_tag),
new_type_id);
new_size = class_member__size(member, cu);
member->hole = size - new_size;
if (member->hole != 0)
@ -586,9 +596,11 @@ static int class__demote_bitfields(struct class *class, const struct cu *cu,
bytes_needed = (member->bit_size + 7) / 8;
if (bytes_needed < size) {
old_type_tag =
cu__find_tag_by_id(cu, member->tag.type);
cu__find_type_by_id(cu, member->tag.type);
uint16_t new_type_id;
new_type_tag =
cu__find_base_type_of_size(cu, bytes_needed);
cu__find_base_type_of_size(cu, bytes_needed,
&new_type_id);
tag__assert_search_result(old_type_tag);
tag__assert_search_result(new_type_tag);
@ -602,7 +614,8 @@ static int class__demote_bitfields(struct class *class, const struct cu *cu,
class__demote_bitfield_members(class,
member, member,
tag__base_type(old_type_tag),
tag__base_type(new_type_tag));
tag__base_type(new_type_tag),
new_type_id);
new_size = class_member__size(member, cu);
member->hole = 0;
/*
@ -661,7 +674,7 @@ restart:
static void class__fixup_bitfield_types(struct class *self,
struct class_member *from,
struct class_member *to_before,
Dwarf_Off type)
uint16_t type)
{
struct class_member *member =
list_prepare_entry(from, class__tags(self), tag.node);
@ -727,9 +740,11 @@ static void class__fixup_member_types(struct class *self, const struct cu *cu,
const size_t size = class_member__size(bitfield_head,
cu);
if (real_size != size) {
uint16_t new_type_id;
struct tag *new_type_tag =
cu__find_base_type_of_size(cu,
real_size);
real_size,
&new_type_id);
if (new_type_tag == NULL) {
fprintf(stderr, "pahole: couldn't find"
" a base_type of %d bytes!\n",
@ -738,7 +753,7 @@ static void class__fixup_member_types(struct class *self, const struct cu *cu,
}
class__fixup_bitfield_types(self,
bitfield_head, pos,
new_type_tag->id);
new_type_id);
fixup_was_done = 1;
}
}

201
man-pages/pahole.1 Normal file
View File

@ -0,0 +1,201 @@
.\" Man page for pahole
.\" Arnaldo Carvalho de Melo, 2009
.\" Licensed under version 2 of the GNU General Public License.
.TH pahole 1 "February 13, 2009" "dwarves" "dwarves"
.\"
.SH NAME
pahole \- Shows and manipulates data structure layout.
.SH SYNOPSIS
\fBpahole\fR [\fIoptions\fR] \fIfiles\fR
.SH DESCRIPTION
.B pahole
shows data structure layouts encoded in debugging information formats,
DWARF and CTF being supported.
This is useful for, among other things: optimizing important data structures by
reducing its size, figuring out what is the field sitting at an offset from the
start of a data structure, investigating ABI changes and more generally
understanding a new codebase you have to work with.
The files must have associated debugging information. This information may be
inside the file itself, in ELF sections, or in another file.
One way to have this information is to specify the \fB\-g\fR option to the
compiler when building it. When this is done the information will be stored in
an ELF section. For the DWARF debugging information format this, adds, among
others, the \fB.debug_info\fR ELF section. For the CTF it is found in just one
ELF section, \fB.SUNW_ctf\fR.
The \fBdebuginfo\fR packages available in most Linux distributions are also
supported by \fBpahole\fR, where the debugging information is available in a
separate file.
By default, \fBpahole\fR shows the layout of all named structs in the files
specified.
.SH OPTIONS
pahole supports the following options.
.TP
.B \-C, \-\-class_name=CLASS_NAME
Show just this class.
.TP
.B \-c, \-\-cacheline_size=SIZE
Set cacheline size to SIZE bytes.
.TP
.B \-E, \-\-expand_types
Expand class members. Useful to find in what member of inner structs where an
offset from the beginning of a struct is.
.TP
.B \-r, \-\-rel_offset
Show relative offsets of members in inner structs.
.TP
.B \-p, \-\-expand_pointers
Expand class pointer members.
.TP
.B \-R, \-\-reorganize
Reorganize struct, demoting and combining bitfields, moving members to remove
alignment holes and padding.
.TP
.B \-S, \-\-show_reorg_steps
Show the struct layout at each reorganization step.
.TP
.B \-i, \-\-contains=CLASS_NAME
Show classes that contains CLASS_NAME.
.TP
.B \-a, \-\-anon_include
Include anonymous classes.
.TP
.B \-A, \-\-nested_anon_include
Include nested (inside other structs) anonymous classes.
.TP
.B \-B, \-\-bit_holes=NR_HOLES
Show only structs at least NR_HOLES bit holes.
.TP
.B \-d, \-\-recursive
Recursive mode, affects several other flags.
.TP
.B \-D, \-\-decl_exclude=PREFIX
exclude classes declared in files with PREFIX.
.TP
.B \-f, \-\-find_pointers_to=CLASS_NAME
Find pointers to CLASS_NAME.
.TP
.B \-H, \-\-holes=NR_HOLES
Show only structs with at least NR_HOLES holes.
.TP
.B \-I, \-\-show_decl_info
Show the file and line number where the tags were defined, if available in
the debugging information.
.TP
.B \-l, \-\-show_first_biggest_size_base_type_member
Show first biggest size base_type member.
.TP
.B \-m, \-\-nr_methods
Show number of methods.
.TP
.B \-M, \-\-show_only_data_members
Show only the members that use space in the class layout. C++ methods will be
suppressed.
.TP
.B \-n, \-\-nr_members
Show number of members.
.TP
.B \-N, \-\-class_name_len
Show size of classes.
.TP
.B \-O, \-\-dwarf_offset=OFFSET
Show tag with DWARF OFFSET.
.TP
.B \-P, \-\-packable
Show only structs that has holes that can be packed if members are reorganized,
for instance when using the \fB\-\-reorganize\fR option.
.TP
.B \-q, \-\-quiet
Be quieter.
.TP
.B \-s, \-\-sizes
Show size of classes.
.TP
.B \-t, \-\-separator=SEP
Use SEP as the field separator.
.TP
.B \-T, \-\-nr_definitions
Show how many times struct was defined.
.TP
.B \-u, \-\-defined_in
Show CUs where CLASS_NAME (-C) is defined.
.TP
.B \-V, \-\-verbose
be verbose
.TP
.B \-w, \-\-word_size=WORD_SIZE
Change the arch word size to WORD_SIZE.
.TP
.B \-x, \-\-exclude=PREFIX
Exclude PREFIXed classes.
.TP
.B \-X, \-\-cu_exclude=PREFIX
Exclude PREFIXed compilation units.
.TP
.B \-y, \-\-prefix_filter=PREFIX
Include PREFIXed classes.
.TP
.B \-z, \-\-hole_size_ge=HOLE_SIZE
Show only structs with at least one hole greater or equal to HOLE_SIZE.
.SH NOTES
To enable the generation of debugging information in the Linux kernel build
process select CONFIG_DEBUG_INFO. This can be done using make menuconfig by
this path: "Kernel Hacking" -> "Kernel Debugging" -> "Compile the kernel with
debug info".
Many distributions also come with debuginfo packages, so just enable it in your
package manager repository configuration and install the kernel-debuginfo, or
any other userspace program written in a language that the compiler generates
debuginfo (C, C++, for instance).
.SH SEE ALSO
\fIeu-readelf\fR(1), \fIreadelf\fR(1), \fIobjdump\fR(1).
.P
\fIhttp://oops.ghostprotocols.net:81/acme/7dwarves.pdf\fR.
.SH AUTHOR
\fBpahole\fR was written by Arnaldo Carvalho de Melo <acme@ghostprotocols.net>.
Please send bug reports to <dwarves@vger.kernel.org>.
.P
No\ subscription is required.

200
pahole.c
View File

@ -63,9 +63,10 @@ struct structure {
const struct cu *cu;
uint32_t nr_files;
uint32_t nr_methods;
uint16_t id;
};
static struct structure *structure__new(struct class *class,
static struct structure *structure__new(struct class *class, uint16_t id,
const struct cu *cu)
{
struct structure *self = malloc(sizeof(*self));
@ -75,6 +76,7 @@ static struct structure *structure__new(struct class *class,
self->cu = cu;
self->nr_files = 1;
self->nr_methods = 0;
self->id = id;
}
return self;
@ -84,9 +86,10 @@ static void *structures__tree;
static LIST_HEAD(structures__anonymous_list);
static LIST_HEAD(structures__named_list);
static void structures__add_anonymous(struct class *class, const struct cu *cu)
static void structures__add_anonymous(struct class *class, uint16_t id,
const struct cu *cu)
{
struct structure *str = structure__new(class, cu);
struct structure *str = structure__new(class, id, cu);
if (str != NULL)
list_add_tail(&str->node, &structures__anonymous_list);
@ -100,7 +103,8 @@ static int structure__compare(const void *a, const void *b)
return strings__cmp(strings, *key, pos->class->type.namespace.name);
}
static int structures__add_named(struct class *class, const struct cu *cu)
static int structures__add_named(struct class *class, uint16_t id,
const struct cu *cu)
{
struct structure *str;
strings_t *s = tsearch(&class->type.namespace.name, &structures__tree,
@ -113,7 +117,7 @@ static int structures__add_named(struct class *class, const struct cu *cu)
* calling structures__add_named */
assert(*s != class->type.namespace.name);
str = structure__new(class, cu);
str = structure__new(class, id, cu);
if (str == NULL)
return -ENOMEM;
@ -125,17 +129,15 @@ static int structures__add_named(struct class *class, const struct cu *cu)
return 0;
}
static int structures__add(struct class *class, const struct cu *cu)
static int structures__add(struct class *class, uint16_t id,
const struct cu *cu)
{
/* Let it follow abstract_origin, etc */
class__name(class, cu);
if (!class->type.namespace.name) {
structures__add_anonymous(class, cu);
structures__add_anonymous(class, id, cu);
return 0;
}
return structures__add_named(class, cu);
return structures__add_named(class, id, cu);
}
static struct structure *structures__find_anonymous(strings_t name)
@ -143,19 +145,17 @@ static struct structure *structures__find_anonymous(strings_t name)
struct structure *pos;
list_for_each_entry(pos, &structures__anonymous_list, node) {
struct class *c = pos->class;
const struct tag *tdef = cu__find_first_typedef_of_type(pos->cu, class__tag(c)->id);
struct class *c;
const struct tag *tdef = cu__find_first_typedef_of_type(pos->cu, pos->id);
if (tdef == NULL)
continue;
c = tag__class(tdef);
/* Let it follow abstract_origin, etc */
class__name(c, pos->cu);
if (c->type.namespace.name == name)
return pos;
}
if (c->type.namespace.name == name)
return pos;
}
return NULL;
}
@ -178,45 +178,45 @@ static struct structure *structures__find(strings_t name)
static void nr_definitions_formatter(struct structure *self)
{
printf("%s%c%u\n", class__name(self->class, self->cu), separator,
printf("%s%c%u\n", class__name(self->class), separator,
self->nr_files);
}
static void nr_members_formatter(struct structure *self)
{
printf("%s%c%u\n", class__name(self->class, self->cu), separator,
printf("%s%c%u\n", class__name(self->class), separator,
class__nr_members(self->class));
}
static void nr_methods_formatter(struct structure *self)
{
printf("%s%c%u\n", class__name(self->class, self->cu), separator,
printf("%s%c%u\n", class__name(self->class), separator,
self->nr_methods);
}
static void size_formatter(struct structure *self)
{
printf("%s%c%zd%c%u\n", class__name(self->class, self->cu), separator,
printf("%s%c%zd%c%u\n", class__name(self->class), separator,
class__size(self->class), separator,
self->class->nr_holes);
}
static void class_name_len_formatter(struct structure *self)
{
const char *name = class__name(self->class, self->cu);
const char *name = class__name(self->class);
printf("%s%c%zd\n", name, separator, strlen(name));
}
static void class_name_formatter(struct structure *self)
{
puts(class__name(self->class, self->cu));
puts(class__name(self->class));
}
static void class_formatter(struct structure *self)
{
struct tag *typedef_alias = NULL;
struct tag *tag = class__tag(self->class);
const char *name = class__name(self->class, self->cu);
const char *name = class__name(self->class);
if (name == NULL) {
/*
@ -225,7 +225,7 @@ static void class_formatter(struct structure *self)
* affected.
*/
typedef_alias = cu__find_first_typedef_of_type(self->cu,
tag->id);
self->id);
/*
* If there is no typedefs for this anonymous struct it is
* found just inside another struct, and in this case it'll
@ -241,7 +241,7 @@ static void class_formatter(struct structure *self)
struct type *tdef = tag__type(typedef_alias);
conf.prefix = "typedef";
conf.suffix = type__name(tdef, self->cu);
conf.suffix = type__name(tdef);
} else
conf.prefix = conf.suffix = NULL;
@ -260,15 +260,15 @@ static void print_packable_info(struct structure *pos)
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, pos->cu);
const char *name = class__name(c);
/* Anonymous struct? Try finding a typedef */
if (name == NULL) {
const struct tag *tdef =
cu__find_first_typedef_of_type(pos->cu, t->id);
cu__find_first_typedef_of_type(pos->cu, pos->id);
if (tdef != NULL)
name = class__name(tag__class(tdef), pos->cu);
name = class__name(tag__class(tdef));
}
if (name != NULL)
printf("%s%c%zd%c%zd%c%zd\n",
@ -278,7 +278,8 @@ static void print_packable_info(struct structure *pos)
savings);
else
printf("%s(%d)%c%zd%c%zd%c%zd\n",
tag__decl_file(t), t->decl_line,
tag__decl_file(t, pos->cu),
tag__decl_line(t, pos->cu),
separator,
orig_size, separator,
new_size, separator,
@ -346,7 +347,7 @@ static void class__dupmsg(struct class *self, const struct cu *cu,
if (!*hdr)
printf("class: %s\nfirst: %s\ncurrent: %s\n",
class__name(self, cu), cu->name, dup_cu->name);
class__name(self), cu->name, dup_cu->name);
va_start(args, fmt);
vprintf(fmt, args);
@ -391,7 +392,7 @@ static void class__chkdupdef(struct class *self, const struct cu *cu,
}
static struct tag *tag__filter(struct tag *tag, struct cu *cu,
void *cookie __unused)
uint16_t tag_id)
{
struct structure *str;
struct class *class;
@ -401,8 +402,11 @@ static struct tag *tag__filter(struct tag *tag, struct cu *cu,
if (!tag__is_struct(tag))
return NULL;
if (!tag->top_level)
return NULL;
class = tag__class(tag);
name = class__name(class, cu);
name = class__name(class);
stname = class->type.namespace.name;
if (class__is_declaration(class))
@ -414,15 +418,14 @@ static struct tag *tag__filter(struct tag *tag, struct cu *cu,
if (class__exclude_prefix != NULL) {
if (name == NULL) {
const struct tag *tdef =
cu__find_first_typedef_of_type(cu, tag->id);
cu__find_first_typedef_of_type(cu, tag_id);
if (tdef != NULL) {
struct class *c = tag__class(tdef);
name = class__name(c, cu);
name = class__name(c);
stname = c->type.namespace.name;
}
}
if (name != NULL && strncmp(class__exclude_prefix, name,
class__exclude_prefix_len) == 0)
return NULL;
@ -431,15 +434,14 @@ static struct tag *tag__filter(struct tag *tag, struct cu *cu,
if (class__include_prefix != NULL) {
if (name == NULL) {
const struct tag *tdef =
cu__find_first_typedef_of_type(cu, tag->id);
cu__find_first_typedef_of_type(cu, tag_id);
if (tdef != NULL) {
struct class *c = tag__class(tdef);
name = class__name(c, cu);
name = class__name(c);
stname = c->type.namespace.name;
}
}
if (name != NULL && strncmp(class__include_prefix, name,
class__include_prefix_len) != 0)
return NULL;
@ -447,13 +449,11 @@ static struct tag *tag__filter(struct tag *tag, struct cu *cu,
if (decl_exclude_prefix != NULL &&
(!tag->decl_file ||
strncmp(decl_exclude_prefix, tag__decl_file(tag),
(!tag__decl_file(tag, cu) ||
strncmp(decl_exclude_prefix, tag__decl_file(tag, cu),
decl_exclude_prefix_len) == 0))
return NULL;
class__find_holes(class, cu);
if (class->nr_holes < nr_holes ||
class->nr_bit_holes < nr_bit_holes ||
(hole_size_ge != 0 && !class__has_hole_ge(class, hole_size_ge)))
@ -473,28 +473,27 @@ static struct tag *tag__filter(struct tag *tag, struct cu *cu,
return tag;
}
static int unique_iterator(struct tag *tag, struct cu *cu,
void *cookie __unused)
static int cu_unique_iterator(struct cu *cu, void *cookie __unused)
{
if (structures__add(tag__class(tag), cu)) {
fprintf(stderr, "pahole: not enough memory! "
"Continuing with partial results\n");
return -1;
uint16_t id;
struct tag *tag;
if (defined_in) {
tag = cu__find_struct_by_name(cu, class_name, 0, &id);
if (tag != NULL)
puts(cu->name);
} else {
cu__for_each_type(cu, id, tag) {
if (tag__filter(tag, cu, id) &&
structures__add(tag__class(tag), id, cu))
fprintf(stderr, "pahole: not enough memory! "
"Continuing with partial results\n");
}
}
return 0;
}
static int cu_unique_iterator(struct cu *cu, void *cookie)
{
if (defined_in) {
struct tag *tag = cu__find_struct_by_name(cu, class_name, 0);
if (tag != NULL)
puts(cu->name);
} else
return cu__for_each_tag(cu, unique_iterator, cookie, tag__filter);
return 0;
}
static strings_t long_int_str_t, long_unsigned_int_str_t;
static void union__find_new_size(struct tag *tag, struct cu *cu);
@ -525,14 +524,14 @@ static void class__resize_LP(struct tag *tag, struct cu *cu)
tag_pos->tag != DW_TAG_inheritance)
continue;
type = cu__find_tag_by_id(cu, tag_pos->type);
type = cu__find_type_by_id(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__find_tag_by_id(cu, type->type);
type = cu__find_type_by_id(cu, type->type);
tag__assert_search_result(type);
}
@ -545,8 +544,8 @@ static void class__resize_LP(struct tag *tag, struct cu *cu)
case DW_TAG_base_type: {
struct base_type *bt = tag__base_type(type);
if (strcmp(base_type__name(bt), "long int") != 0 &&
strcmp(base_type__name(bt), "long unsigned int") != 0)
if (bt->name != long_int_str_t &&
bt->name != long_unsigned_int_str_t)
break;
/* fallthru */
}
@ -606,7 +605,7 @@ static void union__find_new_size(struct tag *tag, struct cu *cu)
tag_pos->tag != DW_TAG_inheritance)
continue;
type = cu__find_tag_by_id(cu, tag_pos->type);
type = cu__find_type_by_id(cu, tag_pos->type);
tag__assert_search_result(type);
if (tag__is_typedef(type))
type = tag__follow_typedef(type, cu);
@ -651,8 +650,8 @@ static int tag_fixup_word_size_iterator(struct tag *tag, struct cu *cu,
if (!bt->name)
return 0;
if (strcmp(base_type__name(bt), "long int") == 0 ||
strcmp(base_type__name(bt), "long unsigned int") == 0)
if (bt->name == long_int_str_t ||
bt->name == long_unsigned_int_str_t)
bt->bit_size = word_size * 8;
}
break;
@ -667,17 +666,17 @@ static int tag_fixup_word_size_iterator(struct tag *tag, struct cu *cu,
return 0;
}
static int cu_fixup_word_size_iterator(struct cu *cu, void *cookie)
static int cu_fixup_word_size_iterator(struct cu *cu, void *cookie __unused)
{
original_word_size = cu->addr_size;
cu->addr_size = word_size;
return cu__for_each_tag(cu, tag_fixup_word_size_iterator, cookie, NULL);
return cu__for_each_tag(cu, tag_fixup_word_size_iterator, NULL, NULL);
}
static struct tag *nr_methods__filter(struct tag *tag, struct cu *cu __unused,
void *cookie __unused)
{
if (tag->tag != DW_TAG_subprogram)
if (!tag__is_function(tag))
return NULL;
if (function__declared_inline(tag__function(tag)))
@ -694,21 +693,19 @@ static int nr_methods_iterator(struct tag *tag, struct cu *cu,
struct type *ctype;
list_for_each_entry(pos, &tag__ftype(tag)->parms, tag.node) {
struct tag *type =
cu__find_tag_by_id(cu, parameter__type(pos, cu));
struct tag *type = cu__find_type_by_id(cu, pos->tag.type);
if (type == NULL || type->tag != DW_TAG_pointer_type)
continue;
type = cu__find_tag_by_id(cu, type->type);
type = cu__find_type_by_id(cu, type->type);
if (type == NULL || !tag__is_struct(type))
continue;
ctype = tag__type(type);
if (type__name(ctype, cu) == NULL)
if (type__name(ctype) == NULL)
continue;
type__name(ctype, cu); /* Resolution of abstract_origin, etc */
str = structures__find(ctype->namespace.name);
if (str != NULL)
++str->nr_methods;
@ -728,8 +725,8 @@ static char tab[128];
static void print_structs_with_pointer_to(const struct structure *s)
{
struct structure *pos_structure;
Dwarf_Off type;
const char *class_name = class__name(s->class, s->cu);
uint16_t type;
const char *class_name = class__name(s->class);
const struct cu *current_cu = NULL;
list_for_each_entry(pos_structure, &structures__named_list, node) {
@ -737,21 +734,24 @@ static void print_structs_with_pointer_to(const struct structure *s)
struct class_member *pos_member;
if (pos_structure->cu != current_cu) {
uint16_t class_id;
struct tag *class;
class = cu__find_struct_by_name(pos_structure->cu, class_name, 1);
class = cu__find_struct_by_name(pos_structure->cu,
class_name, 1,
&class_id);
if (class == NULL)
continue;
current_cu = pos_structure->cu;
type = class->id;
type = class_id;
}
type__for_each_member(&c->type, pos_member) {
struct tag *ctype = cu__find_tag_by_id(pos_structure->cu, pos_member->tag.type);
struct tag *ctype = cu__find_type_by_id(pos_structure->cu, pos_member->tag.type);
tag__assert_search_result(ctype);
if (ctype->tag == DW_TAG_pointer_type && ctype->type == type)
printf("%s: %s\n", class__name(c, pos_structure->cu),
printf("%s: %s\n", class__name(c),
class_member__name(pos_member));
}
}
@ -760,14 +760,14 @@ static void print_structs_with_pointer_to(const struct structure *s)
static void print_containers(const struct structure *s, int ident)
{
struct structure *pos;
const Dwarf_Off type = s->class->type.namespace.tag.id;
const uint16_t type = s->id;
list_for_each_entry(pos, &structures__named_list, node) {
struct class *c = pos->class;
const uint32_t n = type__nr_members_of_type(&c->type, type);
if (n != 0) {
printf("%.*s%s", ident * 2, tab, class__name(c, pos->cu));
printf("%.*s%s", ident * 2, tab, class__name(c));
if (global_verbose)
printf(": %u", n);
putchar('\n');
@ -777,6 +777,9 @@ static void print_containers(const struct structure *s, int ident)
}
}
/* Name and version of program. */
ARGP_PROGRAM_VERSION_HOOK_DEF = dwarves_print_version;
static const struct argp_option pahole__options[] = {
{
.name = "bit_holes",
@ -1044,7 +1047,7 @@ static struct argp pahole__argp = {
int main(int argc, char *argv[])
{
int err;
int err, remaining;
struct cus *cus = cus__new();
if (dwarves__init(cacheline_size) || cus == NULL) {
@ -1052,12 +1055,31 @@ int main(int argc, char *argv[])
return EXIT_FAILURE;
}
err = cus__loadfl(cus, &pahole__argp, argc, argv);
if (err != 0)
return EXIT_FAILURE;
if (argp_parse(&pahole__argp, argc, argv, 0, &remaining, NULL) ||
remaining == argc) {
argp_help(&pahole__argp, stderr, ARGP_HELP_SEE, argv[0]);
return EXIT_FAILURE;
}
err = cus__loadfl(cus, argv + remaining);
if (err != 0) {
fputs("pahole: No debugging information found\n", stderr);
return EXIT_FAILURE;
}
if (word_size != 0) {
long_int_str_t = strings__find(strings, "long int"),
long_unsigned_int_str_t =
strings__find(strings, "long unsigned int");
if (long_int_str_t == 0 || long_unsigned_int_str_t == 0) {
fputs("pahole: couldn't find one of \"long int\" or "
"\"long unsigned int\" types", stderr);
return EXIT_FAILURE;
}
if (word_size != 0)
cus__for_each_cu(cus, cu_fixup_word_size_iterator, NULL, NULL);
}
if (class_dwarf_offset != 0) {
struct cu *cu;

View File

@ -18,46 +18,40 @@ static struct conf_fprintf conf = {
.emit_stats = 1,
};
static int emit_tag(struct tag *self, struct cu *cu, void *cookie __unused)
static void emit_tag(struct tag *self, uint32_t tag_id, struct cu *cu)
{
if (self->tag != DW_TAG_array_type &&
self->tag != DW_TAG_const_type &&
self->tag != DW_TAG_formal_parameter &&
self->tag != DW_TAG_reference_type &&
self->tag != DW_TAG_subroutine_type &&
self->tag != DW_TAG_volatile_type) {
if (tag__is_struct(self))
class__find_holes(tag__class(self), cu);
conf.no_semicolon = tag__is_function(self);
conf.no_semicolon = self->tag == DW_TAG_subprogram;
printf("%d ", tag_id);
printf("%lld ", (unsigned long long)self->id);
if (self->tag == DW_TAG_base_type) {
const char *name = base_type__name(tag__base_type(self));
if (self->tag == DW_TAG_base_type) {
const char *name = base_type__name(tag__base_type(self));
if (name == NULL)
printf("anonymous base_type\n");
else
puts(name);
} else if (self->tag == DW_TAG_pointer_type)
printf("pointer to %lld\n", (unsigned long long)self->type);
if (name == NULL)
printf("anonymous base_type\n");
else
tag__fprintf(self, cu, &conf, stdout);
puts(name);
} else if (self->tag == DW_TAG_pointer_type)
printf("pointer to %lld\n", (unsigned long long)self->type);
else
tag__fprintf(self, cu, &conf, stdout);
if (self->tag == DW_TAG_subprogram) {
struct function *fn = tag__function(self);
putchar('\n');
lexblock__fprintf(&fn->lexblock, cu, fn, 0, stdout);
}
puts("\n");
if (tag__is_function(self)) {
struct function *fn = tag__function(self);
putchar('\n');
lexblock__fprintf(&fn->lexblock, cu, fn, 0, stdout);
}
return 0;
puts("\n");
}
static int cu__emit_tags(struct cu *self, void *cookie __unused)
{
cu__for_each_tag(self, emit_tag, NULL, NULL);
uint16_t i;
for (i = 1; i < self->types_table.nr_entries; ++i) {
struct tag *tag = self->types_table.entries[i];
emit_tag(tag, i, self);
}
return 0;
}
@ -66,6 +60,9 @@ static void cus__emit_tags(struct cus *self)
cus__for_each_cu(self, cu__emit_tags, NULL, NULL);
}
/* Name and version of program. */
ARGP_PROGRAM_VERSION_HOOK_DEF = dwarves_print_version;
static const struct argp_option pdwtags__options[] = {
{
.key = 'V',
@ -101,7 +98,7 @@ static struct argp pdwtags__argp = {
int main(int argc, char *argv[])
{
int err;
int err, remaining;
struct cus *cus = cus__new();
if (dwarves__init(0) || cus == NULL) {
@ -109,7 +106,13 @@ int main(int argc, char *argv[])
return EXIT_FAILURE;
}
err = cus__loadfl(cus, &pdwtags__argp, argc, argv);
if (argp_parse(&pdwtags__argp, argc, argv, 0, &remaining, NULL) ||
remaining == argc) {
argp_help(&pdwtags__argp, stderr, ARGP_HELP_SEE, argv[0]);
return EXIT_FAILURE;
}
err = cus__loadfl(cus, argv + remaining);
if (err != 0)
return EXIT_FAILURE;

View File

@ -215,7 +215,10 @@ static struct tag *function__filter(struct tag *tag, struct cu *cu,
struct fn_stats *fstats;
const char *name;
if (tag->tag != DW_TAG_subprogram)
if (!tag__is_function(tag))
return NULL;
if (!tag->top_level)
return NULL;
function = tag__function(tag);
@ -258,7 +261,7 @@ static struct tag *function__filter(struct tag *tag, struct cu *cu,
static int unique_iterator(struct tag *tag, struct cu *cu,
void *cookie __unused)
{
if (tag->tag == DW_TAG_subprogram)
if (tag__is_function(tag))
fn_stats__add(tag, cu);
return 0;
}
@ -271,16 +274,17 @@ static int cu_unique_iterator(struct cu *cu, void *cookie)
static int class_iterator(struct tag *tag, struct cu *cu, void *cookie)
{
uint16_t *target_id = cookie;
struct function *function;
if (tag->tag != DW_TAG_subprogram)
if (!tag__is_function(tag))
return 0;
function = tag__function(tag);
if (function->inlined)
return 0;
if (ftype__has_parm_of_type(&function->proto, cookie, cu)) {
if (ftype__has_parm_of_type(&function->proto, *target_id, cu)) {
if (verbose)
tag__fprintf(tag, cu, &conf, stdout);
else
@ -292,12 +296,13 @@ static int class_iterator(struct tag *tag, struct cu *cu, void *cookie)
static int cu_class_iterator(struct cu *cu, void *cookie)
{
struct tag *target = cu__find_struct_by_name(cu, cookie, 0);
uint16_t target_id;
struct tag *target = cu__find_struct_by_name(cu, cookie, 0, &target_id);
if (target == NULL)
return 0;
return cu__for_each_tag(cu, class_iterator, target, NULL);
return cu__for_each_tag(cu, class_iterator, &target_id, NULL);
}
static int function__emit_type_definitions(struct function *self,
@ -306,13 +311,13 @@ static int function__emit_type_definitions(struct function *self,
struct parameter *pos;
function__for_each_parameter(self, pos) {
struct tag *type = cu__find_tag_by_id(cu, parameter__type(pos, cu));
struct tag *type = cu__find_type_by_id(cu, pos->tag.type);
try_again:
if (type == NULL)
continue;
if (type->tag == DW_TAG_pointer_type) {
type = cu__find_tag_by_id(cu, type->type);
type = cu__find_type_by_id(cu, type->type);
goto try_again;
}
@ -330,7 +335,7 @@ static int function_iterator(struct tag *tag, struct cu *cu, void *cookie)
{
struct function *function;
if (tag->tag != DW_TAG_subprogram)
if (!tag__is_function(tag))
return 0;
function = tag__function(tag);
@ -351,6 +356,9 @@ static int cu_function_iterator(struct cu *cu, void *cookie)
return cu__for_each_tag(cu, function_iterator, cookie, NULL);
}
/* Name and version of program. */
ARGP_PROGRAM_VERSION_HOOK_DEF = dwarves_print_version;
static const struct argp_option pfunct__options[] = {
{
.key = 'b',
@ -491,7 +499,7 @@ static struct argp pfunct__argp = {
int main(int argc, char *argv[])
{
int err;
int err, remaining;
struct cus *cus = cus__new();
if (dwarves__init(0) || cus == NULL) {
@ -499,7 +507,13 @@ int main(int argc, char *argv[])
return EXIT_FAILURE;
}
err = cus__loadfl(cus, &pfunct__argp, argc, argv);
if (argp_parse(&pfunct__argp, argc, argv, 0, &remaining, NULL) ||
remaining == argc) {
argp_help(&pfunct__argp, stderr, ARGP_HELP_SEE, argv[0]);
return EXIT_FAILURE;
}
err = cus__loadfl(cus, argv + remaining);
if (err != 0)
return EXIT_FAILURE;

View File

@ -139,7 +139,7 @@ static struct tag *extfun__filter(struct tag *tag, struct cu *cu __unused,
{
struct function *fun;
if (tag->tag != DW_TAG_subprogram)
if (!tag__is_function(tag))
return NULL;
fun = tag__function(tag);
@ -264,6 +264,9 @@ static void free_node(void *nodep)
free(*node);
}
/* Name and version of program. */
ARGP_PROGRAM_VERSION_HOOK_DEF = dwarves_print_version;
static const struct argp_option pglobal__options[] = {
{
.key = 'v',
@ -313,7 +316,7 @@ static struct argp pglobal__argp = {
int main(int argc, char *argv[])
{
int err;
int err, remaining;
struct cus *cus = cus__new();
if (dwarves__init(0) || cus == NULL) {
@ -321,7 +324,13 @@ int main(int argc, char *argv[])
return EXIT_FAILURE;
}
err = cus__loadfl(cus, &pglobal__argp, argc, argv);
if (argp_parse(&pglobal__argp, argc, argv, 0, &remaining, NULL) ||
remaining == argc) {
argp_help(&pglobal__argp, stderr, ARGP_HELP_SEE, argv[0]);
return EXIT_FAILURE;
}
err = cus__loadfl(cus, argv + remaining);
if (err != 0)
return EXIT_FAILURE;

View File

@ -24,7 +24,7 @@ static void refcnt_member(struct class_member *member, const struct cu *cu)
return;
member->visited = 1;
if (member->tag.type != 0) { /* if not void */
struct tag *type = cu__find_tag_by_id(cu, member->tag.type);
struct tag *type = cu__find_type_by_id(cu, member->tag.type);
if (type != NULL)
refcnt_tag(type, cu);
}
@ -34,7 +34,7 @@ static void refcnt_parameter(const struct parameter *parameter,
const struct cu *cu)
{
if (parameter->tag.type != 0) { /* if not void */
struct tag *type = cu__find_tag_by_id(cu, parameter->tag.type);
struct tag *type = cu__find_type_by_id(cu, parameter->tag.type);
if (type != NULL)
refcnt_tag(type, cu);
}
@ -44,7 +44,7 @@ static void refcnt_variable(const struct variable *variable,
const struct cu *cu)
{
if (variable->tag.type != 0) { /* if not void */
struct tag *type = cu__find_tag_by_id(cu, variable->tag.type);
struct tag *type = cu__find_type_by_id(cu, variable->tag.type);
if (type != NULL)
refcnt_tag(type, cu);
}
@ -64,7 +64,7 @@ static void refcnt_tag(struct tag *tag, const struct cu *cu)
{
struct class_member *member;
tag->refcnt++;
tag->visited = 1;
if (tag__is_struct(tag) || tag__is_union(tag))
type__for_each_member(tag__type(tag), member)
@ -93,11 +93,11 @@ static void refcnt_function(struct function *function, const struct cu *cu)
{
struct parameter *parameter;
function->proto.tag.refcnt++;
function->proto.tag.visited = 1;
if (function->proto.tag.type != 0) /* if not void */ {
struct tag *type =
cu__find_tag_by_id(cu, function->proto.tag.type);
cu__find_type_by_id(cu, function->proto.tag.type);
if (type != NULL)
refcnt_tag(type, cu);
}
@ -118,9 +118,7 @@ static int refcnt_function_iterator(struct function *function,
static int refcnt_tag_iterator(struct tag *tag, struct cu *cu, void *cookie)
{
if (tag__is_struct(tag))
class__find_holes(tag__class(tag), cu);
else if (tag->tag == DW_TAG_subprogram)
if (tag__is_function(tag))
refcnt_function_iterator(tag__function(tag), cu, cookie);
return 0;
@ -135,7 +133,7 @@ static int cu_refcnt_iterator(struct cu *cu, void *cookie)
static int lost_iterator(struct tag *tag, struct cu *cu,
void *cookie __unused)
{
if (tag->refcnt == 0 && tag->decl_file) {
if (!tag->visited && tag__decl_file(tag, cu)) {
tag__fprintf(tag, cu, NULL, stdout);
puts(";\n");
}
@ -147,7 +145,7 @@ static int cu_lost_iterator(struct cu *cu, void *cookie)
return cu__for_each_tag(cu, lost_iterator, cookie, NULL);
}
int main(int argc, char *argv[])
int main(int argc __unused, char *argv[])
{
int err;
struct cus *cus = cus__new();
@ -157,7 +155,7 @@ int main(int argc, char *argv[])
return EXIT_FAILURE;
}
err = cus__loadfl(cus, NULL, argc, argv);
err = cus__loadfl(cus, argv + 1);
if (err != 0)
return EXIT_FAILURE;

View File

@ -2,13 +2,13 @@
%define libver 1
Name: dwarves
Version: 1.6
Release: 1
Version: 1.7
Release: 2
License: GPLv2
Summary: Dwarf Tools
Group: Development/Tools
URL: http://oops.ghostprotocols.net:81/blog
Source: http://userweb.kernel.org/~acme/dwarves/%{name}-%{version}.tar.bz2
Source: http://fedorapeople.org/~acme/dwarves/%{name}-%{version}.tar.bz2
BuildRequires: cmake
BuildRequires: elfutils-devel >= 0.130
BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
@ -82,9 +82,11 @@ rm -rf %{buildroot}
%{_bindir}/prefcnt
%{_bindir}/syscse
%{_bindir}/ostra-cg
%dir %{_datadir}/dwarves/
%dir %{_datadir}/dwarves/runtime/
%dir %{_datadir}/dwarves/runtime/python/
%defattr(0644,root,root,0755)
%{_mandir}/man1/pahole.1*
%{_datadir}/dwarves/runtime/Makefile
%{_datadir}/dwarves/runtime/linux.blacklist.cu
%{_datadir}/dwarves/runtime/ctracer_relay.c
@ -108,6 +110,24 @@ rm -rf %{buildroot}
%{_libdir}/%{libname}_reorganize.so
%changelog
* Fri Feb 13 2009 Arnaldo Carvalho de Melo <acme@redhat.com> - 1.7-2
- Own /usr/share/dwarves, fixes #473645
* Fri Feb 13 2009 Arnaldo Carvalho de Melo <acme@redhat.com> - 1.7-1
- A CTF decoder based on work done by David S. Miller
- Handle DW_TAG_class_type,
- Add support for showing classes with a prefix
- Add support to DW_TAG_ptr_to_member_type
- Handle typedef definitions in functions
- Print the number of members in a struct/class
- Handle the empty base optimization trick (Zero sized C++ class)
- codiff detect changes in the prototype even when function size doesn't change
- pfunct: Implement --expand_types
- Reduce memory consumption by using a strings table
- Speed up struct search by name
- Several minor bug fixes and infrastructure improvements.
- Initial man page for pahole
* Mon Feb 11 2008 Arnaldo Carvalho de Melo <acme@redhat.com> - 1.6-1
- c83d935a4fd561a3807f520c126c2a61ae1f4d83
- [DWARVES]: Use a hash table for the tags in a CU

View File

@ -23,7 +23,7 @@ static size_t prefix_len = 4;
static struct tag *filter(struct tag *self, struct cu *cu,
void *cookie __unused)
{
if (self->tag == DW_TAG_subprogram) {
if (tag__is_function(self)) {
struct function *f = tag__function(self);
if (f->proto.nr_parms != 0) {
@ -68,8 +68,8 @@ static int emit_wrapper(struct tag *self, struct cu *cu, void *cookie __unused)
int regparm = 0, needs_wrapper = 0;
function__for_each_parameter(f, parm) {
const Dwarf_Off type_id = parameter__type(parm, cu);
struct tag *type = cu__find_tag_by_id(cu, type_id);
const uint16_t type_id = parm->tag.type;
struct tag *type = cu__find_type_by_id(cu, type_id);
tag__assert_search_result(type);
if (type->tag == DW_TAG_base_type) {
@ -81,8 +81,7 @@ static int emit_wrapper(struct tag *self, struct cu *cu, void *cookie __unused)
printf("wrap_%s:\n", name);
needs_wrapper = 1;
}
zero_extend(regparm, bt,
parameter__name(parm, cu));
zero_extend(regparm, bt, parameter__name(parm));
}
}
++regparm;
@ -105,6 +104,9 @@ static void cus__emit_wrapper(struct cus *self)
cus__for_each_cu(self, cu__emit_wrapper, NULL, NULL);
}
/* Name and version of program. */
ARGP_PROGRAM_VERSION_HOOK_DEF = dwarves_print_version;
static const struct argp_option options[] = {
{
.key = 'p',
@ -144,7 +146,7 @@ static struct argp argp = {
int main(int argc, char *argv[])
{
int err;
int err, remaining;
struct cus *cus = cus__new();
if (cus == NULL) {
@ -152,7 +154,12 @@ int main(int argc, char *argv[])
return EXIT_FAILURE;
}
err = cus__loadfl(cus, &argp, argc, argv);
if (argp_parse(&argp, argc, argv, 0, &remaining, NULL) ||
remaining == argc) {
argp_help(&argp, stderr, ARGP_HELP_SEE, argv[0]);
return EXIT_FAILURE;
}
err = cus__loadfl(cus, argv + remaining);
if (err != 0)
return EXIT_FAILURE;