From f6eb9ed92dafbd8cac082737fe0352c0ff6e7fdc Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 12 Jan 2008 13:14:40 -0200 Subject: [PATCH] [PAHOLE]: Allow changing the architecture word-size Using a x86_64 binary: [acme@doppio pahole]$ build/pahole -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 8 */ union { struct { long unsigned int arg0; /* 8 8 */ long unsigned int arg1; /* 16 8 */ long unsigned int arg2; /* 24 8 */ long unsigned int arg3; /* 32 8 */ }; /* 32 */ struct { u32 * uaddr; /* 8 8 */ u32 val; /* 16 4 */ u32 flags; /* 20 4 */ u64 time; /* 24 8 */ } fu; /* 24 */ }; /* 8 32 */ /* size: 40, cachelines: 1 */ /* last cacheline: 40 bytes */ }; Changing the word-size from 8 to 4 bytes: [acme@doppio pahole]$ build/pahole -w 4 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 4 */ union { struct { long unsigned int arg0; /* 4 4 */ long unsigned int arg1; /* 8 4 */ long unsigned int arg2; /* 12 4 */ long unsigned int arg3; /* 16 4 */ }; /* 16 */ struct { u32 * uaddr; /* 4 4 */ u32 val; /* 8 4 */ u32 flags; /* 12 4 */ u64 time; /* 16 8 */ } fu; /* 20 */ }; /* 4 20 */ /* size: 24, cachelines: 1 */ /* last cacheline: 24 bytes */ }; And from 8 to 16: [acme@doppio pahole]$ build/pahole -w 16 -C restart_block /usr/lib/debug/lib/modules/2.6.21-65.el5rt/kernel/drivers/net/e1000/e1000.ko.debug struct restart_block { long int (*fn)(struct restart_block *); /* 0 16 */ union { struct { long unsigned int arg0; /* 16 16 */ long unsigned int arg1; /* 32 16 */ long unsigned int arg2; /* 48 16 */ long unsigned int arg3; /* 64 16 */ /* --- cacheline 1 boundary (64 bytes) --- */ }; /* 64 */ struct { u32 * uaddr; /* 16 16 */ u32 val; /* 32 4 */ u32 flags; /* 36 4 */ u64 time; /* 40 8 */ } fu; /* 32 */ }; /* 16 64 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ /* size: 80, cachelines: 2 */ /* last cacheline: 16 bytes */ }; More work is required to specify different alignment rules. Signed-off-by: Arnaldo Carvalho de Melo --- dwarves.h | 1 + pahole.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 139 insertions(+) diff --git a/dwarves.h b/dwarves.h index f5edb65..ee64b7f 100644 --- a/dwarves.h +++ b/dwarves.h @@ -107,6 +107,7 @@ struct type { struct list_head node; Dwarf_Off specification; size_t size; + size_t size_diff; uint16_t nr_members; uint8_t declaration; /* only one bit used */ uint8_t definition_emitted:1; diff --git a/pahole.c b/pahole.c index 4de68f4..cc0c3f5 100644 --- a/pahole.c +++ b/pahole.c @@ -21,6 +21,7 @@ static uint8_t class__include_anonymous; static uint8_t class__include_nested_anonymous; +static uint8_t word_size, original_word_size; static char *class__exclude_prefix; static size_t class__exclude_prefix_len; @@ -387,6 +388,133 @@ static int cu_unique_iterator(struct cu *cu, void *cookie) return cu__for_each_tag(cu, unique_iterator, cookie, tag__filter); } +static void class__resize_LP(struct tag *tag, struct cu *cu) +{ + struct tag *tag_pos; + struct class *self = tag__class(tag); + size_t word_size_diff; + size_t orig_size = self->type.size; + + if (original_word_size > word_size) + word_size_diff = original_word_size - word_size; + else + word_size_diff = word_size - original_word_size; + + type__for_each_tag(tag__type(tag), tag_pos) { + struct tag *type; + size_t diff = 0; + + /* we want only data members, i.e. with byte_offset attr */ + if (tag_pos->tag != DW_TAG_member && + tag_pos->tag != DW_TAG_inheritance) + continue; + + type = cu__find_tag_by_id(cu, tag_pos->type); + switch (type->tag) { + case DW_TAG_base_type: { + struct base_type *bt = tag__base_type(type); + + if (strcmp(bt->name, "long int") != 0 && + strcmp(bt->name, "long unsigned int") != 0) + break; + /* fallthru */ + } + case DW_TAG_pointer_type: + diff = word_size_diff; + break; + case DW_TAG_structure_type: + case DW_TAG_union_type: + diff = tag__type(type)->size_diff; + break; + } + + if (diff != 0) { + struct class_member *m = tag__class_member(tag_pos); + if (original_word_size > word_size) { + self->type.size -= diff; + class__subtract_offsets_from(self, cu, m, diff); + } else { + self->type.size += diff; + class__add_offsets_from(self, m, diff); + } + } + } + + if (original_word_size > word_size) + tag__type(tag)->size_diff = orig_size - self->type.size; + else + tag__type(tag)->size_diff = self->type.size - orig_size; + + class__fixup_alignment(self, cu); +} + +static void union__find_new_size(struct tag *tag, struct cu *cu) +{ + struct tag *tag_pos; + struct type *self = tag__type(tag); + size_t max_size = 0; + + type__for_each_tag(self, tag_pos) { + struct tag *type; + size_t size; + + /* we want only data members, i.e. with byte_offset attr */ + if (tag_pos->tag != DW_TAG_member && + tag_pos->tag != DW_TAG_inheritance) + continue; + + type = cu__find_tag_by_id(cu, tag_pos->type); + size = tag__size(type, cu); + if (size > max_size) + max_size = size; + } + + if (max_size > self->size) + self->size_diff = max_size - self->size; + else + self->size_diff = self->size - max_size; + + self->size = max_size; +} + +static int tag_fixup_word_size_iterator(struct tag *tag, struct cu *cu, + void *cookie) +{ + if (tag->tag == DW_TAG_structure_type || + tag->tag == DW_TAG_union_type) { + struct tag *pos; + + namespace__for_each_tag(tag__namespace(tag), pos) + tag_fixup_word_size_iterator(pos, cu, cookie); + } + + switch (tag->tag) { + case DW_TAG_base_type: { + struct base_type *bt = tag__base_type(tag); + + if (strcmp(bt->name, "long int") == 0 || + strcmp(bt->name, "long unsigned int") == 0) + bt->size = word_size; + } + break; + case DW_TAG_structure_type: + class__resize_LP(tag, cu); + break; + case DW_TAG_union_type: + union__find_new_size(tag, cu); + break; + } + + return 0; +} + +static int cu_fixup_word_size_iterator(struct cu *cu, void *cookie) +{ + original_word_size = cu->addr_size; + cu->addr_size = word_size; + return cu__for_each_tag(cu, tag_fixup_word_size_iterator, cookie, NULL); +} + static struct tag *nr_methods__filter(struct tag *tag, struct cu *cu __unused, void *cookie __unused) { @@ -651,6 +779,12 @@ static const struct argp_option pahole__options[] = { .key = 'V', .doc = "be verbose", }, + { + .name = "word_size", + .key = 'w', + .arg = "WORD_SIZE", + .doc = "change the arch word size to WORD_SIZE" + }, { .name = NULL, } @@ -696,6 +830,7 @@ static error_t pahole__options_parser(int key, char *arg, case 'T': formatter = nr_definitions_formatter; break; case 't': separator = arg[0]; break; case 'V': global_verbose = 1; break; + case 'w': word_size = atoi(arg); break; case 'X': cu__exclude_prefix = arg; cu__exclude_prefix_len = strlen(cu__exclude_prefix); break; @@ -738,6 +873,9 @@ int main(int argc, char *argv[]) dwarves__init(cacheline_size); + if (word_size != 0) + cus__for_each_cu(cus, cu_fixup_word_size_iterator, NULL, NULL); + if (class_dwarf_offset != 0) { struct cu *cu; struct tag *tag = cus__find_tag_by_id(cus, &cu,