Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/acme/pahole
This commit is contained in:
commit
9f05162b3f
|
@ -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
|
||||
|
|
6
MANIFEST
6
MANIFEST
|
@ -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
162
codiff.c
|
@ -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;
|
||||
|
|
209
ctf_loader.c
209
ctf_loader.c
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
242
ctracer.c
|
@ -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,
|
||||
|
|
|
@ -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
17
dutil.h
|
@ -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;
|
||||
|
|
903
dwarf_loader.c
903
dwarf_loader.c
File diff suppressed because it is too large
Load Diff
|
@ -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_ */
|
||||
|
|
207
dwarves.h
207
dwarves.h
|
@ -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) ||
|
||||
|
@ -102,9 +176,46 @@ static inline int tag__is_type(const struct tag *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_ */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
200
pahole.c
|
@ -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;
|
||||
|
|
65
pdwtags.c
65
pdwtags.c
|
@ -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;
|
||||
|
||||
|
|
36
pfunct.c
36
pfunct.c
|
@ -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;
|
||||
|
||||
|
|
15
pglobal.c
15
pglobal.c
|
@ -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;
|
||||
|
||||
|
|
22
prefcnt.c
22
prefcnt.c
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
21
syscse.c
21
syscse.c
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue