dwarves/dwarves.c

2600 lines
65 KiB
C
Raw Normal View History

/*
Copyright (C) 2006 Mandriva Conectiva S.A.
Copyright (C) 2006 Arnaldo Carvalho de Melo <acme@mandriva.com>
Copyright (C) 2007 Red Hat Inc.
Copyright (C) 2007 Arnaldo Carvalho de Melo <acme@redhat.com>
This program is free software; you can redistribute it and/or modify it
under the terms of version 2 of the GNU General Public License as
published by the Free Software Foundation.
*/
#include <assert.h>
#include <dirent.h>
#include <dwarf.h>
#include <argp.h>
#include <errno.h>
#include <fcntl.h>
#include <fnmatch.h>
#include <libelf.h>
#include <search.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "config.h"
#include "ctf_loader.h"
#include "dwarf_loader.h"
#include "list.h"
#include "dwarves.h"
#include "dutil.h"
static const char *dwarf_tag_names[] = {
[DW_TAG_array_type] = "array_type",
[DW_TAG_class_type] = "class_type",
[DW_TAG_entry_point] = "entry_point",
[DW_TAG_enumeration_type] = "enumeration_type",
[DW_TAG_formal_parameter] = "formal_parameter",
[DW_TAG_imported_declaration] = "imported_declaration",
[DW_TAG_label] = "label",
[DW_TAG_lexical_block] = "lexical_block",
[DW_TAG_member] = "member",
[DW_TAG_pointer_type] = "pointer_type",
[DW_TAG_reference_type] = "reference_type",
[DW_TAG_compile_unit] = "compile_unit",
[DW_TAG_string_type] = "string_type",
[DW_TAG_structure_type] = "structure_type",
[DW_TAG_subroutine_type] = "subroutine_type",
[DW_TAG_typedef] = "typedef",
[DW_TAG_union_type] = "union_type",
[DW_TAG_unspecified_parameters] = "unspecified_parameters",
[DW_TAG_variant] = "variant",
[DW_TAG_common_block] = "common_block",
[DW_TAG_common_inclusion] = "common_inclusion",
[DW_TAG_inheritance] = "inheritance",
[DW_TAG_inlined_subroutine] = "inlined_subroutine",
[DW_TAG_module] = "module",
[DW_TAG_ptr_to_member_type] = "ptr_to_member_type",
[DW_TAG_set_type] = "set_type",
[DW_TAG_subrange_type] = "subrange_type",
[DW_TAG_with_stmt] = "with_stmt",
[DW_TAG_access_declaration] = "access_declaration",
[DW_TAG_base_type] = "base_type",
[DW_TAG_catch_block] = "catch_block",
[DW_TAG_const_type] = "const_type",
[DW_TAG_constant] = "constant",
[DW_TAG_enumerator] = "enumerator",
[DW_TAG_file_type] = "file_type",
[DW_TAG_friend] = "friend",
[DW_TAG_namelist] = "namelist",
[DW_TAG_namelist_item] = "namelist_item",
[DW_TAG_packed_type] = "packed_type",
[DW_TAG_subprogram] = "subprogram",
[DW_TAG_template_type_parameter] = "template_type_parameter",
[DW_TAG_template_value_parameter] = "template_value_parameter",
[DW_TAG_thrown_type] = "thrown_type",
[DW_TAG_try_block] = "try_block",
[DW_TAG_variant_part] = "variant_part",
[DW_TAG_variable] = "variable",
[DW_TAG_volatile_type] = "volatile_type",
[DW_TAG_dwarf_procedure] = "dwarf_procedure",
[DW_TAG_restrict_type] = "restrict_type",
[DW_TAG_interface_type] = "interface_type",
[DW_TAG_namespace] = "namespace",
[DW_TAG_imported_module] = "imported_module",
[DW_TAG_unspecified_type] = "unspecified_type",
[DW_TAG_partial_unit] = "partial_unit",
[DW_TAG_imported_unit] = "imported_unit",
[DW_TAG_mutable_type] = "mutable_type",
[DW_TAG_condition] = "condition",
[DW_TAG_shared_type] = "shared_type",
};
const char *dwarf_tag_name(const uint32_t tag)
{
if (tag >= DW_TAG_array_type && tag <= DW_TAG_shared_type)
return dwarf_tag_names[tag];
return "INVALID";
}
static const struct conf_fprintf conf_fprintf__defaults = {
.name_spacing = 23,
.type_spacing = 26,
.emit_stats = 1,
};
static const char tabs[] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
static size_t cacheline_size;
[PAHOLE]: Print cacheline boundaries Cacheline size defaults to 32, sample output changing the default to 64 bytes: pahole --cacheline=64 ../../acme/OUTPUT/qemu/net-2.6/net/ipv4/tcp.o inode /* /pub/scm/linux/kernel/git/acme/net-2.6/include/linux/dcache.h:86 */ struct inode { struct hlist_node i_hash; /* 0 8 */ struct list_head i_list; /* 8 8 */ struct list_head i_sb_list; /* 16 8 */ struct list_head i_dentry; /* 24 8 */ long unsigned int i_ino; /* 32 4 */ atomic_t i_count; /* 36 4 */ umode_t i_mode; /* 40 2 */ /* XXX 2 bytes hole, try to pack */ unsigned int i_nlink; /* 44 4 */ uid_t i_uid; /* 48 4 */ gid_t i_gid; /* 52 4 */ dev_t i_rdev; /* 56 4 */ loff_t i_size; /* 60 8 */ struct timespec i_atime; /* 68 8 */ struct timespec i_mtime; /* 76 8 */ struct timespec i_ctime; /* 84 8 */ unsigned int i_blkbits; /* 92 4 */ long unsigned int i_version; /* 96 4 */ blkcnt_t i_blocks; /* 100 4 */ short unsigned int i_bytes; /* 104 2 */ spinlock_t i_lock; /* 106 0 */ /* XXX 2 bytes hole, try to pack */ struct mutex i_mutex; /* 108 24 */ /* ---------- cacheline 2 boundary ---------- */ struct rw_semaphore i_alloc_sem; /* 132 12 */ struct inode_operations * i_op; /* 144 4 */ const struct file_operations * i_fop; /* 148 4 */ struct super_block * i_sb; /* 152 4 */ struct file_lock * i_flock; /* 156 4 */ struct address_space * i_mapping; /* 160 4 */ struct address_space i_data; /* 164 72 */ struct list_head i_devices; /* 236 8 */ union ; /* 244 4 */ int i_cindex; /* 248 4 */ __u32 i_generation; /* 252 4 */ long unsigned int i_dnotify_mask; /* 256 4 */ /* ---------- cacheline 4 boundary ---------- */ struct dnotify_struct * i_dnotify; /* 260 4 */ struct list_head inotify_watches; /* 264 8 */ struct mutex inotify_mutex; /* 272 24 */ long unsigned int i_state; /* 296 4 */ long unsigned int dirtied_when; /* 300 4 */ unsigned int i_flags; /* 304 4 */ atomic_t i_writecount; /* 308 4 */ void * i_private; /* 312 4 */ }; /* size: 316, sum members: 312, holes: 2, sum holes: 4 */ Has to be improved to show the other cacheline boundaries, that may be buried into a included struct or union. Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 18:34:54 +01:00
static void *strings;
static int strings__compare(const void *a, const void *b)
{
return strcmp(a, b);
}
char *strings__add(const char *str)
{
char **s;
if (str == NULL)
return NULL;
s = tsearch(str, &strings, strings__compare);
if (s != NULL) {
if (*s == str) {
char *dup = strdup(str);
if (dup != NULL)
*s = dup;
else {
tdelete(str, &strings, strings__compare);
return NULL;
}
}
} else
return NULL;
return *s;
}
void tag__delete(struct tag *self)
{
assert(list_empty(&self->node));
free(self);
}
void tag__not_found_die(const char *file, int line, const char *func)
{
fprintf(stderr, "%s::%s(%d): tag not found, please report to "
"acme@ghostprotocols.net\n", file, func, line);
exit(1);
}
struct tag *tag__follow_typedef(struct tag *tag, const struct cu *cu)
{
struct tag *type = cu__find_tag_by_id(cu, tag->type);
if (type != NULL && type->tag == DW_TAG_typedef)
return tag__follow_typedef(type, cu);
return type;
}
static const char *tag__accessibility(const struct tag *self)
{
int a;
switch (self->tag) {
case DW_TAG_inheritance:
case DW_TAG_member:
a = tag__class_member(self)->accessibility;
break;
case DW_TAG_subprogram:
a = tag__function(self)->accessibility;
break;
default:
return NULL;
}
switch (a) {
case DW_ACCESS_public: return "public";
case DW_ACCESS_private: return "private";
case DW_ACCESS_protected: return "protected";
}
return NULL;
}
size_t tag__nr_cachelines(const struct tag *self, const struct cu *cu)
{
return (tag__size(self, cu) + cacheline_size - 1) / cacheline_size;
}
static void __tag__id_not_found(const struct tag *self,
unsigned long long id, const char *fn)
{
fprintf(stderr, "%s: %#llx id not found for %s (id=%#llx)\n",
fn, (unsigned long long)id, dwarf_tag_name(self->tag),
(unsigned long long)self->id);
fflush(stderr);
}
#define tag__id_not_found(self, id) __tag__id_not_found(self, id, __func__)
#define tag__type_not_found(self) __tag__id_not_found(self, (self)->type, __func__)
size_t tag__fprintf_decl_info(const struct tag *self, FILE *fp)
{
return fprintf(fp, "/* <%llx> %s:%u */\n",
(unsigned long long)self->id,
self->decl_file, self->decl_line);
}
static size_t type__fprintf(struct tag *type, const struct cu *cu,
const char *name, const struct conf_fprintf *conf,
FILE *fp);
static size_t array_type__fprintf(const struct tag *tag_self,
const struct cu *cu, const char *name,
const struct conf_fprintf *conf,
FILE *fp)
{
struct array_type *self = tag__array_type(tag_self);
struct tag *type = cu__find_tag_by_id(cu, tag_self->type);
size_t printed;
int i;
if (type == NULL)
return fprintf(fp, " <ERROR: type %#llx not found!>",
(unsigned long long)tag_self->type);
printed = type__fprintf(type, cu, name, conf, fp);
for (i = 0; i < self->dimensions; ++i)
printed += fprintf(fp, "[%u]", self->nr_entries[i]);
return printed;
}
void namespace__delete(struct namespace *self)
{
struct tag *pos, *n;
namespace__for_each_tag_safe(self, pos, n) {
list_del_init(&pos->node);
/* Look for nested namespaces */
if (tag__is_struct(pos) ||
tag__is_union(pos) ||
tag__is_namespace(pos) ||
tag__is_enumeration(pos))
namespace__delete(tag__namespace(pos));
tag__delete(pos);
}
tag__delete(&self->tag);
}
const char *type__name(struct type *self, const struct cu *cu)
{
/* Check if the tag doesn't comes with a DW_AT_name attribute... */
if (self->namespace.name == NULL &&
/* No? So it can have a DW_TAG_specification... */
self->specification != 0 &&
cu != NULL) {
struct tag *tag = cu__find_tag_by_id(cu, self->specification);
if (tag == NULL) {
tag__id_not_found(&self->namespace.tag, self->specification);
return NULL;
}
/* ... and now we cache the result in this tag ->name field */
self->namespace.name = tag__type(tag)->namespace.name;
}
return self->namespace.name;
}
struct class_member *
type__find_first_biggest_size_base_type_member(struct type *self,
const struct cu *cu)
{
struct class_member *pos, *result = NULL;
size_t result_size = 0;
type__for_each_data_member(self, pos) {
struct tag *type = cu__find_tag_by_id(cu, pos->tag.type);
size_t member_size = 0, power2;
struct class_member *inner = NULL;
if (type == NULL) {
tag__type_not_found(&pos->tag);
continue;
}
reevaluate:
switch (type->tag) {
case DW_TAG_base_type:
member_size = base_type__size(type);
break;
case DW_TAG_pointer_type:
case DW_TAG_reference_type:
member_size = cu->addr_size;
break;
case DW_TAG_union_type:
case DW_TAG_structure_type:
if (tag__type(type)->nr_members == 0)
continue;
inner = type__find_first_biggest_size_base_type_member(tag__type(type), cu);
member_size = class_member__size(inner, cu);
break;
case DW_TAG_array_type:
case DW_TAG_const_type:
case DW_TAG_typedef:
case DW_TAG_volatile_type: {
const struct tag *tag = type;
type = cu__find_tag_by_id(cu, type->id);
if (type == NULL) {
tag__type_not_found(tag);
continue;
}
}
goto reevaluate;
case DW_TAG_enumeration_type:
member_size = tag__type(type)->size;
break;
}
/* long long */
if (member_size > cu->addr_size)
return pos;
for (power2 = cu->addr_size; power2 > result_size; power2 /= 2)
if (member_size >= power2) {
if (power2 == cu->addr_size)
return inner ?: pos;
result_size = power2;
result = inner ?: pos;
}
}
return result;
}
size_t typedef__fprintf(const struct tag *tag_self, const struct cu *cu,
const struct conf_fprintf *conf, FILE *fp)
{
struct type *self = tag__type(tag_self);
const struct conf_fprintf *pconf = conf ?: &conf_fprintf__defaults;
const struct tag *type;
const struct tag *ptr_type;
char bf[512];
int is_pointer = 0;
size_t printed;
/*
* Check for void (humm, perhaps we should have a fake void tag instance
* to avoid all these checks?
*/
if (tag_self->type == 0)
return fprintf(fp, "typedef void %s", type__name(self, cu));
type = cu__find_tag_by_id(cu, tag_self->type);
if (type == NULL) {
tag__type_not_found(tag_self);
return 0;
}
switch (type->tag) {
case DW_TAG_array_type:
printed = fprintf(fp, "typedef ");
return printed + array_type__fprintf(type, cu,
type__name(self, cu),
pconf, fp);
case DW_TAG_pointer_type:
if (type->type == 0) /* void pointer */
break;
ptr_type = cu__find_tag_by_id(cu, type->type);
if (ptr_type == NULL) {
tag__type_not_found(type);
return 0;
}
if (ptr_type->tag != DW_TAG_subroutine_type)
break;
type = ptr_type;
is_pointer = 1;
/* Fall thru */
case DW_TAG_subroutine_type:
printed = fprintf(fp, "typedef ");
return printed + ftype__fprintf(tag__ftype(type), cu,
type__name(self, cu),
0, is_pointer, 0,
fp);
case DW_TAG_structure_type: {
struct type *ctype = tag__type(type);
if (type__name(ctype, cu) != NULL)
return fprintf(fp, "typedef struct %s %s",
type__name(ctype, cu),
type__name(self, cu));
}
}
return fprintf(fp, "typedef %s %s",
tag__name(type, cu, bf, sizeof(bf)),
type__name(self, cu));
}
static size_t imported_declaration__fprintf(const struct tag *self,
const struct cu *cu, FILE *fp)
{
char bf[512];
size_t printed = fprintf(fp, "using ::");
const struct tag *decl = cu__find_tag_by_id(cu, self->type);
if (decl == NULL)
printed += fprintf(fp, " <ERROR: type %#llx not found!>",
(unsigned long long)self->type);
return printed + fprintf(fp, "%s", tag__name(decl, cu, bf, sizeof(bf)));
}
static size_t imported_module__fprintf(const struct tag *self,
const struct cu *cu, FILE *fp)
{
const struct tag *module = cu__find_tag_by_id(cu, self->type);
const char *name = "<IMPORTED MODULE ERROR!>";
if (tag__is_namespace(module))
name = tag__namespace(module)->name;
return fprintf(fp, "using namespace %s", name);
}
size_t enumeration__fprintf(const struct tag *tag_self, const struct cu *cu,
const struct conf_fprintf *conf, FILE *fp)
{
struct type *self = tag__type(tag_self);
struct enumerator *pos;
size_t printed = fprintf(fp, "enum%s%s {\n",
type__name(self, cu) ? " " : "",
type__name(self, cu) ?: "");
int indent = conf->indent;
if (indent >= (int)sizeof(tabs))
indent = sizeof(tabs) - 1;
type__for_each_enumerator(self, pos)
printed += fprintf(fp, "%.*s\t%s = %u,\n", indent, tabs,
pos->name, pos->value);
return printed + fprintf(fp, "%.*s}%s%s", indent, tabs,
conf->suffix ? " " : "", conf->suffix ?: "");
}
void cus__add(struct cus *self, struct cu *cu)
{
list_add_tail(&cu->node, &self->cus);
}
struct cu *cu__new(const char *name, uint8_t addr_size,
const unsigned char *build_id,
int build_id_len)
{
struct cu *self = malloc(sizeof(*self) + build_id_len);
if (self != NULL) {
uint32_t i;
for (i = 0; i < HASHTAGS__SIZE; ++i)
INIT_LIST_HEAD(&self->hash_tags[i]);
INIT_LIST_HEAD(&self->tags);
INIT_LIST_HEAD(&self->tool_list);
self->name = strings__add(name);
self->addr_size = addr_size;
self->nr_inline_expansions = 0;
self->size_inline_expansions = 0;
self->nr_structures_changed = 0;
self->nr_functions_changed = 0;
self->max_len_changed_item = 0;
self->function_bytes_added = 0;
self->function_bytes_removed = 0;
self->build_id_len = build_id_len;
if (build_id_len > 0)
memcpy(self->build_id, build_id, build_id_len);
}
return self;
}
void cu__delete(struct cu *self)
{
struct tag *pos, *n;
list_for_each_entry_safe(pos, n, &self->tags, node) {
list_del_init(&pos->node);
/* Look for nested namespaces */
if (tag__is_struct(pos) ||
tag__is_union(pos) ||
tag__is_namespace(pos) ||
tag__is_enumeration(pos)) {
namespace__delete(tag__namespace(pos));
}
}
free(self);
}
void hashtags__hash(struct list_head *hashtable, struct tag *tag)
{
struct list_head *head = hashtable + hashtags__fn(tag->id);
list_add_tail(&tag->hash_node, head);
}
void cu__add_tag(struct cu *self, struct tag *tag)
{
list_add_tail(&tag->node, &self->tags);
hashtags__hash(self->hash_tags, tag);
}
bool cu__same_build_id(const struct cu *self, const struct cu *other)
{
return self->build_id_len != 0 &&
self->build_id_len == other->build_id_len &&
memcmp(self->build_id, other->build_id, self->build_id_len) == 0;
}
static const char *tag__prefix(const struct cu *cu, const uint32_t tag)
{
switch (tag) {
case DW_TAG_enumeration_type: return "enum ";
case DW_TAG_structure_type:
return cu->language == DW_LANG_C_plus_plus ? "class " :
"struct ";
case DW_TAG_union_type: return "union ";
case DW_TAG_pointer_type: return " *";
case DW_TAG_reference_type: return " &";
}
return "";
}
struct tag *cu__find_tag_by_id(const struct cu *self, const Dwarf_Off id)
{
struct tag *pos;
const struct list_head *head;
if (self == NULL || id == 0)
return NULL;
head = &self->hash_tags[hashtags__fn(id)];
list_for_each_entry(pos, head, hash_node)
if (pos->id == id)
return pos;
return NULL;
}
struct tag *cu__find_first_typedef_of_type(const struct cu *self,
const Dwarf_Off type)
{
struct tag *pos;
if (self == NULL || type == 0)
return NULL;
list_for_each_entry(pos, &self->tags, node)
if (pos->tag == DW_TAG_typedef && pos->type == type)
return pos;
return NULL;
}
struct tag *cu__find_base_type_by_name(const struct cu *self, const char *name)
{
struct tag *pos;
if (self == NULL || name == NULL)
return NULL;
list_for_each_entry(pos, &self->tags, node)
if (pos->tag == DW_TAG_base_type) {
const struct base_type *bt = tag__base_type(pos);
if (bt->name != NULL && strcmp(bt->name, name) == 0)
return pos;
}
return NULL;
}
struct tag *cu__find_struct_by_name(const struct cu *self, const char *name,
const int include_decls)
{
struct tag *pos;
if (self == NULL || name == NULL)
return NULL;
list_for_each_entry(pos, &self->tags, node) {
struct type *type;
if (!tag__is_struct(pos))
continue;
type = tag__type(pos);
if (type__name(type, self) != NULL &&
strcmp(type__name(type, self), name) == 0) {
if (type->declaration) {
if (include_decls)
return pos;
} else
return pos;
}
}
return NULL;
}
struct tag *cus__find_struct_by_name(const struct cus *self,
struct cu **cu, const char *name,
const int include_decls)
{
struct cu *pos;
list_for_each_entry(pos, &self->cus, node) {
struct tag *tag = cu__find_struct_by_name(pos, name,
include_decls);
if (tag != NULL) {
if (cu != NULL)
*cu = pos;
return tag;
}
}
return NULL;
}
struct tag *cus__find_function_by_name(const struct cus *self,
struct cu **cu, const char *name)
{
struct cu *pos;
list_for_each_entry(pos, &self->cus, node) {
struct tag *function = cu__find_function_by_name(pos, name);
if (function != NULL) {
if (cu != NULL)
*cu = pos;
return function;
}
}
return NULL;
}
struct tag *cus__find_tag_by_id(const struct cus *self,
struct cu **cu, const Dwarf_Off id)
{
struct cu *pos;
list_for_each_entry(pos, &self->cus, node) {
struct tag *tag = cu__find_tag_by_id(pos, id);
if (tag != NULL) {
if (cu != NULL)
*cu = pos;
return tag;
}
}
return NULL;
}
struct cu *cus__find_cu_by_name(const struct cus *self, const char *name)
{
struct cu *pos;
list_for_each_entry(pos, &self->cus, node)
if (strcmp(pos->name, name) == 0)
return pos;
return NULL;
}
struct tag *cu__find_function_by_name(const struct cu *self, const char *name)
{
struct tag *pos;
struct function *fpos;
if (self == NULL || name == NULL)
return NULL;
list_for_each_entry(pos, &self->tags, node) {
if (pos->tag != DW_TAG_subprogram)
continue;
fpos = tag__function(pos);
if (fpos->name != NULL && strcmp(fpos->name, name) == 0)
return pos;
}
return NULL;
}
static struct tag *lexblock__find_tag_by_id(const struct lexblock *self,
const Dwarf_Off id)
{
struct tag *pos;
list_for_each_entry(pos, &self->tags, node) {
/* Allow find DW_TAG_lexical_block tags */
if (pos->id == id)
return pos;
/*
* Oh, not looking for DW_TAG_lexical_block tags? So lets look
* inside this lexblock:
*/
if (pos->tag == DW_TAG_lexical_block) {
const struct lexblock *child = tag__lexblock(pos);
struct tag *tag = lexblock__find_tag_by_id(child, id);
if (tag != NULL)
return tag;
}
}
return NULL;
}
static struct variable *cu__find_variable_by_id(const struct cu *self,
const Dwarf_Off id)
{
struct tag *pos;
if (self == NULL)
return NULL;
list_for_each_entry(pos, &self->tags, node) {
/* Look at global variables first */
if (pos->id == id)
return (struct variable *)(pos);
/* Now look inside function lexical blocks */
if (pos->tag == DW_TAG_subprogram) {
struct function *fn = tag__function(pos);
struct tag *tag =
lexblock__find_tag_by_id(&fn->lexblock, id);
if (tag != NULL)
return (struct variable *)(tag);
}
}
return NULL;
}
static struct tag *list__find_tag_by_id(const struct list_head *self,
const Dwarf_Off id)
{
struct tag *pos, *tag;
list_for_each_entry(pos, self, node) {
if (pos->id == id)
return pos;
switch (pos->tag) {
case DW_TAG_namespace:
case DW_TAG_structure_type:
case DW_TAG_union_type:
tag = list__find_tag_by_id(&tag__namespace(pos)->tags, id);
break;
case DW_TAG_subprogram:
tag = list__find_tag_by_id(&tag__ftype(pos)->parms, id);
if (tag == NULL)
tag = list__find_tag_by_id(&tag__function(pos)->lexblock.tags, id);
break;
default:
continue;
}
if (tag != NULL)
return tag;
}
return NULL;
}
static struct tag *cu__find_parameter_by_id(const struct cu *self,
const Dwarf_Off id)
{
if (self == NULL)
return NULL;
return list__find_tag_by_id(&self->tags, id);
}
static size_t array_type__nr_entries(const struct array_type *self)
{
int i;
size_t nr_entries = 1;
for (i = 0; i < self->dimensions; ++i)
nr_entries *= self->nr_entries[i];
return nr_entries;
}
size_t tag__size(const struct tag *self, const struct cu *cu)
{
size_t size;
switch (self->tag) {
case DW_TAG_pointer_type:
case DW_TAG_reference_type: return cu->addr_size;
case DW_TAG_base_type: return base_type__size(self);
case DW_TAG_enumeration_type: return tag__type(self)->size;
}
if (self->type == 0) /* struct class: unions, structs */
size = tag__type(self)->size;
else {
const struct tag *type = cu__find_tag_by_id(cu, self->type);
if (type == NULL) {
tag__type_not_found(self);
return -1;
}
size = tag__size(type, cu);
}
if (self->tag == DW_TAG_array_type)
return size * array_type__nr_entries(tag__array_type(self));
return size;
}
static const char *tag__ptr_name(const struct tag *self, const struct cu *cu,
char *bf, size_t len, char ptr_char)
{
if (self->type == 0) /* No type == void */
snprintf(bf, len, "void %c", ptr_char);
else {
const struct tag *type = cu__find_tag_by_id(cu, self->type);
if (type == NULL) {
tag__type_not_found(self);
snprintf(bf, len,
"<ERROR: type not found!> %c", ptr_char);
} else {
char tmpbf[512];
snprintf(bf, len, "%s %c",
tag__name(type, cu,
tmpbf, sizeof(tmpbf)), ptr_char);
}
}
return bf;
}
const char *tag__name(const struct tag *self, const struct cu *cu,
char *bf, size_t len)
{
struct tag *type;
if (self == NULL)
strncpy(bf, "void", len);
else switch (self->tag) {
case DW_TAG_base_type: {
const struct base_type *bt = tag__base_type(self);
const char *s = "nameless base type!";
if (bt->name != NULL)
s = bt->name;
strncpy(bf, s, len);
}
break;
case DW_TAG_subprogram:
strncpy(bf, function__name(tag__function(self), cu), len);
break;
case DW_TAG_pointer_type:
return tag__ptr_name(self, cu, bf, len, '*');
case DW_TAG_reference_type:
return tag__ptr_name(self, cu, bf, len, '&');
case DW_TAG_volatile_type:
case DW_TAG_const_type:
type = cu__find_tag_by_id(cu, self->type);
if (type == NULL && self->type != 0) {
tag__type_not_found(self);
strncpy(bf, "<ERROR>", len);
} else {
char tmpbf[128];
snprintf(bf, len, "%s %s ",
self->tag == DW_TAG_volatile_type ?
"volatile" : "const",
tag__name(type, cu, tmpbf, sizeof(tmpbf)));
}
break;
case DW_TAG_array_type:
type = cu__find_tag_by_id(cu, self->type);
if (type == NULL) {
tag__type_not_found(self);
strncpy(bf, "<ERROR>", len);
} else
return tag__name(type, cu, bf, len);
break;
case DW_TAG_subroutine_type: {
FILE *bfp = fmemopen(bf, len, "w");
if (bfp != NULL) {
ftype__fprintf(tag__ftype(self), cu, NULL, 0, 0, 0, bfp);
fclose(bfp);
} else
strncpy(bf, "<ERROR>", len);
}
break;
default:
snprintf(bf, len, "%s%s", tag__prefix(cu, self->tag),
type__name(tag__type(self), cu) ?: "");
break;
}
return bf;
}
static struct tag *variable__type(const struct variable *self,
const struct cu *cu)
{
struct variable *var;
if (self->tag.type != 0)
return cu__find_tag_by_id(cu, self->tag.type);
else if (self->abstract_origin != 0) {
var = cu__find_variable_by_id(cu, self->abstract_origin);
if (var)
return variable__type(var, cu);
}
return NULL;
}
const char *variable__type_name(const struct variable *self,
const struct cu *cu,
char *bf, size_t len)
{
const struct tag *tag = variable__type(self, cu);
return tag != NULL ? tag__name(tag, cu, bf, len) : NULL;
}
const char *variable__name(const struct variable *self, const struct cu *cu)
{
if (self->name != NULL)
return self->name;
if (self->abstract_origin != 0) {
struct variable *var =
cu__find_variable_by_id(cu, self->abstract_origin);
if (var != NULL)
return var->name;
}
return NULL;
}
static const char *variable__prefix(const struct variable *var)
{
switch (var->location) {
case LOCATION_REGISTER:
return "register ";
case LOCATION_UNKNOWN:
if (var->external && var->declaration)
return "extern ";
break;
case LOCATION_GLOBAL:
if (!var->external)
return "static ";
break;
case LOCATION_LOCAL:
case LOCATION_OPTIMIZED:
break;
}
return NULL;
}
void class_member__delete(struct class_member *self)
{
free(self);
}
static struct class_member *class_member__clone(const struct class_member *from)
{
struct class_member *self = malloc(sizeof(*self));
if (self != NULL)
memcpy(self, from, sizeof(*self));
return self;
}
size_t class_member__size(const struct class_member *self,
const struct cu *cu)
{
struct tag *type = cu__find_tag_by_id(cu, self->tag.type);
if (type == NULL) {
tag__type_not_found(&self->tag);
return -1;
}
return tag__size(type, cu);
}
const char *parameter__name(struct parameter *self, const struct cu *cu)
{
/* Check if the tag doesn't comes with a DW_AT_name attribute... */
if (self->name == NULL && self->abstract_origin != 0) {
/* No? Does it have a DW_AT_abstract_origin? */
struct tag *alias =
cu__find_parameter_by_id(cu, self->abstract_origin);
if (alias == NULL) {
tag__id_not_found(&self->tag, self->abstract_origin);
return NULL;
}
/* Now cache the result in this tag ->name field */
self->name = tag__parameter(alias)->name;
}
return self->name;
}
Dwarf_Off parameter__type(struct parameter *self, const struct cu *cu)
{
/* Check if the tag doesn't comes with a DW_AT_type attribute... */
if (self->tag.type == 0 && self->abstract_origin != 0) {
/* No? Does it have a DW_AT_abstract_origin? */
struct tag *alias =
cu__find_parameter_by_id(cu, self->abstract_origin);
if (alias == NULL) {
tag__id_not_found(&self->tag, self->abstract_origin);
return 0;
}
/* Now cache the result in this tag ->name and type fields */
self->name = tag__parameter(alias)->name;
self->tag.type = tag__parameter(alias)->tag.type;
}
return self->tag.type;
}
static size_t union__fprintf(struct type *self, const struct cu *cu,
const struct conf_fprintf *conf, FILE *fp);
[CLASSES]: Ditch class_member__names Was a awful function, to replace it added some new __snprintf methods for more classes (array_type, class_member, etc), the end result is a much nicer rendering, for instance: @@ -6549,11 +6549,11 @@ /* XXX 2 bytes hole, try to pack */ union { - struct ff_constant_effect constant; /* 10 */ - struct ff_ramp_effect ramp; /* 12 */ - struct ff_periodic_effect periodic; /* 28 */ - struct ff_condition_effect condition[2]; /* 24 */ - struct ff_rumble_effect rumble; /* 4 */ + struct ff_constant_effect constant; /* 10 */ + struct ff_ramp_effect ramp; /* 12 */ + struct ff_periodic_effect periodic; /* 28 */ + struct ff_condition_effect condition[2]; /* 24 */ + struct ff_rumble_effect rumble; /* 4 */ } u; /* 16 28 */ /* --- cacheline 1 boundary (32 bytes) was 12 bytes ago --- */ }; /* size: 44, cachelines: 2 */ Previously when such big class members appeared the comments with the size and offset were unaligned, now its only in extreme cases, such as the array above that things get unaligned. End result is a smaller library: [acme@newtoy pahole]$ codiff -V build/libclasses.so.orig build/libclasses.so /home/acme/pahole/classes.c: struct array_type | -4 nr_members: -1 -const char *name /* 36 4 */ 1 struct changed enumeration__print | +10 # 175 -> 185 union__snprintf | +32 # 576 -> 608 union__print | +16 # 182 -> 198 class_member__names | -851 (removed) class_member__print | -721 # 1218 -> 497 class__print_struct | +54 # 1403 -> 1457 6 functions changed, 112 bytes added, 1572 bytes removed, diff: -1460 /home/acme/pahole/classes.c: array_type__snprintf | +249 (added) class_member__snprintf | +892 (added) 2 functions changed, 1141 bytes added build/libclasses.so: 8 functions changed, 1253 bytes added, 1572 bytes removed, diff: -319 Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 17:19:55 +01:00
static size_t type__fprintf(struct tag *type, const struct cu *cu,
const char *name, const struct conf_fprintf *conf,
FILE *fp)
[CLASSES]: Ditch class_member__names Was a awful function, to replace it added some new __snprintf methods for more classes (array_type, class_member, etc), the end result is a much nicer rendering, for instance: @@ -6549,11 +6549,11 @@ /* XXX 2 bytes hole, try to pack */ union { - struct ff_constant_effect constant; /* 10 */ - struct ff_ramp_effect ramp; /* 12 */ - struct ff_periodic_effect periodic; /* 28 */ - struct ff_condition_effect condition[2]; /* 24 */ - struct ff_rumble_effect rumble; /* 4 */ + struct ff_constant_effect constant; /* 10 */ + struct ff_ramp_effect ramp; /* 12 */ + struct ff_periodic_effect periodic; /* 28 */ + struct ff_condition_effect condition[2]; /* 24 */ + struct ff_rumble_effect rumble; /* 4 */ } u; /* 16 28 */ /* --- cacheline 1 boundary (32 bytes) was 12 bytes ago --- */ }; /* size: 44, cachelines: 2 */ Previously when such big class members appeared the comments with the size and offset were unaligned, now its only in extreme cases, such as the array above that things get unaligned. End result is a smaller library: [acme@newtoy pahole]$ codiff -V build/libclasses.so.orig build/libclasses.so /home/acme/pahole/classes.c: struct array_type | -4 nr_members: -1 -const char *name /* 36 4 */ 1 struct changed enumeration__print | +10 # 175 -> 185 union__snprintf | +32 # 576 -> 608 union__print | +16 # 182 -> 198 class_member__names | -851 (removed) class_member__print | -721 # 1218 -> 497 class__print_struct | +54 # 1403 -> 1457 6 functions changed, 112 bytes added, 1572 bytes removed, diff: -1460 /home/acme/pahole/classes.c: array_type__snprintf | +249 (added) class_member__snprintf | +892 (added) 2 functions changed, 1141 bytes added build/libclasses.so: 8 functions changed, 1253 bytes added, 1572 bytes removed, diff: -319 Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 17:19:55 +01:00
{
char tbf[128];
char namebf[256];
struct type *ctype;
struct conf_fprintf tconf;
size_t printed = 0;
int expand_types = conf->expand_types;
int suppress_offset_comment = conf->suppress_offset_comment;
[CLASSES]: Ditch class_member__names Was a awful function, to replace it added some new __snprintf methods for more classes (array_type, class_member, etc), the end result is a much nicer rendering, for instance: @@ -6549,11 +6549,11 @@ /* XXX 2 bytes hole, try to pack */ union { - struct ff_constant_effect constant; /* 10 */ - struct ff_ramp_effect ramp; /* 12 */ - struct ff_periodic_effect periodic; /* 28 */ - struct ff_condition_effect condition[2]; /* 24 */ - struct ff_rumble_effect rumble; /* 4 */ + struct ff_constant_effect constant; /* 10 */ + struct ff_ramp_effect ramp; /* 12 */ + struct ff_periodic_effect periodic; /* 28 */ + struct ff_condition_effect condition[2]; /* 24 */ + struct ff_rumble_effect rumble; /* 4 */ } u; /* 16 28 */ /* --- cacheline 1 boundary (32 bytes) was 12 bytes ago --- */ }; /* size: 44, cachelines: 2 */ Previously when such big class members appeared the comments with the size and offset were unaligned, now its only in extreme cases, such as the array above that things get unaligned. End result is a smaller library: [acme@newtoy pahole]$ codiff -V build/libclasses.so.orig build/libclasses.so /home/acme/pahole/classes.c: struct array_type | -4 nr_members: -1 -const char *name /* 36 4 */ 1 struct changed enumeration__print | +10 # 175 -> 185 union__snprintf | +32 # 576 -> 608 union__print | +16 # 182 -> 198 class_member__names | -851 (removed) class_member__print | -721 # 1218 -> 497 class__print_struct | +54 # 1403 -> 1457 6 functions changed, 112 bytes added, 1572 bytes removed, diff: -1460 /home/acme/pahole/classes.c: array_type__snprintf | +249 (added) class_member__snprintf | +892 (added) 2 functions changed, 1141 bytes added build/libclasses.so: 8 functions changed, 1253 bytes added, 1572 bytes removed, diff: -319 Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 17:19:55 +01:00
if (type == NULL)
goto out_type_not_found;
[CLASSES]: Ditch class_member__names Was a awful function, to replace it added some new __snprintf methods for more classes (array_type, class_member, etc), the end result is a much nicer rendering, for instance: @@ -6549,11 +6549,11 @@ /* XXX 2 bytes hole, try to pack */ union { - struct ff_constant_effect constant; /* 10 */ - struct ff_ramp_effect ramp; /* 12 */ - struct ff_periodic_effect periodic; /* 28 */ - struct ff_condition_effect condition[2]; /* 24 */ - struct ff_rumble_effect rumble; /* 4 */ + struct ff_constant_effect constant; /* 10 */ + struct ff_ramp_effect ramp; /* 12 */ + struct ff_periodic_effect periodic; /* 28 */ + struct ff_condition_effect condition[2]; /* 24 */ + struct ff_rumble_effect rumble; /* 4 */ } u; /* 16 28 */ /* --- cacheline 1 boundary (32 bytes) was 12 bytes ago --- */ }; /* size: 44, cachelines: 2 */ Previously when such big class members appeared the comments with the size and offset were unaligned, now its only in extreme cases, such as the array above that things get unaligned. End result is a smaller library: [acme@newtoy pahole]$ codiff -V build/libclasses.so.orig build/libclasses.so /home/acme/pahole/classes.c: struct array_type | -4 nr_members: -1 -const char *name /* 36 4 */ 1 struct changed enumeration__print | +10 # 175 -> 185 union__snprintf | +32 # 576 -> 608 union__print | +16 # 182 -> 198 class_member__names | -851 (removed) class_member__print | -721 # 1218 -> 497 class__print_struct | +54 # 1403 -> 1457 6 functions changed, 112 bytes added, 1572 bytes removed, diff: -1460 /home/acme/pahole/classes.c: array_type__snprintf | +249 (added) class_member__snprintf | +892 (added) 2 functions changed, 1141 bytes added build/libclasses.so: 8 functions changed, 1253 bytes added, 1572 bytes removed, diff: -319 Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 17:19:55 +01:00
if (conf->expand_pointers) {
int nr_indirections = 0;
while (type->tag == DW_TAG_pointer_type && type->type != 0) {
type = cu__find_tag_by_id(cu, type->type);
if (type == NULL)
goto out_type_not_found;
++nr_indirections;
}
if (nr_indirections > 0) {
const size_t len = strlen(name);
if (len + nr_indirections >= sizeof(namebf))
goto out_type_not_found;
memset(namebf, '*', nr_indirections);
memcpy(namebf + nr_indirections, name, len);
namebf[len + nr_indirections] = '\0';
name = namebf;
}
expand_types = nr_indirections;
if (!suppress_offset_comment)
suppress_offset_comment = !!nr_indirections;
/* Avoid loops */
if (type->recursivity_level != 0)
expand_types = 0;
++type->recursivity_level;
}
if (expand_types) {
int typedef_expanded = 0;
while (type->tag == DW_TAG_typedef) {
ctype = tag__type(type);
if (typedef_expanded)
printed += fprintf(fp, " -> %s",
type__name(ctype, cu));
else {
printed += fprintf(fp, "/* typedef %s",
type__name(ctype, cu));
typedef_expanded = 1;
}
type = cu__find_tag_by_id(cu, type->type);
if (type == NULL)
goto out_type_not_found;
}
if (typedef_expanded)
printed += fprintf(fp, " */ ");
}
if (tag__is_struct(type) || tag__is_union(type) ||
tag__is_enumeration(type)) {
tconf = *conf;
tconf.type_spacing -= 8;
tconf.prefix = NULL;
tconf.suffix = name;
tconf.emit_stats = 0;
tconf.suppress_offset_comment = suppress_offset_comment;
}
switch (type->tag) {
case DW_TAG_pointer_type:
[CLASSES]: Ditch class_member__names Was a awful function, to replace it added some new __snprintf methods for more classes (array_type, class_member, etc), the end result is a much nicer rendering, for instance: @@ -6549,11 +6549,11 @@ /* XXX 2 bytes hole, try to pack */ union { - struct ff_constant_effect constant; /* 10 */ - struct ff_ramp_effect ramp; /* 12 */ - struct ff_periodic_effect periodic; /* 28 */ - struct ff_condition_effect condition[2]; /* 24 */ - struct ff_rumble_effect rumble; /* 4 */ + struct ff_constant_effect constant; /* 10 */ + struct ff_ramp_effect ramp; /* 12 */ + struct ff_periodic_effect periodic; /* 28 */ + struct ff_condition_effect condition[2]; /* 24 */ + struct ff_rumble_effect rumble; /* 4 */ } u; /* 16 28 */ /* --- cacheline 1 boundary (32 bytes) was 12 bytes ago --- */ }; /* size: 44, cachelines: 2 */ Previously when such big class members appeared the comments with the size and offset were unaligned, now its only in extreme cases, such as the array above that things get unaligned. End result is a smaller library: [acme@newtoy pahole]$ codiff -V build/libclasses.so.orig build/libclasses.so /home/acme/pahole/classes.c: struct array_type | -4 nr_members: -1 -const char *name /* 36 4 */ 1 struct changed enumeration__print | +10 # 175 -> 185 union__snprintf | +32 # 576 -> 608 union__print | +16 # 182 -> 198 class_member__names | -851 (removed) class_member__print | -721 # 1218 -> 497 class__print_struct | +54 # 1403 -> 1457 6 functions changed, 112 bytes added, 1572 bytes removed, diff: -1460 /home/acme/pahole/classes.c: array_type__snprintf | +249 (added) class_member__snprintf | +892 (added) 2 functions changed, 1141 bytes added build/libclasses.so: 8 functions changed, 1253 bytes added, 1572 bytes removed, diff: -319 Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 17:19:55 +01:00
if (type->type != 0) {
struct tag *ptype = cu__find_tag_by_id(cu, type->type);
if (ptype == NULL)
goto out_type_not_found;
if (ptype->tag == DW_TAG_subroutine_type) {
printed += ftype__fprintf(tag__ftype(ptype),
cu, name, 0, 1,
conf->type_spacing,
fp);
break;
}
[CLASSES]: Ditch class_member__names Was a awful function, to replace it added some new __snprintf methods for more classes (array_type, class_member, etc), the end result is a much nicer rendering, for instance: @@ -6549,11 +6549,11 @@ /* XXX 2 bytes hole, try to pack */ union { - struct ff_constant_effect constant; /* 10 */ - struct ff_ramp_effect ramp; /* 12 */ - struct ff_periodic_effect periodic; /* 28 */ - struct ff_condition_effect condition[2]; /* 24 */ - struct ff_rumble_effect rumble; /* 4 */ + struct ff_constant_effect constant; /* 10 */ + struct ff_ramp_effect ramp; /* 12 */ + struct ff_periodic_effect periodic; /* 28 */ + struct ff_condition_effect condition[2]; /* 24 */ + struct ff_rumble_effect rumble; /* 4 */ } u; /* 16 28 */ /* --- cacheline 1 boundary (32 bytes) was 12 bytes ago --- */ }; /* size: 44, cachelines: 2 */ Previously when such big class members appeared the comments with the size and offset were unaligned, now its only in extreme cases, such as the array above that things get unaligned. End result is a smaller library: [acme@newtoy pahole]$ codiff -V build/libclasses.so.orig build/libclasses.so /home/acme/pahole/classes.c: struct array_type | -4 nr_members: -1 -const char *name /* 36 4 */ 1 struct changed enumeration__print | +10 # 175 -> 185 union__snprintf | +32 # 576 -> 608 union__print | +16 # 182 -> 198 class_member__names | -851 (removed) class_member__print | -721 # 1218 -> 497 class__print_struct | +54 # 1403 -> 1457 6 functions changed, 112 bytes added, 1572 bytes removed, diff: -1460 /home/acme/pahole/classes.c: array_type__snprintf | +249 (added) class_member__snprintf | +892 (added) 2 functions changed, 1141 bytes added build/libclasses.so: 8 functions changed, 1253 bytes added, 1572 bytes removed, diff: -319 Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 17:19:55 +01:00
}
/* Fall Thru */
default:
printed += fprintf(fp, "%-*s %s", conf->type_spacing,
tag__name(type, cu, tbf, sizeof(tbf)), name);
break;
case DW_TAG_subroutine_type:
printed += ftype__fprintf(tag__ftype(type), cu, name, 0, 0,
conf->type_spacing, fp);
break;
case DW_TAG_array_type:
printed += array_type__fprintf(type, cu, name, conf, fp);
break;
case DW_TAG_structure_type:
ctype = tag__type(type);
[CLASSES]: Fully support nested classes Example: [acme@newtoy pahole]$ pahole net/ipv4/tcp.o flowi /* include/net/flow.h:13 */ struct flowi { int oif; /* 0 4 */ int iif; /* 4 4 */ __u32 mark; /* 8 4 */ union { struct { __be32 daddr; /* 0 4 */ __be32 saddr; /* 4 4 */ __u8 tos; /* 8 1 */ __u8 scope; /* 9 1 */ } ip4_u; /* 12 */ struct { struct in6_addr daddr; /* 0 16 */ struct in6_addr saddr; /* 16 16 */ /* --- cacheline 1 boundary (32 bytes) --- */ __be32 flowlabel; /* 32 4 */ } ip6_u; /* 36 */ struct { __le16 daddr; /* 0 2 */ __le16 saddr; /* 2 2 */ __u8 scope; /* 4 1 */ } dn_u; /* 6 */ } nl_u; /* 12 36 */ /* --- cacheline 1 boundary (32 bytes) was 16 bytes ago --- */ __u8 proto; /* 48 1 */ __u8 flags; /* 49 1 */ /* XXX 2 bytes hole, try to pack */ union { struct { __be16 sport; /* 0 2 */ __be16 dport; /* 2 2 */ } ports; /* 4 */ struct { __u8 type; /* 0 1 */ __u8 code; /* 1 1 */ } icmpt; /* 2 */ struct { __le16 sport; /* 0 2 */ __le16 dport; /* 2 2 */ } dnports; /* 4 */ __be32 spi; /* 4 */ } uli_u; /* 52 4 */ __u32 secid; /* 56 4 */ }; /* size: 60, cachelines: 2 */ /* sum members: 58, holes: 1, sum holes: 2 */ /* last cacheline: 28 bytes */ Supporting anonymous structs and unions just fine, even combinations of both, like in struct page, in the Linux kernel: [acme@newtoy pahole]$ pahole mm/mmap.o page /* include/linux/mmzone.h:391 */ struct page { long unsigned int flags; /* 0 4 */ atomic_t _count; /* 4 4 */ atomic_t _mapcount; /* 8 4 */ union { struct { long unsigned int private; /* 0 4 */ struct address_space * mapping; /* 4 4 */ }; /* 8 */ }; /* 12 8 */ long unsigned int index; /* 20 4 */ struct list_head lru; /* 24 8 */ /* --- cacheline 1 boundary (32 bytes) --- */ }; /* size: 32, cachelines: 1 */ Or struct freebsd_sys_getdents_args in the OpenBSD kernel: /* /usr/home/leonardo/openbsd/src/sys/compat/freebsd/freebsd_syscallargs.h:231 */ struct freebsd_sys_getdents_args { union { register_t pad; /* 4 */ struct { int datum; /* 0 4 */ } le; /* 4 */ struct { int8_t pad[0]; /* 0 0 */ int datum; /* 0 4 */ } be; /* 4 */ } fd; /* 0 4 */ union { register_t pad; /* 4 */ struct { void * datum; /* 0 4 */ } le; /* 4 */ struct { int8_t pad[0]; /* 0 0 */ void * datum; /* 0 4 */ } be; /* 4 */ } dirent; /* 4 4 */ union { register_t pad; /* 4 */ struct { unsigned int datum; /* 0 4 */ } le; /* 4 */ struct { int8_t pad[0]; /* 0 0 */ unsigned int datum; /* 0 4 */ } be; /* 4 */ } count; /* 8 4 */ }; /* size: 12, cachelines: 1 */ /* last cacheline: 12 bytes */ /* definitions: 7 */ One more from the OpenBSD kernel: /* /usr/home/leonardo/openbsd/src/sys/nfs/nfs.h:344 */ struct nfssvc_sock { struct { struct nfssvc_sock * tqe_next; /* 0 4 */ struct nfssvc_sock * * tqe_prev; /* 4 4 */ } ns_chain; /* 0 8 */ struct { struct nfsuid * tqh_first; /* 0 4 */ struct nfsuid * * tqh_last; /* 4 4 */ } ns_uidlruhead; /* 8 8 */ struct file * ns_fp; /* 16 4 */ struct socket * ns_so; /* 20 4 */ struct mbuf * ns_nam; /* 24 4 */ struct mbuf * ns_raw; /* 28 4 */ /* --- cacheline 1 boundary (32 bytes) --- */ struct mbuf * ns_rawend; /* 32 4 */ struct mbuf * ns_rec; /* 36 4 */ struct mbuf * ns_recend; /* 40 4 */ struct mbuf * ns_frag; /* 44 4 */ int ns_flag; /* 48 4 */ int ns_solock; /* 52 4 */ int ns_cc; /* 56 4 */ int ns_reclen; /* 60 4 */ /* --- cacheline 2 boundary (64 bytes) --- */ int ns_numuids; /* 64 4 */ u_int32_t ns_sref; /* 68 4 */ struct { struct nfsrv_descript * lh_first; /* 0 4 */ } ns_tq; /* 72 4 */ struct ns_uidhashtbl[29]; /* 76 116 */ /* --- cacheline 6 boundary (192 bytes) --- */ struct nfsrvw_delayhash ns_wdelayhashtbl[16]; /* 192 64 */ /* --- cacheline 8 boundary (256 bytes) --- */ }; /* size: 256, cachelines: 8 */ /* definitions: 12 */ Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 22:46:47 +01:00
if (type__name(ctype, cu) != NULL && !expand_types)
printed += fprintf(fp, "struct %-*s %s",
conf->type_spacing - 7,
type__name(ctype, cu), name);
else {
struct class *class = tag__class(type);
class__find_holes(class, cu);
printed += class__fprintf(class, cu, &tconf, fp);
}
break;
case DW_TAG_union_type:
ctype = tag__type(type);
[CLASSES]: Ditch class_member__names Was a awful function, to replace it added some new __snprintf methods for more classes (array_type, class_member, etc), the end result is a much nicer rendering, for instance: @@ -6549,11 +6549,11 @@ /* XXX 2 bytes hole, try to pack */ union { - struct ff_constant_effect constant; /* 10 */ - struct ff_ramp_effect ramp; /* 12 */ - struct ff_periodic_effect periodic; /* 28 */ - struct ff_condition_effect condition[2]; /* 24 */ - struct ff_rumble_effect rumble; /* 4 */ + struct ff_constant_effect constant; /* 10 */ + struct ff_ramp_effect ramp; /* 12 */ + struct ff_periodic_effect periodic; /* 28 */ + struct ff_condition_effect condition[2]; /* 24 */ + struct ff_rumble_effect rumble; /* 4 */ } u; /* 16 28 */ /* --- cacheline 1 boundary (32 bytes) was 12 bytes ago --- */ }; /* size: 44, cachelines: 2 */ Previously when such big class members appeared the comments with the size and offset were unaligned, now its only in extreme cases, such as the array above that things get unaligned. End result is a smaller library: [acme@newtoy pahole]$ codiff -V build/libclasses.so.orig build/libclasses.so /home/acme/pahole/classes.c: struct array_type | -4 nr_members: -1 -const char *name /* 36 4 */ 1 struct changed enumeration__print | +10 # 175 -> 185 union__snprintf | +32 # 576 -> 608 union__print | +16 # 182 -> 198 class_member__names | -851 (removed) class_member__print | -721 # 1218 -> 497 class__print_struct | +54 # 1403 -> 1457 6 functions changed, 112 bytes added, 1572 bytes removed, diff: -1460 /home/acme/pahole/classes.c: array_type__snprintf | +249 (added) class_member__snprintf | +892 (added) 2 functions changed, 1141 bytes added build/libclasses.so: 8 functions changed, 1253 bytes added, 1572 bytes removed, diff: -319 Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 17:19:55 +01:00
if (type__name(ctype, cu) != NULL && !expand_types)
printed += fprintf(fp, "union %-*s %s",
conf->type_spacing - 6,
type__name(ctype, cu), name);
else
printed += union__fprintf(ctype, cu, &tconf, fp);
break;
case DW_TAG_enumeration_type:
ctype = tag__type(type);
[CLASSES]: Ditch class_member__names Was a awful function, to replace it added some new __snprintf methods for more classes (array_type, class_member, etc), the end result is a much nicer rendering, for instance: @@ -6549,11 +6549,11 @@ /* XXX 2 bytes hole, try to pack */ union { - struct ff_constant_effect constant; /* 10 */ - struct ff_ramp_effect ramp; /* 12 */ - struct ff_periodic_effect periodic; /* 28 */ - struct ff_condition_effect condition[2]; /* 24 */ - struct ff_rumble_effect rumble; /* 4 */ + struct ff_constant_effect constant; /* 10 */ + struct ff_ramp_effect ramp; /* 12 */ + struct ff_periodic_effect periodic; /* 28 */ + struct ff_condition_effect condition[2]; /* 24 */ + struct ff_rumble_effect rumble; /* 4 */ } u; /* 16 28 */ /* --- cacheline 1 boundary (32 bytes) was 12 bytes ago --- */ }; /* size: 44, cachelines: 2 */ Previously when such big class members appeared the comments with the size and offset were unaligned, now its only in extreme cases, such as the array above that things get unaligned. End result is a smaller library: [acme@newtoy pahole]$ codiff -V build/libclasses.so.orig build/libclasses.so /home/acme/pahole/classes.c: struct array_type | -4 nr_members: -1 -const char *name /* 36 4 */ 1 struct changed enumeration__print | +10 # 175 -> 185 union__snprintf | +32 # 576 -> 608 union__print | +16 # 182 -> 198 class_member__names | -851 (removed) class_member__print | -721 # 1218 -> 497 class__print_struct | +54 # 1403 -> 1457 6 functions changed, 112 bytes added, 1572 bytes removed, diff: -1460 /home/acme/pahole/classes.c: array_type__snprintf | +249 (added) class_member__snprintf | +892 (added) 2 functions changed, 1141 bytes added build/libclasses.so: 8 functions changed, 1253 bytes added, 1572 bytes removed, diff: -319 Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 17:19:55 +01:00
if (type__name(ctype, cu) != NULL)
printed += fprintf(fp, "enum %-*s %s",
conf->type_spacing - 5,
type__name(ctype, cu), name);
else
printed += enumeration__fprintf(type, cu, &tconf, fp);
break;
[CLASSES]: Ditch class_member__names Was a awful function, to replace it added some new __snprintf methods for more classes (array_type, class_member, etc), the end result is a much nicer rendering, for instance: @@ -6549,11 +6549,11 @@ /* XXX 2 bytes hole, try to pack */ union { - struct ff_constant_effect constant; /* 10 */ - struct ff_ramp_effect ramp; /* 12 */ - struct ff_periodic_effect periodic; /* 28 */ - struct ff_condition_effect condition[2]; /* 24 */ - struct ff_rumble_effect rumble; /* 4 */ + struct ff_constant_effect constant; /* 10 */ + struct ff_ramp_effect ramp; /* 12 */ + struct ff_periodic_effect periodic; /* 28 */ + struct ff_condition_effect condition[2]; /* 24 */ + struct ff_rumble_effect rumble; /* 4 */ } u; /* 16 28 */ /* --- cacheline 1 boundary (32 bytes) was 12 bytes ago --- */ }; /* size: 44, cachelines: 2 */ Previously when such big class members appeared the comments with the size and offset were unaligned, now its only in extreme cases, such as the array above that things get unaligned. End result is a smaller library: [acme@newtoy pahole]$ codiff -V build/libclasses.so.orig build/libclasses.so /home/acme/pahole/classes.c: struct array_type | -4 nr_members: -1 -const char *name /* 36 4 */ 1 struct changed enumeration__print | +10 # 175 -> 185 union__snprintf | +32 # 576 -> 608 union__print | +16 # 182 -> 198 class_member__names | -851 (removed) class_member__print | -721 # 1218 -> 497 class__print_struct | +54 # 1403 -> 1457 6 functions changed, 112 bytes added, 1572 bytes removed, diff: -1460 /home/acme/pahole/classes.c: array_type__snprintf | +249 (added) class_member__snprintf | +892 (added) 2 functions changed, 1141 bytes added build/libclasses.so: 8 functions changed, 1253 bytes added, 1572 bytes removed, diff: -319 Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 17:19:55 +01:00
}
out:
if (conf->expand_types)
--type->recursivity_level;
return printed;
out_type_not_found:
printed = fprintf(fp, "%-*s %s", conf->type_spacing, "<ERROR>", name);
goto out;
[CLASSES]: Ditch class_member__names Was a awful function, to replace it added some new __snprintf methods for more classes (array_type, class_member, etc), the end result is a much nicer rendering, for instance: @@ -6549,11 +6549,11 @@ /* XXX 2 bytes hole, try to pack */ union { - struct ff_constant_effect constant; /* 10 */ - struct ff_ramp_effect ramp; /* 12 */ - struct ff_periodic_effect periodic; /* 28 */ - struct ff_condition_effect condition[2]; /* 24 */ - struct ff_rumble_effect rumble; /* 4 */ + struct ff_constant_effect constant; /* 10 */ + struct ff_ramp_effect ramp; /* 12 */ + struct ff_periodic_effect periodic; /* 28 */ + struct ff_condition_effect condition[2]; /* 24 */ + struct ff_rumble_effect rumble; /* 4 */ } u; /* 16 28 */ /* --- cacheline 1 boundary (32 bytes) was 12 bytes ago --- */ }; /* size: 44, cachelines: 2 */ Previously when such big class members appeared the comments with the size and offset were unaligned, now its only in extreme cases, such as the array above that things get unaligned. End result is a smaller library: [acme@newtoy pahole]$ codiff -V build/libclasses.so.orig build/libclasses.so /home/acme/pahole/classes.c: struct array_type | -4 nr_members: -1 -const char *name /* 36 4 */ 1 struct changed enumeration__print | +10 # 175 -> 185 union__snprintf | +32 # 576 -> 608 union__print | +16 # 182 -> 198 class_member__names | -851 (removed) class_member__print | -721 # 1218 -> 497 class__print_struct | +54 # 1403 -> 1457 6 functions changed, 112 bytes added, 1572 bytes removed, diff: -1460 /home/acme/pahole/classes.c: array_type__snprintf | +249 (added) class_member__snprintf | +892 (added) 2 functions changed, 1141 bytes added build/libclasses.so: 8 functions changed, 1253 bytes added, 1572 bytes removed, diff: -319 Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 17:19:55 +01:00
}
static size_t struct_member__fprintf(struct class_member *self,
struct tag *type, const struct cu *cu,
const struct conf_fprintf *conf, FILE *fp)
[CLASSES]: Ditch class_member__names Was a awful function, to replace it added some new __snprintf methods for more classes (array_type, class_member, etc), the end result is a much nicer rendering, for instance: @@ -6549,11 +6549,11 @@ /* XXX 2 bytes hole, try to pack */ union { - struct ff_constant_effect constant; /* 10 */ - struct ff_ramp_effect ramp; /* 12 */ - struct ff_periodic_effect periodic; /* 28 */ - struct ff_condition_effect condition[2]; /* 24 */ - struct ff_rumble_effect rumble; /* 4 */ + struct ff_constant_effect constant; /* 10 */ + struct ff_ramp_effect ramp; /* 12 */ + struct ff_periodic_effect periodic; /* 28 */ + struct ff_condition_effect condition[2]; /* 24 */ + struct ff_rumble_effect rumble; /* 4 */ } u; /* 16 28 */ /* --- cacheline 1 boundary (32 bytes) was 12 bytes ago --- */ }; /* size: 44, cachelines: 2 */ Previously when such big class members appeared the comments with the size and offset were unaligned, now its only in extreme cases, such as the array above that things get unaligned. End result is a smaller library: [acme@newtoy pahole]$ codiff -V build/libclasses.so.orig build/libclasses.so /home/acme/pahole/classes.c: struct array_type | -4 nr_members: -1 -const char *name /* 36 4 */ 1 struct changed enumeration__print | +10 # 175 -> 185 union__snprintf | +32 # 576 -> 608 union__print | +16 # 182 -> 198 class_member__names | -851 (removed) class_member__print | -721 # 1218 -> 497 class__print_struct | +54 # 1403 -> 1457 6 functions changed, 112 bytes added, 1572 bytes removed, diff: -1460 /home/acme/pahole/classes.c: array_type__snprintf | +249 (added) class_member__snprintf | +892 (added) 2 functions changed, 1141 bytes added build/libclasses.so: 8 functions changed, 1253 bytes added, 1572 bytes removed, diff: -319 Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 17:19:55 +01:00
{
const int size = tag__size(type, cu);
struct conf_fprintf sconf = *conf;
uint32_t offset = self->offset;
size_t printed = 0;
const char *name = self->name;
if (!sconf.rel_offset) {
sconf.base_offset += self->offset;
offset = sconf.base_offset;
}
if (self->tag.tag == DW_TAG_inheritance) {
name = "<ancestor>";
printed += fprintf(fp, "/* ");
}
printed += type__fprintf(type, cu, name, &sconf, fp);
[CLASSES]: Ditch class_member__names Was a awful function, to replace it added some new __snprintf methods for more classes (array_type, class_member, etc), the end result is a much nicer rendering, for instance: @@ -6549,11 +6549,11 @@ /* XXX 2 bytes hole, try to pack */ union { - struct ff_constant_effect constant; /* 10 */ - struct ff_ramp_effect ramp; /* 12 */ - struct ff_periodic_effect periodic; /* 28 */ - struct ff_condition_effect condition[2]; /* 24 */ - struct ff_rumble_effect rumble; /* 4 */ + struct ff_constant_effect constant; /* 10 */ + struct ff_ramp_effect ramp; /* 12 */ + struct ff_periodic_effect periodic; /* 28 */ + struct ff_condition_effect condition[2]; /* 24 */ + struct ff_rumble_effect rumble; /* 4 */ } u; /* 16 28 */ /* --- cacheline 1 boundary (32 bytes) was 12 bytes ago --- */ }; /* size: 44, cachelines: 2 */ Previously when such big class members appeared the comments with the size and offset were unaligned, now its only in extreme cases, such as the array above that things get unaligned. End result is a smaller library: [acme@newtoy pahole]$ codiff -V build/libclasses.so.orig build/libclasses.so /home/acme/pahole/classes.c: struct array_type | -4 nr_members: -1 -const char *name /* 36 4 */ 1 struct changed enumeration__print | +10 # 175 -> 185 union__snprintf | +32 # 576 -> 608 union__print | +16 # 182 -> 198 class_member__names | -851 (removed) class_member__print | -721 # 1218 -> 497 class__print_struct | +54 # 1403 -> 1457 6 functions changed, 112 bytes added, 1572 bytes removed, diff: -1460 /home/acme/pahole/classes.c: array_type__snprintf | +249 (added) class_member__snprintf | +892 (added) 2 functions changed, 1141 bytes added build/libclasses.so: 8 functions changed, 1253 bytes added, 1572 bytes removed, diff: -319 Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 17:19:55 +01:00
if (self->bit_size != 0)
printed += fprintf(fp, ":%u;", self->bit_size);
else {
fputc(';', fp);
++printed;
}
if ((tag__is_union(type) || tag__is_struct(type) ||
tag__is_enumeration(type)) &&
[CLASSES]: Fully support nested classes Example: [acme@newtoy pahole]$ pahole net/ipv4/tcp.o flowi /* include/net/flow.h:13 */ struct flowi { int oif; /* 0 4 */ int iif; /* 4 4 */ __u32 mark; /* 8 4 */ union { struct { __be32 daddr; /* 0 4 */ __be32 saddr; /* 4 4 */ __u8 tos; /* 8 1 */ __u8 scope; /* 9 1 */ } ip4_u; /* 12 */ struct { struct in6_addr daddr; /* 0 16 */ struct in6_addr saddr; /* 16 16 */ /* --- cacheline 1 boundary (32 bytes) --- */ __be32 flowlabel; /* 32 4 */ } ip6_u; /* 36 */ struct { __le16 daddr; /* 0 2 */ __le16 saddr; /* 2 2 */ __u8 scope; /* 4 1 */ } dn_u; /* 6 */ } nl_u; /* 12 36 */ /* --- cacheline 1 boundary (32 bytes) was 16 bytes ago --- */ __u8 proto; /* 48 1 */ __u8 flags; /* 49 1 */ /* XXX 2 bytes hole, try to pack */ union { struct { __be16 sport; /* 0 2 */ __be16 dport; /* 2 2 */ } ports; /* 4 */ struct { __u8 type; /* 0 1 */ __u8 code; /* 1 1 */ } icmpt; /* 2 */ struct { __le16 sport; /* 0 2 */ __le16 dport; /* 2 2 */ } dnports; /* 4 */ __be32 spi; /* 4 */ } uli_u; /* 52 4 */ __u32 secid; /* 56 4 */ }; /* size: 60, cachelines: 2 */ /* sum members: 58, holes: 1, sum holes: 2 */ /* last cacheline: 28 bytes */ Supporting anonymous structs and unions just fine, even combinations of both, like in struct page, in the Linux kernel: [acme@newtoy pahole]$ pahole mm/mmap.o page /* include/linux/mmzone.h:391 */ struct page { long unsigned int flags; /* 0 4 */ atomic_t _count; /* 4 4 */ atomic_t _mapcount; /* 8 4 */ union { struct { long unsigned int private; /* 0 4 */ struct address_space * mapping; /* 4 4 */ }; /* 8 */ }; /* 12 8 */ long unsigned int index; /* 20 4 */ struct list_head lru; /* 24 8 */ /* --- cacheline 1 boundary (32 bytes) --- */ }; /* size: 32, cachelines: 1 */ Or struct freebsd_sys_getdents_args in the OpenBSD kernel: /* /usr/home/leonardo/openbsd/src/sys/compat/freebsd/freebsd_syscallargs.h:231 */ struct freebsd_sys_getdents_args { union { register_t pad; /* 4 */ struct { int datum; /* 0 4 */ } le; /* 4 */ struct { int8_t pad[0]; /* 0 0 */ int datum; /* 0 4 */ } be; /* 4 */ } fd; /* 0 4 */ union { register_t pad; /* 4 */ struct { void * datum; /* 0 4 */ } le; /* 4 */ struct { int8_t pad[0]; /* 0 0 */ void * datum; /* 0 4 */ } be; /* 4 */ } dirent; /* 4 4 */ union { register_t pad; /* 4 */ struct { unsigned int datum; /* 0 4 */ } le; /* 4 */ struct { int8_t pad[0]; /* 0 0 */ unsigned int datum; /* 0 4 */ } be; /* 4 */ } count; /* 8 4 */ }; /* size: 12, cachelines: 1 */ /* last cacheline: 12 bytes */ /* definitions: 7 */ One more from the OpenBSD kernel: /* /usr/home/leonardo/openbsd/src/sys/nfs/nfs.h:344 */ struct nfssvc_sock { struct { struct nfssvc_sock * tqe_next; /* 0 4 */ struct nfssvc_sock * * tqe_prev; /* 4 4 */ } ns_chain; /* 0 8 */ struct { struct nfsuid * tqh_first; /* 0 4 */ struct nfsuid * * tqh_last; /* 4 4 */ } ns_uidlruhead; /* 8 8 */ struct file * ns_fp; /* 16 4 */ struct socket * ns_so; /* 20 4 */ struct mbuf * ns_nam; /* 24 4 */ struct mbuf * ns_raw; /* 28 4 */ /* --- cacheline 1 boundary (32 bytes) --- */ struct mbuf * ns_rawend; /* 32 4 */ struct mbuf * ns_rec; /* 36 4 */ struct mbuf * ns_recend; /* 40 4 */ struct mbuf * ns_frag; /* 44 4 */ int ns_flag; /* 48 4 */ int ns_solock; /* 52 4 */ int ns_cc; /* 56 4 */ int ns_reclen; /* 60 4 */ /* --- cacheline 2 boundary (64 bytes) --- */ int ns_numuids; /* 64 4 */ u_int32_t ns_sref; /* 68 4 */ struct { struct nfsrv_descript * lh_first; /* 0 4 */ } ns_tq; /* 72 4 */ struct ns_uidhashtbl[29]; /* 76 116 */ /* --- cacheline 6 boundary (192 bytes) --- */ struct nfsrvw_delayhash ns_wdelayhashtbl[16]; /* 192 64 */ /* --- cacheline 8 boundary (256 bytes) --- */ }; /* size: 256, cachelines: 8 */ /* definitions: 12 */ Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 22:46:47 +01:00
/* Look if is a type defined inline */
type__name(tag__type(type), cu) == NULL) {
if (!sconf.suppress_offset_comment) {
/* Check if this is a anonymous union */
const int slen = self->name != NULL ?
(int)strlen(self->name) : -1;
printed += fprintf(fp, "%*s/* %5u %5u */",
(sconf.type_spacing +
sconf.name_spacing - slen - 3),
" ", offset, size);
}
} else {
int spacing = sconf.type_spacing + sconf.name_spacing - printed;
if (self->tag.tag == DW_TAG_inheritance) {
const size_t p = fprintf(fp, " */");
printed += p;
spacing -= p;
}
if (!sconf.suppress_offset_comment) {
int size_spacing = 5;
printed += fprintf(fp, "%*s/* %5u",
spacing > 0 ? spacing : 0, " ",
offset);
if (self->bit_size != 0) {
printed += fprintf(fp, ":%2d", self->bit_offset);
size_spacing -= 3;
}
printed += fprintf(fp, " %*u */", size_spacing, size);
}
}
return printed;
[CLASSES]: Fully support nested classes Example: [acme@newtoy pahole]$ pahole net/ipv4/tcp.o flowi /* include/net/flow.h:13 */ struct flowi { int oif; /* 0 4 */ int iif; /* 4 4 */ __u32 mark; /* 8 4 */ union { struct { __be32 daddr; /* 0 4 */ __be32 saddr; /* 4 4 */ __u8 tos; /* 8 1 */ __u8 scope; /* 9 1 */ } ip4_u; /* 12 */ struct { struct in6_addr daddr; /* 0 16 */ struct in6_addr saddr; /* 16 16 */ /* --- cacheline 1 boundary (32 bytes) --- */ __be32 flowlabel; /* 32 4 */ } ip6_u; /* 36 */ struct { __le16 daddr; /* 0 2 */ __le16 saddr; /* 2 2 */ __u8 scope; /* 4 1 */ } dn_u; /* 6 */ } nl_u; /* 12 36 */ /* --- cacheline 1 boundary (32 bytes) was 16 bytes ago --- */ __u8 proto; /* 48 1 */ __u8 flags; /* 49 1 */ /* XXX 2 bytes hole, try to pack */ union { struct { __be16 sport; /* 0 2 */ __be16 dport; /* 2 2 */ } ports; /* 4 */ struct { __u8 type; /* 0 1 */ __u8 code; /* 1 1 */ } icmpt; /* 2 */ struct { __le16 sport; /* 0 2 */ __le16 dport; /* 2 2 */ } dnports; /* 4 */ __be32 spi; /* 4 */ } uli_u; /* 52 4 */ __u32 secid; /* 56 4 */ }; /* size: 60, cachelines: 2 */ /* sum members: 58, holes: 1, sum holes: 2 */ /* last cacheline: 28 bytes */ Supporting anonymous structs and unions just fine, even combinations of both, like in struct page, in the Linux kernel: [acme@newtoy pahole]$ pahole mm/mmap.o page /* include/linux/mmzone.h:391 */ struct page { long unsigned int flags; /* 0 4 */ atomic_t _count; /* 4 4 */ atomic_t _mapcount; /* 8 4 */ union { struct { long unsigned int private; /* 0 4 */ struct address_space * mapping; /* 4 4 */ }; /* 8 */ }; /* 12 8 */ long unsigned int index; /* 20 4 */ struct list_head lru; /* 24 8 */ /* --- cacheline 1 boundary (32 bytes) --- */ }; /* size: 32, cachelines: 1 */ Or struct freebsd_sys_getdents_args in the OpenBSD kernel: /* /usr/home/leonardo/openbsd/src/sys/compat/freebsd/freebsd_syscallargs.h:231 */ struct freebsd_sys_getdents_args { union { register_t pad; /* 4 */ struct { int datum; /* 0 4 */ } le; /* 4 */ struct { int8_t pad[0]; /* 0 0 */ int datum; /* 0 4 */ } be; /* 4 */ } fd; /* 0 4 */ union { register_t pad; /* 4 */ struct { void * datum; /* 0 4 */ } le; /* 4 */ struct { int8_t pad[0]; /* 0 0 */ void * datum; /* 0 4 */ } be; /* 4 */ } dirent; /* 4 4 */ union { register_t pad; /* 4 */ struct { unsigned int datum; /* 0 4 */ } le; /* 4 */ struct { int8_t pad[0]; /* 0 0 */ unsigned int datum; /* 0 4 */ } be; /* 4 */ } count; /* 8 4 */ }; /* size: 12, cachelines: 1 */ /* last cacheline: 12 bytes */ /* definitions: 7 */ One more from the OpenBSD kernel: /* /usr/home/leonardo/openbsd/src/sys/nfs/nfs.h:344 */ struct nfssvc_sock { struct { struct nfssvc_sock * tqe_next; /* 0 4 */ struct nfssvc_sock * * tqe_prev; /* 4 4 */ } ns_chain; /* 0 8 */ struct { struct nfsuid * tqh_first; /* 0 4 */ struct nfsuid * * tqh_last; /* 4 4 */ } ns_uidlruhead; /* 8 8 */ struct file * ns_fp; /* 16 4 */ struct socket * ns_so; /* 20 4 */ struct mbuf * ns_nam; /* 24 4 */ struct mbuf * ns_raw; /* 28 4 */ /* --- cacheline 1 boundary (32 bytes) --- */ struct mbuf * ns_rawend; /* 32 4 */ struct mbuf * ns_rec; /* 36 4 */ struct mbuf * ns_recend; /* 40 4 */ struct mbuf * ns_frag; /* 44 4 */ int ns_flag; /* 48 4 */ int ns_solock; /* 52 4 */ int ns_cc; /* 56 4 */ int ns_reclen; /* 60 4 */ /* --- cacheline 2 boundary (64 bytes) --- */ int ns_numuids; /* 64 4 */ u_int32_t ns_sref; /* 68 4 */ struct { struct nfsrv_descript * lh_first; /* 0 4 */ } ns_tq; /* 72 4 */ struct ns_uidhashtbl[29]; /* 76 116 */ /* --- cacheline 6 boundary (192 bytes) --- */ struct nfsrvw_delayhash ns_wdelayhashtbl[16]; /* 192 64 */ /* --- cacheline 8 boundary (256 bytes) --- */ }; /* size: 256, cachelines: 8 */ /* definitions: 12 */ Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 22:46:47 +01:00
}
static size_t union_member__fprintf(struct class_member *self,
struct tag *type, const struct cu *cu,
const struct conf_fprintf *conf, FILE *fp)
[CLASSES]: Fully support nested classes Example: [acme@newtoy pahole]$ pahole net/ipv4/tcp.o flowi /* include/net/flow.h:13 */ struct flowi { int oif; /* 0 4 */ int iif; /* 4 4 */ __u32 mark; /* 8 4 */ union { struct { __be32 daddr; /* 0 4 */ __be32 saddr; /* 4 4 */ __u8 tos; /* 8 1 */ __u8 scope; /* 9 1 */ } ip4_u; /* 12 */ struct { struct in6_addr daddr; /* 0 16 */ struct in6_addr saddr; /* 16 16 */ /* --- cacheline 1 boundary (32 bytes) --- */ __be32 flowlabel; /* 32 4 */ } ip6_u; /* 36 */ struct { __le16 daddr; /* 0 2 */ __le16 saddr; /* 2 2 */ __u8 scope; /* 4 1 */ } dn_u; /* 6 */ } nl_u; /* 12 36 */ /* --- cacheline 1 boundary (32 bytes) was 16 bytes ago --- */ __u8 proto; /* 48 1 */ __u8 flags; /* 49 1 */ /* XXX 2 bytes hole, try to pack */ union { struct { __be16 sport; /* 0 2 */ __be16 dport; /* 2 2 */ } ports; /* 4 */ struct { __u8 type; /* 0 1 */ __u8 code; /* 1 1 */ } icmpt; /* 2 */ struct { __le16 sport; /* 0 2 */ __le16 dport; /* 2 2 */ } dnports; /* 4 */ __be32 spi; /* 4 */ } uli_u; /* 52 4 */ __u32 secid; /* 56 4 */ }; /* size: 60, cachelines: 2 */ /* sum members: 58, holes: 1, sum holes: 2 */ /* last cacheline: 28 bytes */ Supporting anonymous structs and unions just fine, even combinations of both, like in struct page, in the Linux kernel: [acme@newtoy pahole]$ pahole mm/mmap.o page /* include/linux/mmzone.h:391 */ struct page { long unsigned int flags; /* 0 4 */ atomic_t _count; /* 4 4 */ atomic_t _mapcount; /* 8 4 */ union { struct { long unsigned int private; /* 0 4 */ struct address_space * mapping; /* 4 4 */ }; /* 8 */ }; /* 12 8 */ long unsigned int index; /* 20 4 */ struct list_head lru; /* 24 8 */ /* --- cacheline 1 boundary (32 bytes) --- */ }; /* size: 32, cachelines: 1 */ Or struct freebsd_sys_getdents_args in the OpenBSD kernel: /* /usr/home/leonardo/openbsd/src/sys/compat/freebsd/freebsd_syscallargs.h:231 */ struct freebsd_sys_getdents_args { union { register_t pad; /* 4 */ struct { int datum; /* 0 4 */ } le; /* 4 */ struct { int8_t pad[0]; /* 0 0 */ int datum; /* 0 4 */ } be; /* 4 */ } fd; /* 0 4 */ union { register_t pad; /* 4 */ struct { void * datum; /* 0 4 */ } le; /* 4 */ struct { int8_t pad[0]; /* 0 0 */ void * datum; /* 0 4 */ } be; /* 4 */ } dirent; /* 4 4 */ union { register_t pad; /* 4 */ struct { unsigned int datum; /* 0 4 */ } le; /* 4 */ struct { int8_t pad[0]; /* 0 0 */ unsigned int datum; /* 0 4 */ } be; /* 4 */ } count; /* 8 4 */ }; /* size: 12, cachelines: 1 */ /* last cacheline: 12 bytes */ /* definitions: 7 */ One more from the OpenBSD kernel: /* /usr/home/leonardo/openbsd/src/sys/nfs/nfs.h:344 */ struct nfssvc_sock { struct { struct nfssvc_sock * tqe_next; /* 0 4 */ struct nfssvc_sock * * tqe_prev; /* 4 4 */ } ns_chain; /* 0 8 */ struct { struct nfsuid * tqh_first; /* 0 4 */ struct nfsuid * * tqh_last; /* 4 4 */ } ns_uidlruhead; /* 8 8 */ struct file * ns_fp; /* 16 4 */ struct socket * ns_so; /* 20 4 */ struct mbuf * ns_nam; /* 24 4 */ struct mbuf * ns_raw; /* 28 4 */ /* --- cacheline 1 boundary (32 bytes) --- */ struct mbuf * ns_rawend; /* 32 4 */ struct mbuf * ns_rec; /* 36 4 */ struct mbuf * ns_recend; /* 40 4 */ struct mbuf * ns_frag; /* 44 4 */ int ns_flag; /* 48 4 */ int ns_solock; /* 52 4 */ int ns_cc; /* 56 4 */ int ns_reclen; /* 60 4 */ /* --- cacheline 2 boundary (64 bytes) --- */ int ns_numuids; /* 64 4 */ u_int32_t ns_sref; /* 68 4 */ struct { struct nfsrv_descript * lh_first; /* 0 4 */ } ns_tq; /* 72 4 */ struct ns_uidhashtbl[29]; /* 76 116 */ /* --- cacheline 6 boundary (192 bytes) --- */ struct nfsrvw_delayhash ns_wdelayhashtbl[16]; /* 192 64 */ /* --- cacheline 8 boundary (256 bytes) --- */ }; /* size: 256, cachelines: 8 */ /* definitions: 12 */ Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 22:46:47 +01:00
{
const size_t size = tag__size(type, cu);
size_t printed = type__fprintf(type, cu, self->name, conf, fp);
[CLASSES]: Fully support nested classes Example: [acme@newtoy pahole]$ pahole net/ipv4/tcp.o flowi /* include/net/flow.h:13 */ struct flowi { int oif; /* 0 4 */ int iif; /* 4 4 */ __u32 mark; /* 8 4 */ union { struct { __be32 daddr; /* 0 4 */ __be32 saddr; /* 4 4 */ __u8 tos; /* 8 1 */ __u8 scope; /* 9 1 */ } ip4_u; /* 12 */ struct { struct in6_addr daddr; /* 0 16 */ struct in6_addr saddr; /* 16 16 */ /* --- cacheline 1 boundary (32 bytes) --- */ __be32 flowlabel; /* 32 4 */ } ip6_u; /* 36 */ struct { __le16 daddr; /* 0 2 */ __le16 saddr; /* 2 2 */ __u8 scope; /* 4 1 */ } dn_u; /* 6 */ } nl_u; /* 12 36 */ /* --- cacheline 1 boundary (32 bytes) was 16 bytes ago --- */ __u8 proto; /* 48 1 */ __u8 flags; /* 49 1 */ /* XXX 2 bytes hole, try to pack */ union { struct { __be16 sport; /* 0 2 */ __be16 dport; /* 2 2 */ } ports; /* 4 */ struct { __u8 type; /* 0 1 */ __u8 code; /* 1 1 */ } icmpt; /* 2 */ struct { __le16 sport; /* 0 2 */ __le16 dport; /* 2 2 */ } dnports; /* 4 */ __be32 spi; /* 4 */ } uli_u; /* 52 4 */ __u32 secid; /* 56 4 */ }; /* size: 60, cachelines: 2 */ /* sum members: 58, holes: 1, sum holes: 2 */ /* last cacheline: 28 bytes */ Supporting anonymous structs and unions just fine, even combinations of both, like in struct page, in the Linux kernel: [acme@newtoy pahole]$ pahole mm/mmap.o page /* include/linux/mmzone.h:391 */ struct page { long unsigned int flags; /* 0 4 */ atomic_t _count; /* 4 4 */ atomic_t _mapcount; /* 8 4 */ union { struct { long unsigned int private; /* 0 4 */ struct address_space * mapping; /* 4 4 */ }; /* 8 */ }; /* 12 8 */ long unsigned int index; /* 20 4 */ struct list_head lru; /* 24 8 */ /* --- cacheline 1 boundary (32 bytes) --- */ }; /* size: 32, cachelines: 1 */ Or struct freebsd_sys_getdents_args in the OpenBSD kernel: /* /usr/home/leonardo/openbsd/src/sys/compat/freebsd/freebsd_syscallargs.h:231 */ struct freebsd_sys_getdents_args { union { register_t pad; /* 4 */ struct { int datum; /* 0 4 */ } le; /* 4 */ struct { int8_t pad[0]; /* 0 0 */ int datum; /* 0 4 */ } be; /* 4 */ } fd; /* 0 4 */ union { register_t pad; /* 4 */ struct { void * datum; /* 0 4 */ } le; /* 4 */ struct { int8_t pad[0]; /* 0 0 */ void * datum; /* 0 4 */ } be; /* 4 */ } dirent; /* 4 4 */ union { register_t pad; /* 4 */ struct { unsigned int datum; /* 0 4 */ } le; /* 4 */ struct { int8_t pad[0]; /* 0 0 */ unsigned int datum; /* 0 4 */ } be; /* 4 */ } count; /* 8 4 */ }; /* size: 12, cachelines: 1 */ /* last cacheline: 12 bytes */ /* definitions: 7 */ One more from the OpenBSD kernel: /* /usr/home/leonardo/openbsd/src/sys/nfs/nfs.h:344 */ struct nfssvc_sock { struct { struct nfssvc_sock * tqe_next; /* 0 4 */ struct nfssvc_sock * * tqe_prev; /* 4 4 */ } ns_chain; /* 0 8 */ struct { struct nfsuid * tqh_first; /* 0 4 */ struct nfsuid * * tqh_last; /* 4 4 */ } ns_uidlruhead; /* 8 8 */ struct file * ns_fp; /* 16 4 */ struct socket * ns_so; /* 20 4 */ struct mbuf * ns_nam; /* 24 4 */ struct mbuf * ns_raw; /* 28 4 */ /* --- cacheline 1 boundary (32 bytes) --- */ struct mbuf * ns_rawend; /* 32 4 */ struct mbuf * ns_rec; /* 36 4 */ struct mbuf * ns_recend; /* 40 4 */ struct mbuf * ns_frag; /* 44 4 */ int ns_flag; /* 48 4 */ int ns_solock; /* 52 4 */ int ns_cc; /* 56 4 */ int ns_reclen; /* 60 4 */ /* --- cacheline 2 boundary (64 bytes) --- */ int ns_numuids; /* 64 4 */ u_int32_t ns_sref; /* 68 4 */ struct { struct nfsrv_descript * lh_first; /* 0 4 */ } ns_tq; /* 72 4 */ struct ns_uidhashtbl[29]; /* 76 116 */ /* --- cacheline 6 boundary (192 bytes) --- */ struct nfsrvw_delayhash ns_wdelayhashtbl[16]; /* 192 64 */ /* --- cacheline 8 boundary (256 bytes) --- */ }; /* size: 256, cachelines: 8 */ /* definitions: 12 */ Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 22:46:47 +01:00
if ((tag__is_union(type) || tag__is_struct(type) ||
tag__is_enumeration(type)) &&
[CLASSES]: Fully support nested classes Example: [acme@newtoy pahole]$ pahole net/ipv4/tcp.o flowi /* include/net/flow.h:13 */ struct flowi { int oif; /* 0 4 */ int iif; /* 4 4 */ __u32 mark; /* 8 4 */ union { struct { __be32 daddr; /* 0 4 */ __be32 saddr; /* 4 4 */ __u8 tos; /* 8 1 */ __u8 scope; /* 9 1 */ } ip4_u; /* 12 */ struct { struct in6_addr daddr; /* 0 16 */ struct in6_addr saddr; /* 16 16 */ /* --- cacheline 1 boundary (32 bytes) --- */ __be32 flowlabel; /* 32 4 */ } ip6_u; /* 36 */ struct { __le16 daddr; /* 0 2 */ __le16 saddr; /* 2 2 */ __u8 scope; /* 4 1 */ } dn_u; /* 6 */ } nl_u; /* 12 36 */ /* --- cacheline 1 boundary (32 bytes) was 16 bytes ago --- */ __u8 proto; /* 48 1 */ __u8 flags; /* 49 1 */ /* XXX 2 bytes hole, try to pack */ union { struct { __be16 sport; /* 0 2 */ __be16 dport; /* 2 2 */ } ports; /* 4 */ struct { __u8 type; /* 0 1 */ __u8 code; /* 1 1 */ } icmpt; /* 2 */ struct { __le16 sport; /* 0 2 */ __le16 dport; /* 2 2 */ } dnports; /* 4 */ __be32 spi; /* 4 */ } uli_u; /* 52 4 */ __u32 secid; /* 56 4 */ }; /* size: 60, cachelines: 2 */ /* sum members: 58, holes: 1, sum holes: 2 */ /* last cacheline: 28 bytes */ Supporting anonymous structs and unions just fine, even combinations of both, like in struct page, in the Linux kernel: [acme@newtoy pahole]$ pahole mm/mmap.o page /* include/linux/mmzone.h:391 */ struct page { long unsigned int flags; /* 0 4 */ atomic_t _count; /* 4 4 */ atomic_t _mapcount; /* 8 4 */ union { struct { long unsigned int private; /* 0 4 */ struct address_space * mapping; /* 4 4 */ }; /* 8 */ }; /* 12 8 */ long unsigned int index; /* 20 4 */ struct list_head lru; /* 24 8 */ /* --- cacheline 1 boundary (32 bytes) --- */ }; /* size: 32, cachelines: 1 */ Or struct freebsd_sys_getdents_args in the OpenBSD kernel: /* /usr/home/leonardo/openbsd/src/sys/compat/freebsd/freebsd_syscallargs.h:231 */ struct freebsd_sys_getdents_args { union { register_t pad; /* 4 */ struct { int datum; /* 0 4 */ } le; /* 4 */ struct { int8_t pad[0]; /* 0 0 */ int datum; /* 0 4 */ } be; /* 4 */ } fd; /* 0 4 */ union { register_t pad; /* 4 */ struct { void * datum; /* 0 4 */ } le; /* 4 */ struct { int8_t pad[0]; /* 0 0 */ void * datum; /* 0 4 */ } be; /* 4 */ } dirent; /* 4 4 */ union { register_t pad; /* 4 */ struct { unsigned int datum; /* 0 4 */ } le; /* 4 */ struct { int8_t pad[0]; /* 0 0 */ unsigned int datum; /* 0 4 */ } be; /* 4 */ } count; /* 8 4 */ }; /* size: 12, cachelines: 1 */ /* last cacheline: 12 bytes */ /* definitions: 7 */ One more from the OpenBSD kernel: /* /usr/home/leonardo/openbsd/src/sys/nfs/nfs.h:344 */ struct nfssvc_sock { struct { struct nfssvc_sock * tqe_next; /* 0 4 */ struct nfssvc_sock * * tqe_prev; /* 4 4 */ } ns_chain; /* 0 8 */ struct { struct nfsuid * tqh_first; /* 0 4 */ struct nfsuid * * tqh_last; /* 4 4 */ } ns_uidlruhead; /* 8 8 */ struct file * ns_fp; /* 16 4 */ struct socket * ns_so; /* 20 4 */ struct mbuf * ns_nam; /* 24 4 */ struct mbuf * ns_raw; /* 28 4 */ /* --- cacheline 1 boundary (32 bytes) --- */ struct mbuf * ns_rawend; /* 32 4 */ struct mbuf * ns_rec; /* 36 4 */ struct mbuf * ns_recend; /* 40 4 */ struct mbuf * ns_frag; /* 44 4 */ int ns_flag; /* 48 4 */ int ns_solock; /* 52 4 */ int ns_cc; /* 56 4 */ int ns_reclen; /* 60 4 */ /* --- cacheline 2 boundary (64 bytes) --- */ int ns_numuids; /* 64 4 */ u_int32_t ns_sref; /* 68 4 */ struct { struct nfsrv_descript * lh_first; /* 0 4 */ } ns_tq; /* 72 4 */ struct ns_uidhashtbl[29]; /* 76 116 */ /* --- cacheline 6 boundary (192 bytes) --- */ struct nfsrvw_delayhash ns_wdelayhashtbl[16]; /* 192 64 */ /* --- cacheline 8 boundary (256 bytes) --- */ }; /* size: 256, cachelines: 8 */ /* definitions: 12 */ Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 22:46:47 +01:00
/* Look if is a type defined inline */
type__name(tag__type(type), cu) == NULL) {
if (!conf->suppress_offset_comment) {
/* Check if this is a anonymous union */
const int slen = self->name != NULL ? (int)strlen(self->name) : -1;
/*
* Add the comment with the union size after padding the
* '} member_name;' last line of the type printed in the
* above call to type__fprintf.
*/
printed += fprintf(fp, ";%*s/* %11zd */",
(conf->type_spacing +
conf->name_spacing - slen - 3), " ", size);
}
} else {
printed += fprintf(fp, ";");
if (!conf->suppress_offset_comment) {
const int spacing = conf->type_spacing + conf->name_spacing - printed;
printed += fprintf(fp, "%*s/* %11zd */",
spacing > 0 ? spacing : 0, " ", size);
}
[CLASSES]: Fully support nested classes Example: [acme@newtoy pahole]$ pahole net/ipv4/tcp.o flowi /* include/net/flow.h:13 */ struct flowi { int oif; /* 0 4 */ int iif; /* 4 4 */ __u32 mark; /* 8 4 */ union { struct { __be32 daddr; /* 0 4 */ __be32 saddr; /* 4 4 */ __u8 tos; /* 8 1 */ __u8 scope; /* 9 1 */ } ip4_u; /* 12 */ struct { struct in6_addr daddr; /* 0 16 */ struct in6_addr saddr; /* 16 16 */ /* --- cacheline 1 boundary (32 bytes) --- */ __be32 flowlabel; /* 32 4 */ } ip6_u; /* 36 */ struct { __le16 daddr; /* 0 2 */ __le16 saddr; /* 2 2 */ __u8 scope; /* 4 1 */ } dn_u; /* 6 */ } nl_u; /* 12 36 */ /* --- cacheline 1 boundary (32 bytes) was 16 bytes ago --- */ __u8 proto; /* 48 1 */ __u8 flags; /* 49 1 */ /* XXX 2 bytes hole, try to pack */ union { struct { __be16 sport; /* 0 2 */ __be16 dport; /* 2 2 */ } ports; /* 4 */ struct { __u8 type; /* 0 1 */ __u8 code; /* 1 1 */ } icmpt; /* 2 */ struct { __le16 sport; /* 0 2 */ __le16 dport; /* 2 2 */ } dnports; /* 4 */ __be32 spi; /* 4 */ } uli_u; /* 52 4 */ __u32 secid; /* 56 4 */ }; /* size: 60, cachelines: 2 */ /* sum members: 58, holes: 1, sum holes: 2 */ /* last cacheline: 28 bytes */ Supporting anonymous structs and unions just fine, even combinations of both, like in struct page, in the Linux kernel: [acme@newtoy pahole]$ pahole mm/mmap.o page /* include/linux/mmzone.h:391 */ struct page { long unsigned int flags; /* 0 4 */ atomic_t _count; /* 4 4 */ atomic_t _mapcount; /* 8 4 */ union { struct { long unsigned int private; /* 0 4 */ struct address_space * mapping; /* 4 4 */ }; /* 8 */ }; /* 12 8 */ long unsigned int index; /* 20 4 */ struct list_head lru; /* 24 8 */ /* --- cacheline 1 boundary (32 bytes) --- */ }; /* size: 32, cachelines: 1 */ Or struct freebsd_sys_getdents_args in the OpenBSD kernel: /* /usr/home/leonardo/openbsd/src/sys/compat/freebsd/freebsd_syscallargs.h:231 */ struct freebsd_sys_getdents_args { union { register_t pad; /* 4 */ struct { int datum; /* 0 4 */ } le; /* 4 */ struct { int8_t pad[0]; /* 0 0 */ int datum; /* 0 4 */ } be; /* 4 */ } fd; /* 0 4 */ union { register_t pad; /* 4 */ struct { void * datum; /* 0 4 */ } le; /* 4 */ struct { int8_t pad[0]; /* 0 0 */ void * datum; /* 0 4 */ } be; /* 4 */ } dirent; /* 4 4 */ union { register_t pad; /* 4 */ struct { unsigned int datum; /* 0 4 */ } le; /* 4 */ struct { int8_t pad[0]; /* 0 0 */ unsigned int datum; /* 0 4 */ } be; /* 4 */ } count; /* 8 4 */ }; /* size: 12, cachelines: 1 */ /* last cacheline: 12 bytes */ /* definitions: 7 */ One more from the OpenBSD kernel: /* /usr/home/leonardo/openbsd/src/sys/nfs/nfs.h:344 */ struct nfssvc_sock { struct { struct nfssvc_sock * tqe_next; /* 0 4 */ struct nfssvc_sock * * tqe_prev; /* 4 4 */ } ns_chain; /* 0 8 */ struct { struct nfsuid * tqh_first; /* 0 4 */ struct nfsuid * * tqh_last; /* 4 4 */ } ns_uidlruhead; /* 8 8 */ struct file * ns_fp; /* 16 4 */ struct socket * ns_so; /* 20 4 */ struct mbuf * ns_nam; /* 24 4 */ struct mbuf * ns_raw; /* 28 4 */ /* --- cacheline 1 boundary (32 bytes) --- */ struct mbuf * ns_rawend; /* 32 4 */ struct mbuf * ns_rec; /* 36 4 */ struct mbuf * ns_recend; /* 40 4 */ struct mbuf * ns_frag; /* 44 4 */ int ns_flag; /* 48 4 */ int ns_solock; /* 52 4 */ int ns_cc; /* 56 4 */ int ns_reclen; /* 60 4 */ /* --- cacheline 2 boundary (64 bytes) --- */ int ns_numuids; /* 64 4 */ u_int32_t ns_sref; /* 68 4 */ struct { struct nfsrv_descript * lh_first; /* 0 4 */ } ns_tq; /* 72 4 */ struct ns_uidhashtbl[29]; /* 76 116 */ /* --- cacheline 6 boundary (192 bytes) --- */ struct nfsrvw_delayhash ns_wdelayhashtbl[16]; /* 192 64 */ /* --- cacheline 8 boundary (256 bytes) --- */ }; /* size: 256, cachelines: 8 */ /* definitions: 12 */ Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 22:46:47 +01:00
}
return printed;
[CLASSES]: Ditch class_member__names Was a awful function, to replace it added some new __snprintf methods for more classes (array_type, class_member, etc), the end result is a much nicer rendering, for instance: @@ -6549,11 +6549,11 @@ /* XXX 2 bytes hole, try to pack */ union { - struct ff_constant_effect constant; /* 10 */ - struct ff_ramp_effect ramp; /* 12 */ - struct ff_periodic_effect periodic; /* 28 */ - struct ff_condition_effect condition[2]; /* 24 */ - struct ff_rumble_effect rumble; /* 4 */ + struct ff_constant_effect constant; /* 10 */ + struct ff_ramp_effect ramp; /* 12 */ + struct ff_periodic_effect periodic; /* 28 */ + struct ff_condition_effect condition[2]; /* 24 */ + struct ff_rumble_effect rumble; /* 4 */ } u; /* 16 28 */ /* --- cacheline 1 boundary (32 bytes) was 12 bytes ago --- */ }; /* size: 44, cachelines: 2 */ Previously when such big class members appeared the comments with the size and offset were unaligned, now its only in extreme cases, such as the array above that things get unaligned. End result is a smaller library: [acme@newtoy pahole]$ codiff -V build/libclasses.so.orig build/libclasses.so /home/acme/pahole/classes.c: struct array_type | -4 nr_members: -1 -const char *name /* 36 4 */ 1 struct changed enumeration__print | +10 # 175 -> 185 union__snprintf | +32 # 576 -> 608 union__print | +16 # 182 -> 198 class_member__names | -851 (removed) class_member__print | -721 # 1218 -> 497 class__print_struct | +54 # 1403 -> 1457 6 functions changed, 112 bytes added, 1572 bytes removed, diff: -1460 /home/acme/pahole/classes.c: array_type__snprintf | +249 (added) class_member__snprintf | +892 (added) 2 functions changed, 1141 bytes added build/libclasses.so: 8 functions changed, 1253 bytes added, 1572 bytes removed, diff: -319 Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 17:19:55 +01:00
}
static size_t union__fprintf(struct type *self, const struct cu *cu,
const struct conf_fprintf *conf, FILE *fp)
[CLASSES]: Ditch class_member__names Was a awful function, to replace it added some new __snprintf methods for more classes (array_type, class_member, etc), the end result is a much nicer rendering, for instance: @@ -6549,11 +6549,11 @@ /* XXX 2 bytes hole, try to pack */ union { - struct ff_constant_effect constant; /* 10 */ - struct ff_ramp_effect ramp; /* 12 */ - struct ff_periodic_effect periodic; /* 28 */ - struct ff_condition_effect condition[2]; /* 24 */ - struct ff_rumble_effect rumble; /* 4 */ + struct ff_constant_effect constant; /* 10 */ + struct ff_ramp_effect ramp; /* 12 */ + struct ff_periodic_effect periodic; /* 28 */ + struct ff_condition_effect condition[2]; /* 24 */ + struct ff_rumble_effect rumble; /* 4 */ } u; /* 16 28 */ /* --- cacheline 1 boundary (32 bytes) was 12 bytes ago --- */ }; /* size: 44, cachelines: 2 */ Previously when such big class members appeared the comments with the size and offset were unaligned, now its only in extreme cases, such as the array above that things get unaligned. End result is a smaller library: [acme@newtoy pahole]$ codiff -V build/libclasses.so.orig build/libclasses.so /home/acme/pahole/classes.c: struct array_type | -4 nr_members: -1 -const char *name /* 36 4 */ 1 struct changed enumeration__print | +10 # 175 -> 185 union__snprintf | +32 # 576 -> 608 union__print | +16 # 182 -> 198 class_member__names | -851 (removed) class_member__print | -721 # 1218 -> 497 class__print_struct | +54 # 1403 -> 1457 6 functions changed, 112 bytes added, 1572 bytes removed, diff: -1460 /home/acme/pahole/classes.c: array_type__snprintf | +249 (added) class_member__snprintf | +892 (added) 2 functions changed, 1141 bytes added build/libclasses.so: 8 functions changed, 1253 bytes added, 1572 bytes removed, diff: -319 Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 17:19:55 +01:00
{
struct class_member *pos;
size_t printed = 0;
int indent = conf->indent;
struct conf_fprintf uconf;
[CLASSES]: Ditch class_member__names Was a awful function, to replace it added some new __snprintf methods for more classes (array_type, class_member, etc), the end result is a much nicer rendering, for instance: @@ -6549,11 +6549,11 @@ /* XXX 2 bytes hole, try to pack */ union { - struct ff_constant_effect constant; /* 10 */ - struct ff_ramp_effect ramp; /* 12 */ - struct ff_periodic_effect periodic; /* 28 */ - struct ff_condition_effect condition[2]; /* 24 */ - struct ff_rumble_effect rumble; /* 4 */ + struct ff_constant_effect constant; /* 10 */ + struct ff_ramp_effect ramp; /* 12 */ + struct ff_periodic_effect periodic; /* 28 */ + struct ff_condition_effect condition[2]; /* 24 */ + struct ff_rumble_effect rumble; /* 4 */ } u; /* 16 28 */ /* --- cacheline 1 boundary (32 bytes) was 12 bytes ago --- */ }; /* size: 44, cachelines: 2 */ Previously when such big class members appeared the comments with the size and offset were unaligned, now its only in extreme cases, such as the array above that things get unaligned. End result is a smaller library: [acme@newtoy pahole]$ codiff -V build/libclasses.so.orig build/libclasses.so /home/acme/pahole/classes.c: struct array_type | -4 nr_members: -1 -const char *name /* 36 4 */ 1 struct changed enumeration__print | +10 # 175 -> 185 union__snprintf | +32 # 576 -> 608 union__print | +16 # 182 -> 198 class_member__names | -851 (removed) class_member__print | -721 # 1218 -> 497 class__print_struct | +54 # 1403 -> 1457 6 functions changed, 112 bytes added, 1572 bytes removed, diff: -1460 /home/acme/pahole/classes.c: array_type__snprintf | +249 (added) class_member__snprintf | +892 (added) 2 functions changed, 1141 bytes added build/libclasses.so: 8 functions changed, 1253 bytes added, 1572 bytes removed, diff: -319 Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 17:19:55 +01:00
if (indent >= (int)sizeof(tabs))
indent = sizeof(tabs) - 1;
[CLASSES]: Ditch class_member__names Was a awful function, to replace it added some new __snprintf methods for more classes (array_type, class_member, etc), the end result is a much nicer rendering, for instance: @@ -6549,11 +6549,11 @@ /* XXX 2 bytes hole, try to pack */ union { - struct ff_constant_effect constant; /* 10 */ - struct ff_ramp_effect ramp; /* 12 */ - struct ff_periodic_effect periodic; /* 28 */ - struct ff_condition_effect condition[2]; /* 24 */ - struct ff_rumble_effect rumble; /* 4 */ + struct ff_constant_effect constant; /* 10 */ + struct ff_ramp_effect ramp; /* 12 */ + struct ff_periodic_effect periodic; /* 28 */ + struct ff_condition_effect condition[2]; /* 24 */ + struct ff_rumble_effect rumble; /* 4 */ } u; /* 16 28 */ /* --- cacheline 1 boundary (32 bytes) was 12 bytes ago --- */ }; /* size: 44, cachelines: 2 */ Previously when such big class members appeared the comments with the size and offset were unaligned, now its only in extreme cases, such as the array above that things get unaligned. End result is a smaller library: [acme@newtoy pahole]$ codiff -V build/libclasses.so.orig build/libclasses.so /home/acme/pahole/classes.c: struct array_type | -4 nr_members: -1 -const char *name /* 36 4 */ 1 struct changed enumeration__print | +10 # 175 -> 185 union__snprintf | +32 # 576 -> 608 union__print | +16 # 182 -> 198 class_member__names | -851 (removed) class_member__print | -721 # 1218 -> 497 class__print_struct | +54 # 1403 -> 1457 6 functions changed, 112 bytes added, 1572 bytes removed, diff: -1460 /home/acme/pahole/classes.c: array_type__snprintf | +249 (added) class_member__snprintf | +892 (added) 2 functions changed, 1141 bytes added build/libclasses.so: 8 functions changed, 1253 bytes added, 1572 bytes removed, diff: -319 Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 17:19:55 +01:00
if (conf->prefix != NULL)
printed += fprintf(fp, "%s ", conf->prefix);
printed += fprintf(fp, "union%s%s {\n", type__name(self, cu) ? " " : "",
type__name(self, cu) ?: "");
uconf = *conf;
uconf.indent = indent + 1;
type__for_each_member(self, pos) {
[CLASSES]: Ditch class_member__names Was a awful function, to replace it added some new __snprintf methods for more classes (array_type, class_member, etc), the end result is a much nicer rendering, for instance: @@ -6549,11 +6549,11 @@ /* XXX 2 bytes hole, try to pack */ union { - struct ff_constant_effect constant; /* 10 */ - struct ff_ramp_effect ramp; /* 12 */ - struct ff_periodic_effect periodic; /* 28 */ - struct ff_condition_effect condition[2]; /* 24 */ - struct ff_rumble_effect rumble; /* 4 */ + struct ff_constant_effect constant; /* 10 */ + struct ff_ramp_effect ramp; /* 12 */ + struct ff_periodic_effect periodic; /* 28 */ + struct ff_condition_effect condition[2]; /* 24 */ + struct ff_rumble_effect rumble; /* 4 */ } u; /* 16 28 */ /* --- cacheline 1 boundary (32 bytes) was 12 bytes ago --- */ }; /* size: 44, cachelines: 2 */ Previously when such big class members appeared the comments with the size and offset were unaligned, now its only in extreme cases, such as the array above that things get unaligned. End result is a smaller library: [acme@newtoy pahole]$ codiff -V build/libclasses.so.orig build/libclasses.so /home/acme/pahole/classes.c: struct array_type | -4 nr_members: -1 -const char *name /* 36 4 */ 1 struct changed enumeration__print | +10 # 175 -> 185 union__snprintf | +32 # 576 -> 608 union__print | +16 # 182 -> 198 class_member__names | -851 (removed) class_member__print | -721 # 1218 -> 497 class__print_struct | +54 # 1403 -> 1457 6 functions changed, 112 bytes added, 1572 bytes removed, diff: -1460 /home/acme/pahole/classes.c: array_type__snprintf | +249 (added) class_member__snprintf | +892 (added) 2 functions changed, 1141 bytes added build/libclasses.so: 8 functions changed, 1253 bytes added, 1572 bytes removed, diff: -319 Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 17:19:55 +01:00
struct tag *type = cu__find_tag_by_id(cu, pos->tag.type);
if (type == NULL) {
tag__type_not_found(&pos->tag);
printed += fprintf(fp, "%.*s>>>ERROR: type(%#llx) for %s not "
"found!\n", uconf.indent, tabs,
(unsigned long long)pos->tag.type,
pos->name);
continue;
}
printed += fprintf(fp, "%.*s", uconf.indent, tabs);
printed += union_member__fprintf(pos, type, cu, &uconf, fp);
fputc('\n', fp);
++printed;
[CLASSES]: Ditch class_member__names Was a awful function, to replace it added some new __snprintf methods for more classes (array_type, class_member, etc), the end result is a much nicer rendering, for instance: @@ -6549,11 +6549,11 @@ /* XXX 2 bytes hole, try to pack */ union { - struct ff_constant_effect constant; /* 10 */ - struct ff_ramp_effect ramp; /* 12 */ - struct ff_periodic_effect periodic; /* 28 */ - struct ff_condition_effect condition[2]; /* 24 */ - struct ff_rumble_effect rumble; /* 4 */ + struct ff_constant_effect constant; /* 10 */ + struct ff_ramp_effect ramp; /* 12 */ + struct ff_periodic_effect periodic; /* 28 */ + struct ff_condition_effect condition[2]; /* 24 */ + struct ff_rumble_effect rumble; /* 4 */ } u; /* 16 28 */ /* --- cacheline 1 boundary (32 bytes) was 12 bytes ago --- */ }; /* size: 44, cachelines: 2 */ Previously when such big class members appeared the comments with the size and offset were unaligned, now its only in extreme cases, such as the array above that things get unaligned. End result is a smaller library: [acme@newtoy pahole]$ codiff -V build/libclasses.so.orig build/libclasses.so /home/acme/pahole/classes.c: struct array_type | -4 nr_members: -1 -const char *name /* 36 4 */ 1 struct changed enumeration__print | +10 # 175 -> 185 union__snprintf | +32 # 576 -> 608 union__print | +16 # 182 -> 198 class_member__names | -851 (removed) class_member__print | -721 # 1218 -> 497 class__print_struct | +54 # 1403 -> 1457 6 functions changed, 112 bytes added, 1572 bytes removed, diff: -1460 /home/acme/pahole/classes.c: array_type__snprintf | +249 (added) class_member__snprintf | +892 (added) 2 functions changed, 1141 bytes added build/libclasses.so: 8 functions changed, 1253 bytes added, 1572 bytes removed, diff: -319 Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 17:19:55 +01:00
}
return printed + fprintf(fp, "%.*s}%s%s", indent, tabs,
conf->suffix ? " " : "", conf->suffix ?: "");
}
void class__delete(struct class *self)
{
struct class_member *pos, *next;
type__for_each_member_safe(&self->type, pos, next)
class_member__delete(pos);
free(self);
}
void class__add_vtable_entry(struct class *self, struct function *vtable_entry)
{
++self->nr_vtable_entries;
list_add_tail(&vtable_entry->vtable_node, &self->vtable);
}
void namespace__add_tag(struct namespace *self, struct tag *tag)
{
++self->nr_tags;
list_add_tail(&tag->node, &self->tags);
}
void type__add_member(struct type *self, struct class_member *member)
{
++self->nr_members;
namespace__add_tag(&self->namespace, &member->tag);
}
struct class_member *type__last_member(struct type *self)
{
struct class_member *pos;
list_for_each_entry_reverse(pos, &self->namespace.tags, tag.node)
if (pos->tag.tag == DW_TAG_member)
return pos;
return NULL;
}
static int type__clone_members(struct type *self, const struct type *from)
{
struct class_member *pos;
self->nr_members = 0;
INIT_LIST_HEAD(&self->namespace.tags);
type__for_each_member(from, pos) {
struct class_member *member_clone = class_member__clone(pos);
if (member_clone == NULL)
return -1;
type__add_member(self, member_clone);
}
return 0;
}
struct class *class__clone(const struct class *from,
const char *new_class_name)
{
struct class *self = malloc(sizeof(*self));
if (self != NULL) {
memcpy(self, from, sizeof(*self));
if (type__clone_members(&self->type, &from->type) != 0) {
class__delete(self);
self = NULL;
}
if (new_class_name != NULL)
self->type.namespace.name = strings__add(new_class_name);
}
return self;
}
void enumeration__add(struct type *self, struct enumerator *enumerator)
{
++self->nr_members;
namespace__add_tag(&self->namespace, &enumerator->tag);
}
void lexblock__add_lexblock(struct lexblock *self, struct lexblock *child)
{
++self->nr_lexblocks;
list_add_tail(&child->tag.node, &self->tags);
}
const char *function__name(struct function *self, const struct cu *cu)
{
/* Check if the tag doesn't comes with a DW_AT_name attribute... */
if (self->name == NULL) {
/* No? So it must have a DW_AT_abstract_origin... */
struct tag *tag = cu__find_tag_by_id(cu,
self->abstract_origin);
if (tag == NULL) {
/* ... or a DW_TAG_specification... */
tag = cu__find_tag_by_id(cu, self->specification);
if (tag == NULL) {
tag__id_not_found(&self->proto.tag,
self->specification);
return NULL;
}
}
/* ... and now we cache the result in this tag ->name field */
self->name = tag__function(tag)->name;
}
return self->name;
}
int ftype__has_parm_of_type(const struct ftype *self, const struct tag *target,
const struct cu *cu)
{
struct parameter *pos;
ftype__for_each_parameter(self, pos) {
struct tag *type =
cu__find_tag_by_id(cu, parameter__type(pos, cu));
if (type != NULL && type->tag == DW_TAG_pointer_type) {
type = cu__find_tag_by_id(cu, type->type);
if (type != NULL && type->id == target->id)
return 1;
}
}
return 0;
}
void ftype__add_parameter(struct ftype *self, struct parameter *parm)
{
++self->nr_parms;
list_add_tail(&parm->tag.node, &self->parms);
}
void lexblock__add_tag(struct lexblock *self, struct tag *tag)
{
list_add_tail(&tag->node, &self->tags);
}
void lexblock__add_inline_expansion(struct lexblock *self,
struct inline_expansion *exp)
[CLASSES]: Add support for DW_TAG_inlined_subroutine Output of pfunct using this information (all for a make allyesconfig build): Top 5 functions by size of inlined functions in net/ipv4: [acme@newtoy guinea_pig-2.6]$ pfunct -I net/ipv4/built-in.o | sort -k3 -nr | head -5 ip_route_input: 19 7086 tcp_ack: 33 6415 do_ip_vs_set_ctl: 23 4193 q931_help: 8 3822 ip_defrag: 19 3318 [acme@newtoy guinea_pig-2.6]$ And by number of inline expansions: [acme@newtoy guinea_pig-2.6]$ pfunct -I net/ipv4/built-in.o | sort -k2 -nr | head -5 dump_packet: 35 905 tcp_v4_rcv: 34 1773 tcp_recvmsg: 34 928 tcp_ack: 33 6415 tcp_rcv_established: 31 1195 [acme@newtoy guinea_pig-2.6]$ And the list of expansions on a specific function: [acme@newtoy guinea_pig-2.6]$ pfunct -i net/ipv4/built-in.o tcp_v4_rcv /* net/ipv4/tcp_ipv4.c:1054 */ int tcp_v4_rcv(struct sk_buff * skb); /* size: 2189, variables: 8, goto labels: 6, inline expansions: 34 (1773 bytes) */ /* inline expansions in tcp_v4_rcv: current_thread_info: 8 pskb_may_pull: 36 pskb_may_pull: 29 tcp_v4_checksum_init: 139 __fswab32: 2 __fswab32: 2 inet_iif: 12 __inet_lookup: 292 __fswab16: 20 inet_ehashfn: 25 inet_ehash_bucket: 18 prefetch: 4 prefetch: 4 prefetch: 4 sock_hold: 4 xfrm4_policy_check: 59 nf_reset: 66 sk_filter: 135 __skb_trim: 20 get_softnet_dma: 68 tcp_prequeue: 257 sk_add_backlog: 40 sock_put: 27 xfrm4_policy_check: 46 tcp_checksum_complete: 29 current_thread_info: 8 sock_put: 20 xfrm4_policy_check: 50 tcp_checksum_complete: 29 current_thread_info: 8 inet_iif: 9 inet_lookup_listener: 36 inet_twsk_put: 114 tcp_v4_timewait_ack: 153 */ [acme@newtoy guinea_pig-2.6]$ Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-03 16:41:19 +01:00
{
++self->nr_inline_expansions;
[CLASSES]: Add support for DW_TAG_inlined_subroutine Output of pfunct using this information (all for a make allyesconfig build): Top 5 functions by size of inlined functions in net/ipv4: [acme@newtoy guinea_pig-2.6]$ pfunct -I net/ipv4/built-in.o | sort -k3 -nr | head -5 ip_route_input: 19 7086 tcp_ack: 33 6415 do_ip_vs_set_ctl: 23 4193 q931_help: 8 3822 ip_defrag: 19 3318 [acme@newtoy guinea_pig-2.6]$ And by number of inline expansions: [acme@newtoy guinea_pig-2.6]$ pfunct -I net/ipv4/built-in.o | sort -k2 -nr | head -5 dump_packet: 35 905 tcp_v4_rcv: 34 1773 tcp_recvmsg: 34 928 tcp_ack: 33 6415 tcp_rcv_established: 31 1195 [acme@newtoy guinea_pig-2.6]$ And the list of expansions on a specific function: [acme@newtoy guinea_pig-2.6]$ pfunct -i net/ipv4/built-in.o tcp_v4_rcv /* net/ipv4/tcp_ipv4.c:1054 */ int tcp_v4_rcv(struct sk_buff * skb); /* size: 2189, variables: 8, goto labels: 6, inline expansions: 34 (1773 bytes) */ /* inline expansions in tcp_v4_rcv: current_thread_info: 8 pskb_may_pull: 36 pskb_may_pull: 29 tcp_v4_checksum_init: 139 __fswab32: 2 __fswab32: 2 inet_iif: 12 __inet_lookup: 292 __fswab16: 20 inet_ehashfn: 25 inet_ehash_bucket: 18 prefetch: 4 prefetch: 4 prefetch: 4 sock_hold: 4 xfrm4_policy_check: 59 nf_reset: 66 sk_filter: 135 __skb_trim: 20 get_softnet_dma: 68 tcp_prequeue: 257 sk_add_backlog: 40 sock_put: 27 xfrm4_policy_check: 46 tcp_checksum_complete: 29 current_thread_info: 8 sock_put: 20 xfrm4_policy_check: 50 tcp_checksum_complete: 29 current_thread_info: 8 inet_iif: 9 inet_lookup_listener: 36 inet_twsk_put: 114 tcp_v4_timewait_ack: 153 */ [acme@newtoy guinea_pig-2.6]$ Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-03 16:41:19 +01:00
self->size_inline_expansions += exp->size;
lexblock__add_tag(self, &exp->tag);
[CLASSES]: Add support for DW_TAG_inlined_subroutine Output of pfunct using this information (all for a make allyesconfig build): Top 5 functions by size of inlined functions in net/ipv4: [acme@newtoy guinea_pig-2.6]$ pfunct -I net/ipv4/built-in.o | sort -k3 -nr | head -5 ip_route_input: 19 7086 tcp_ack: 33 6415 do_ip_vs_set_ctl: 23 4193 q931_help: 8 3822 ip_defrag: 19 3318 [acme@newtoy guinea_pig-2.6]$ And by number of inline expansions: [acme@newtoy guinea_pig-2.6]$ pfunct -I net/ipv4/built-in.o | sort -k2 -nr | head -5 dump_packet: 35 905 tcp_v4_rcv: 34 1773 tcp_recvmsg: 34 928 tcp_ack: 33 6415 tcp_rcv_established: 31 1195 [acme@newtoy guinea_pig-2.6]$ And the list of expansions on a specific function: [acme@newtoy guinea_pig-2.6]$ pfunct -i net/ipv4/built-in.o tcp_v4_rcv /* net/ipv4/tcp_ipv4.c:1054 */ int tcp_v4_rcv(struct sk_buff * skb); /* size: 2189, variables: 8, goto labels: 6, inline expansions: 34 (1773 bytes) */ /* inline expansions in tcp_v4_rcv: current_thread_info: 8 pskb_may_pull: 36 pskb_may_pull: 29 tcp_v4_checksum_init: 139 __fswab32: 2 __fswab32: 2 inet_iif: 12 __inet_lookup: 292 __fswab16: 20 inet_ehashfn: 25 inet_ehash_bucket: 18 prefetch: 4 prefetch: 4 prefetch: 4 sock_hold: 4 xfrm4_policy_check: 59 nf_reset: 66 sk_filter: 135 __skb_trim: 20 get_softnet_dma: 68 tcp_prequeue: 257 sk_add_backlog: 40 sock_put: 27 xfrm4_policy_check: 46 tcp_checksum_complete: 29 current_thread_info: 8 sock_put: 20 xfrm4_policy_check: 50 tcp_checksum_complete: 29 current_thread_info: 8 inet_iif: 9 inet_lookup_listener: 36 inet_twsk_put: 114 tcp_v4_timewait_ack: 153 */ [acme@newtoy guinea_pig-2.6]$ Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-03 16:41:19 +01:00
}
void lexblock__add_variable(struct lexblock *self, struct variable *var)
{
++self->nr_variables;
lexblock__add_tag(self, &var->tag);
}
void lexblock__add_label(struct lexblock *self, struct label *label)
{
++self->nr_labels;
lexblock__add_tag(self, &label->tag);
}
const struct class_member *class__find_bit_hole(const struct class *self,
const struct class_member *trailer,
const size_t bit_hole_size)
{
struct class_member *pos;
const size_t byte_hole_size = bit_hole_size / 8;
type__for_each_data_member(&self->type, pos)
if (pos == trailer)
break;
else if (pos->hole >= byte_hole_size ||
pos->bit_hole >= bit_hole_size)
return pos;
return NULL;
}
void class__find_holes(struct class *self, const struct cu *cu)
{
const struct type *ctype = &self->type;
struct class_member *pos, *last = NULL;
size_t last_size = 0, size;
uint32_t bit_sum = 0;
[DWARVES]: Properly find holes in bitfields Make class__find_holes understand that when a byte offset goes backward it is because the compiler is "combining" small bitfields with previous fields, and using from the end of the combined bitfield + small fields. This made your head hurt, huh? One example: struct usb_bus { struct device * controller; /* 0 8 */ int busnum; /* 8 4 */ /* XXX 4 bytes hole, try to pack */ char * bus_name; /* 16 8 */ u8 uses_dma; /* 24 1 */ u8 otg_port; /* 25 1 */ /* Bitfield combined with previous fields */ unsigned int is_b_host:1; /* 24:15 4 */ unsigned int b_hnp_enable:1; /* 24:14 4 */ /* XXX 14 bits hole, try to pack */ int devnum_next; /* 28 4 */ struct usb_devmap devmap; /* 32 16 */ <SNIP> }; See? is_b_host:1 .. b_hnp_enable:1 makes a bitfield of just two bits. The programmer decided to make this a 'unsigned int' bitfield, so taking 4 bytes. And placed this "4" bytes bitfield just after two fields of one byte. The compiler put the "4" bytes bitfield "in the same place" as the "uses_dma" field, but its really not clobbering it neither "otg_port", as it allocates it from (offset 24 + sizeof(unsigned int) - 1), backwards. So at the end there is a, now correctly calculated, 14 bits hole, and that matches the bit offset used for the last field, that is "14", as offsets for bits and bytes starts at zero, all is explained now. One last thing is that since we actually have 14 bits we in fact have a one byte hole + a 6 bits hole, but that should be clear (haha) for those looking for holes :-) Nah, just run pahole reorganize on this beast and you'll have (for the complete structure, with the <SNIP> part back in: struct usb_bus { struct device * controller; /* 0 8 */ int busnum; /* 8 4 */ unsigned char is_b_host:1; /* 12:247 1 */ unsigned char b_hnp_enable:1; /* 12:246 1 */ /* XXX 6 bits hole, try to pack */ u8 otg_port; /* 13 1 */ u8 uses_dma; /* 14 1 */ /* XXX 1 byte hole, try to pack */ char * bus_name; /* 16 8 */ int bandwidth_isoc_reqs; /* 24 4 */ int devnum_next; /* 28 4 */ struct usb_devmap devmap; /* 32 16 */ struct usb_device * root_hub; /* 48 8 */ struct list_head bus_list; /* 56 16 */ /* --- cacheline 1 boundary (64 bytes) was 8 bytes ago --- */ int bandwidth_allocated; /* 72 4 */ int bandwidth_int_reqs; /* 76 4 */ struct dentry * usbfs_dentry; /* 80 8 */ struct class_device * class_dev; /* 88 8 */ struct mon_bus * mon_bus; /* 96 8 */ int monitored; /* 104 4 */ /* size: 112, cachelines: 2 */ /* sum members: 107, holes: 1, sum holes: 1 */ /* bit holes: 1, sum bit holes: 6 bits */ /* padding: 4 */ /* last cacheline: 48 bytes */ }; /* saved 8 bytes! */ And we save 8 bytes and reduce the previous complexity. Hey, but look at those bit offsets at is_b_host and b_hnp_enable... damn, exposing the bit offsets I just exposed another bug, that is: the reorganization code is not fixing up the bit offsets, one more for the TODO list, nah, just compile it and pass the results back to the dwarves and we get: struct usb_bus { struct device * controller; /* 0 8 */ int busnum; /* 8 4 */ unsigned char is_b_host:1; /* 12: 7 1 */ unsigned char b_hnp_enable:1; /* 12: 6 1 */ /* XXX 6 bits hole, try to pack */ u8 otg_port; /* 13 1 */ u8 uses_dma; /* 14 1 */ /* XXX 1 byte hole, try to pack */ char * bus_name; /* 16 8 */ int bandwidth_isoc_reqs; /* 24 4 */ int devnum_next; /* 28 4 */ struct usb_devmap devmap; /* 32 16 */ struct usb_device * root_hub; /* 48 8 */ struct list_head bus_list; /* 56 16 */ /* --- cacheline 1 boundary (64 bytes) was 8 bytes ago --- */ int bandwidth_allocated; /* 72 4 */ int bandwidth_int_reqs; /* 76 4 */ struct dentry * usbfs_dentry; /* 80 8 */ struct class_device * class_dev; /* 88 8 */ struct mon_bus * mon_bus; /* 96 8 */ int monitored; /* 104 4 */ /* size: 112, cachelines: 2 */ /* sum members: 107, holes: 1, sum holes: 1 */ /* bit holes: 1, sum bit holes: 6 bits */ /* padding: 4 */ /* last cacheline: 48 bytes */ }; See? this time gcc fixed up things for us and even agreed on the reorganization the dwarves did! 8-) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2007-12-07 18:03:27 +01:00
uint32_t bitfield_real_offset = 0;
self->nr_holes = 0;
self->nr_bit_holes = 0;
type__for_each_member(ctype, pos) {
/* XXX for now just skip these */
if (pos->tag.tag == DW_TAG_inheritance &&
pos->virtuality == DW_VIRTUALITY_virtual)
continue;
if (last != NULL) {
[DWARVES]: Add sanity check when calculating size from DWARF offsets This struct, from the linux kernel: struct usb_bus { struct device * controller; /* 0 8 */ int busnum; /* 8 4 */ char * bus_name; /* 16 8 */ u8 uses_dma; /* 24 1 */ u8 otg_port; /* 25 1 */ unsigned int is_b_host:1; /* 24 4 */ unsigned int b_hnp_enable:1; /* 24 4 */ int devnum_next; /* 28 4 */ struct usb_devmap devmap; /* 32 16 */ struct usb_device * root_hub; /* 48 8 */ struct list_head bus_list; /* 56 16 */ int bandwidth_allocated; /* 72 4 */ int bandwidth_int_reqs; /* 76 4 */ int bandwidth_isoc_reqs; /* 80 4 */ struct dentry * usbfs_dentry; /* 88 8 */ struct class_device * class_dev; /* 96 8 */ struct mon_bus * mon_bus; /* 104 8 */ int monitored; /* 112 4 */ }; Generates seemingly wrong DWARF when compiled with GCC: struct usb_bus { struct device * controller; /* 0 8 */ int busnum; /* 8 4 */ /* XXX 4 bytes hole, try to pack */ char * bus_name; /* 16 8 */ u8 uses_dma; /* 24 1 */ u8 otg_port; /* 25 1 */ /* WARNING: DWARF offset=24, real offset=26 */ unsigned int is_b_host:1; /* 24 4 */ unsigned int b_hnp_enable:1; /* 24 4 */ /* XXX 30 bits hole, try to pack */ int devnum_next; /* 28 4 */ struct usb_devmap devmap; /* 32 16 */ struct usb_device * root_hub; /* 48 8 */ struct list_head bus_list; /* 56 16 */ /* --- cacheline 1 boundary (64 bytes) was 10 bytes ago --- */ int bandwidth_allocated; /* 72 4 */ int bandwidth_int_reqs; /* 76 4 */ int bandwidth_isoc_reqs; /* 80 4 */ /* XXX 4 bytes hole, try to pack */ struct dentry * usbfs_dentry; /* 88 8 */ struct class_device * class_dev; /* 96 8 */ struct mon_bus * mon_bus; /* 104 8 */ int monitored; /* 112 4 */ /* size: 120, cachelines: 2 */ /* sum members: 110, holes: 2, sum holes: 8 */ /* bit holes: 1, sum bit holes: 30 bits */ /* padding: 4 */ /* last cacheline: 56 bytes */ /* BRAIN FART ALERT! 120 != 110 + 8(holes), diff = 2 */ }; Look at the offset for the first entry in the bitfield (is_b_host), the compiler said in the DWARF info that it was at offset 25, when in fact it is at offset 26 as can be seen when looking at the generated assembly code. This previously was confusing libdwarves, as it uses subtracts the last offset from the current offset to see what was the size the compiler really allocated to then check if it is equal to the size of the previous entry, so as to detect alignment holes. The offsets are uint32_t, so cast both to int64_t when doing the calculation, the existing code already deals with negative numbers that result in this patologic case. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2007-12-07 00:59:42 +01:00
/*
* We have to cast both offsets to int64_t because
* the current offset can be before the last offset
[DWARVES]: Properly find holes in bitfields Make class__find_holes understand that when a byte offset goes backward it is because the compiler is "combining" small bitfields with previous fields, and using from the end of the combined bitfield + small fields. This made your head hurt, huh? One example: struct usb_bus { struct device * controller; /* 0 8 */ int busnum; /* 8 4 */ /* XXX 4 bytes hole, try to pack */ char * bus_name; /* 16 8 */ u8 uses_dma; /* 24 1 */ u8 otg_port; /* 25 1 */ /* Bitfield combined with previous fields */ unsigned int is_b_host:1; /* 24:15 4 */ unsigned int b_hnp_enable:1; /* 24:14 4 */ /* XXX 14 bits hole, try to pack */ int devnum_next; /* 28 4 */ struct usb_devmap devmap; /* 32 16 */ <SNIP> }; See? is_b_host:1 .. b_hnp_enable:1 makes a bitfield of just two bits. The programmer decided to make this a 'unsigned int' bitfield, so taking 4 bytes. And placed this "4" bytes bitfield just after two fields of one byte. The compiler put the "4" bytes bitfield "in the same place" as the "uses_dma" field, but its really not clobbering it neither "otg_port", as it allocates it from (offset 24 + sizeof(unsigned int) - 1), backwards. So at the end there is a, now correctly calculated, 14 bits hole, and that matches the bit offset used for the last field, that is "14", as offsets for bits and bytes starts at zero, all is explained now. One last thing is that since we actually have 14 bits we in fact have a one byte hole + a 6 bits hole, but that should be clear (haha) for those looking for holes :-) Nah, just run pahole reorganize on this beast and you'll have (for the complete structure, with the <SNIP> part back in: struct usb_bus { struct device * controller; /* 0 8 */ int busnum; /* 8 4 */ unsigned char is_b_host:1; /* 12:247 1 */ unsigned char b_hnp_enable:1; /* 12:246 1 */ /* XXX 6 bits hole, try to pack */ u8 otg_port; /* 13 1 */ u8 uses_dma; /* 14 1 */ /* XXX 1 byte hole, try to pack */ char * bus_name; /* 16 8 */ int bandwidth_isoc_reqs; /* 24 4 */ int devnum_next; /* 28 4 */ struct usb_devmap devmap; /* 32 16 */ struct usb_device * root_hub; /* 48 8 */ struct list_head bus_list; /* 56 16 */ /* --- cacheline 1 boundary (64 bytes) was 8 bytes ago --- */ int bandwidth_allocated; /* 72 4 */ int bandwidth_int_reqs; /* 76 4 */ struct dentry * usbfs_dentry; /* 80 8 */ struct class_device * class_dev; /* 88 8 */ struct mon_bus * mon_bus; /* 96 8 */ int monitored; /* 104 4 */ /* size: 112, cachelines: 2 */ /* sum members: 107, holes: 1, sum holes: 1 */ /* bit holes: 1, sum bit holes: 6 bits */ /* padding: 4 */ /* last cacheline: 48 bytes */ }; /* saved 8 bytes! */ And we save 8 bytes and reduce the previous complexity. Hey, but look at those bit offsets at is_b_host and b_hnp_enable... damn, exposing the bit offsets I just exposed another bug, that is: the reorganization code is not fixing up the bit offsets, one more for the TODO list, nah, just compile it and pass the results back to the dwarves and we get: struct usb_bus { struct device * controller; /* 0 8 */ int busnum; /* 8 4 */ unsigned char is_b_host:1; /* 12: 7 1 */ unsigned char b_hnp_enable:1; /* 12: 6 1 */ /* XXX 6 bits hole, try to pack */ u8 otg_port; /* 13 1 */ u8 uses_dma; /* 14 1 */ /* XXX 1 byte hole, try to pack */ char * bus_name; /* 16 8 */ int bandwidth_isoc_reqs; /* 24 4 */ int devnum_next; /* 28 4 */ struct usb_devmap devmap; /* 32 16 */ struct usb_device * root_hub; /* 48 8 */ struct list_head bus_list; /* 56 16 */ /* --- cacheline 1 boundary (64 bytes) was 8 bytes ago --- */ int bandwidth_allocated; /* 72 4 */ int bandwidth_int_reqs; /* 76 4 */ struct dentry * usbfs_dentry; /* 80 8 */ struct class_device * class_dev; /* 88 8 */ struct mon_bus * mon_bus; /* 96 8 */ int monitored; /* 104 4 */ /* size: 112, cachelines: 2 */ /* sum members: 107, holes: 1, sum holes: 1 */ /* bit holes: 1, sum bit holes: 6 bits */ /* padding: 4 */ /* last cacheline: 48 bytes */ }; See? this time gcc fixed up things for us and even agreed on the reorganization the dwarves did! 8-) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2007-12-07 18:03:27 +01:00
* when we are starting a bitfield that combines with
* the previous, small size fields.
[DWARVES]: Add sanity check when calculating size from DWARF offsets This struct, from the linux kernel: struct usb_bus { struct device * controller; /* 0 8 */ int busnum; /* 8 4 */ char * bus_name; /* 16 8 */ u8 uses_dma; /* 24 1 */ u8 otg_port; /* 25 1 */ unsigned int is_b_host:1; /* 24 4 */ unsigned int b_hnp_enable:1; /* 24 4 */ int devnum_next; /* 28 4 */ struct usb_devmap devmap; /* 32 16 */ struct usb_device * root_hub; /* 48 8 */ struct list_head bus_list; /* 56 16 */ int bandwidth_allocated; /* 72 4 */ int bandwidth_int_reqs; /* 76 4 */ int bandwidth_isoc_reqs; /* 80 4 */ struct dentry * usbfs_dentry; /* 88 8 */ struct class_device * class_dev; /* 96 8 */ struct mon_bus * mon_bus; /* 104 8 */ int monitored; /* 112 4 */ }; Generates seemingly wrong DWARF when compiled with GCC: struct usb_bus { struct device * controller; /* 0 8 */ int busnum; /* 8 4 */ /* XXX 4 bytes hole, try to pack */ char * bus_name; /* 16 8 */ u8 uses_dma; /* 24 1 */ u8 otg_port; /* 25 1 */ /* WARNING: DWARF offset=24, real offset=26 */ unsigned int is_b_host:1; /* 24 4 */ unsigned int b_hnp_enable:1; /* 24 4 */ /* XXX 30 bits hole, try to pack */ int devnum_next; /* 28 4 */ struct usb_devmap devmap; /* 32 16 */ struct usb_device * root_hub; /* 48 8 */ struct list_head bus_list; /* 56 16 */ /* --- cacheline 1 boundary (64 bytes) was 10 bytes ago --- */ int bandwidth_allocated; /* 72 4 */ int bandwidth_int_reqs; /* 76 4 */ int bandwidth_isoc_reqs; /* 80 4 */ /* XXX 4 bytes hole, try to pack */ struct dentry * usbfs_dentry; /* 88 8 */ struct class_device * class_dev; /* 96 8 */ struct mon_bus * mon_bus; /* 104 8 */ int monitored; /* 112 4 */ /* size: 120, cachelines: 2 */ /* sum members: 110, holes: 2, sum holes: 8 */ /* bit holes: 1, sum bit holes: 30 bits */ /* padding: 4 */ /* last cacheline: 56 bytes */ /* BRAIN FART ALERT! 120 != 110 + 8(holes), diff = 2 */ }; Look at the offset for the first entry in the bitfield (is_b_host), the compiler said in the DWARF info that it was at offset 25, when in fact it is at offset 26 as can be seen when looking at the generated assembly code. This previously was confusing libdwarves, as it uses subtracts the last offset from the current offset to see what was the size the compiler really allocated to then check if it is equal to the size of the previous entry, so as to detect alignment holes. The offsets are uint32_t, so cast both to int64_t when doing the calculation, the existing code already deals with negative numbers that result in this patologic case. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2007-12-07 00:59:42 +01:00
*/
const ssize_t cc_last_size = ((int64_t)pos->offset -
(int64_t)last->offset);
/*
* If the offset is the same this better be a bitfield
* or an empty struct (see rwlock_t in the Linux kernel
* sources when compiled for UP) or...
*/
if (cc_last_size > 0) {
/*
* Check if the DWARF byte_size info is smaller
* than the size used by the compiler, i.e.
* when combining small bitfields with the next
* member.
*/
if ((size_t)cc_last_size < last_size)
last_size = cc_last_size;
last->hole = cc_last_size - last_size;
if (last->hole > 0)
++self->nr_holes;
if (bit_sum != 0) {
[DWARVES]: Properly find holes in bitfields Make class__find_holes understand that when a byte offset goes backward it is because the compiler is "combining" small bitfields with previous fields, and using from the end of the combined bitfield + small fields. This made your head hurt, huh? One example: struct usb_bus { struct device * controller; /* 0 8 */ int busnum; /* 8 4 */ /* XXX 4 bytes hole, try to pack */ char * bus_name; /* 16 8 */ u8 uses_dma; /* 24 1 */ u8 otg_port; /* 25 1 */ /* Bitfield combined with previous fields */ unsigned int is_b_host:1; /* 24:15 4 */ unsigned int b_hnp_enable:1; /* 24:14 4 */ /* XXX 14 bits hole, try to pack */ int devnum_next; /* 28 4 */ struct usb_devmap devmap; /* 32 16 */ <SNIP> }; See? is_b_host:1 .. b_hnp_enable:1 makes a bitfield of just two bits. The programmer decided to make this a 'unsigned int' bitfield, so taking 4 bytes. And placed this "4" bytes bitfield just after two fields of one byte. The compiler put the "4" bytes bitfield "in the same place" as the "uses_dma" field, but its really not clobbering it neither "otg_port", as it allocates it from (offset 24 + sizeof(unsigned int) - 1), backwards. So at the end there is a, now correctly calculated, 14 bits hole, and that matches the bit offset used for the last field, that is "14", as offsets for bits and bytes starts at zero, all is explained now. One last thing is that since we actually have 14 bits we in fact have a one byte hole + a 6 bits hole, but that should be clear (haha) for those looking for holes :-) Nah, just run pahole reorganize on this beast and you'll have (for the complete structure, with the <SNIP> part back in: struct usb_bus { struct device * controller; /* 0 8 */ int busnum; /* 8 4 */ unsigned char is_b_host:1; /* 12:247 1 */ unsigned char b_hnp_enable:1; /* 12:246 1 */ /* XXX 6 bits hole, try to pack */ u8 otg_port; /* 13 1 */ u8 uses_dma; /* 14 1 */ /* XXX 1 byte hole, try to pack */ char * bus_name; /* 16 8 */ int bandwidth_isoc_reqs; /* 24 4 */ int devnum_next; /* 28 4 */ struct usb_devmap devmap; /* 32 16 */ struct usb_device * root_hub; /* 48 8 */ struct list_head bus_list; /* 56 16 */ /* --- cacheline 1 boundary (64 bytes) was 8 bytes ago --- */ int bandwidth_allocated; /* 72 4 */ int bandwidth_int_reqs; /* 76 4 */ struct dentry * usbfs_dentry; /* 80 8 */ struct class_device * class_dev; /* 88 8 */ struct mon_bus * mon_bus; /* 96 8 */ int monitored; /* 104 4 */ /* size: 112, cachelines: 2 */ /* sum members: 107, holes: 1, sum holes: 1 */ /* bit holes: 1, sum bit holes: 6 bits */ /* padding: 4 */ /* last cacheline: 48 bytes */ }; /* saved 8 bytes! */ And we save 8 bytes and reduce the previous complexity. Hey, but look at those bit offsets at is_b_host and b_hnp_enable... damn, exposing the bit offsets I just exposed another bug, that is: the reorganization code is not fixing up the bit offsets, one more for the TODO list, nah, just compile it and pass the results back to the dwarves and we get: struct usb_bus { struct device * controller; /* 0 8 */ int busnum; /* 8 4 */ unsigned char is_b_host:1; /* 12: 7 1 */ unsigned char b_hnp_enable:1; /* 12: 6 1 */ /* XXX 6 bits hole, try to pack */ u8 otg_port; /* 13 1 */ u8 uses_dma; /* 14 1 */ /* XXX 1 byte hole, try to pack */ char * bus_name; /* 16 8 */ int bandwidth_isoc_reqs; /* 24 4 */ int devnum_next; /* 28 4 */ struct usb_devmap devmap; /* 32 16 */ struct usb_device * root_hub; /* 48 8 */ struct list_head bus_list; /* 56 16 */ /* --- cacheline 1 boundary (64 bytes) was 8 bytes ago --- */ int bandwidth_allocated; /* 72 4 */ int bandwidth_int_reqs; /* 76 4 */ struct dentry * usbfs_dentry; /* 80 8 */ struct class_device * class_dev; /* 88 8 */ struct mon_bus * mon_bus; /* 96 8 */ int monitored; /* 104 4 */ /* size: 112, cachelines: 2 */ /* sum members: 107, holes: 1, sum holes: 1 */ /* bit holes: 1, sum bit holes: 6 bits */ /* padding: 4 */ /* last cacheline: 48 bytes */ }; See? this time gcc fixed up things for us and even agreed on the reorganization the dwarves did! 8-) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2007-12-07 18:03:27 +01:00
if (bitfield_real_offset != 0) {
last_size = bitfield_real_offset - last->offset;
bitfield_real_offset = 0;
}
last->bit_hole = (last_size * 8) -
bit_sum;
if (last->bit_hole != 0)
++self->nr_bit_holes;
[CLASSES]: Find bit holes An example is worth a thousand words, look for "XXX ... bit hole, try to pack" and the stats at the bottom: [acme@newtoy net-2.6]$ pahole ../OUTPUT/qemu/net-2.6/fs/inode.o task_struct /* include2/asm/system.h:11 */ struct task_struct { volatile long int state; /* 0 4 */ struct thread_info * thread_info; /* 4 4 */ atomic_t usage; /* 8 4 */ long unsigned int flags; /* 12 4 */ long unsigned int ptrace; /* 16 4 */ int lock_depth; /* 20 4 */ int load_weight; /* 24 4 */ int prio; /* 28 4 */ /* --- cacheline 1 boundary (32 bytes) --- */ int static_prio; /* 32 4 */ int normal_prio; /* 36 4 */ struct list_head run_list; /* 40 8 */ struct prio_array * array; /* 48 4 */ short unsigned int ioprio; /* 52 2 */ /* XXX 2 bytes hole, try to pack */ long unsigned int sleep_avg; /* 56 4 */ long long unsigned int timestamp; /* 60 8 */ /* --- cacheline 2 boundary (64 bytes) was 4 bytes ago --- */ long long unsigned int last_ran; /* 68 8 */ long long unsigned int sched_time; /* 76 8 */ enum sleep_type sleep_type; /* 84 4 */ long unsigned int policy; /* 88 4 */ cpumask_t cpus_allowed; /* 92 4 */ /* --- cacheline 3 boundary (96 bytes) --- */ unsigned int time_slice; /* 96 4 */ unsigned int first_time_slice; /* 100 4 */ struct list_head tasks; /* 104 8 */ struct list_head ptrace_children; /* 112 8 */ struct list_head ptrace_list; /* 120 8 */ /* --- cacheline 4 boundary (128 bytes) --- */ struct mm_struct * mm; /* 128 4 */ struct mm_struct * active_mm; /* 132 4 */ struct linux_binfmt * binfmt; /* 136 4 */ long int exit_state; /* 140 4 */ int exit_code; /* 144 4 */ int exit_signal; /* 148 4 */ int pdeath_signal; /* 152 4 */ long unsigned int personality; /* 156 4 */ /* --- cacheline 5 boundary (160 bytes) --- */ unsigned int did_exec:1; /* 160 4 */ /* XXX 31 bits hole, try to pack */ pid_t pid; /* 164 4 */ pid_t tgid; /* 168 4 */ struct task_struct * real_parent; /* 172 4 */ struct task_struct * parent; /* 176 4 */ struct list_head children; /* 180 8 */ struct list_head sibling; /* 188 8 */ /* --- cacheline 6 boundary (192 bytes) was 4 bytes ago --- */ struct task_struct * group_leader; /* 196 4 */ struct pid_link pids[3]; /* 200 36 */ /* --- cacheline 7 boundary (224 bytes) was 12 bytes ago --- */ struct list_head thread_group; /* 236 8 */ struct completion * vfork_done; /* 244 4 */ int * set_child_tid; /* 248 4 */ int * clear_child_tid; /* 252 4 */ /* --- cacheline 8 boundary (256 bytes) --- */ long unsigned int rt_priority; /* 256 4 */ cputime_t utime; /* 260 4 */ cputime_t stime; /* 264 4 */ long unsigned int nvcsw; /* 268 4 */ long unsigned int nivcsw; /* 272 4 */ struct timespec start_time; /* 276 8 */ long unsigned int min_flt; /* 284 4 */ /* --- cacheline 9 boundary (288 bytes) --- */ long unsigned int maj_flt; /* 288 4 */ cputime_t it_prof_expires; /* 292 4 */ cputime_t it_virt_expires; /* 296 4 */ long long unsigned int it_sched_expires; /* 300 8 */ struct list_head cpu_timers[3]; /* 308 24 */ /* --- cacheline 10 boundary (320 bytes) was 12 bytes ago --- */ uid_t uid; /* 332 4 */ uid_t euid; /* 336 4 */ uid_t suid; /* 340 4 */ uid_t fsuid; /* 344 4 */ gid_t gid; /* 348 4 */ /* --- cacheline 11 boundary (352 bytes) --- */ gid_t egid; /* 352 4 */ gid_t sgid; /* 356 4 */ gid_t fsgid; /* 360 4 */ struct group_info * group_info; /* 364 4 */ kernel_cap_t cap_effective; /* 368 4 */ kernel_cap_t cap_inheritable; /* 372 4 */ kernel_cap_t cap_permitted; /* 376 4 */ unsigned int keep_capabilities:1; /* 380 4 */ /* XXX 31 bits hole, try to pack */ /* --- cacheline 12 boundary (384 bytes) --- */ struct user_struct * user; /* 384 4 */ struct key * request_key_auth; /* 388 4 */ struct key * thread_keyring; /* 392 4 */ unsigned char jit_keyring; /* 396 1 */ unsigned char fpu_counter; /* 397 1 */ /* XXX 2 bytes hole, try to pack */ int oomkilladj; /* 400 4 */ char comm[16]; /* 404 16 */ /* --- cacheline 13 boundary (416 bytes) was 4 bytes ago --- */ int link_count; /* 420 4 */ int total_link_count; /* 424 4 */ struct sysv_sem sysvsem; /* 428 4 */ struct thread_struct thread; /* 432 656 */ /* --- cacheline 34 boundary (1088 bytes) --- */ struct fs_struct * fs; /* 1088 4 */ struct files_struct * files; /* 1092 4 */ struct nsproxy * nsproxy; /* 1096 4 */ struct signal_struct * signal; /* 1100 4 */ struct sighand_struct * sighand; /* 1104 4 */ sigset_t blocked; /* 1108 8 */ sigset_t real_blocked; /* 1116 8 */ /* --- cacheline 35 boundary (1120 bytes) was 4 bytes ago --- */ sigset_t saved_sigmask; /* 1124 8 */ struct sigpending pending; /* 1132 16 */ long unsigned int sas_ss_sp; /* 1148 4 */ /* --- cacheline 36 boundary (1152 bytes) --- */ size_t sas_ss_size; /* 1152 4 */ int (*notifier)(); /* 1156 4 */ void * notifier_data; /* 1160 4 */ sigset_t * notifier_mask; /* 1164 4 */ void * security; /* 1168 4 */ struct audit_context * audit_context; /* 1172 4 */ seccomp_t seccomp; /* 1176 0 */ u32 parent_exec_id; /* 1176 4 */ u32 self_exec_id; /* 1180 4 */ /* --- cacheline 37 boundary (1184 bytes) --- */ spinlock_t alloc_lock; /* 1184 40 */ /* --- cacheline 38 boundary (1216 bytes) was 8 bytes ago --- */ spinlock_t pi_lock; /* 1224 40 */ /* --- cacheline 39 boundary (1248 bytes) was 16 bytes ago --- */ struct plist_head pi_waiters; /* 1264 20 */ /* --- cacheline 40 boundary (1280 bytes) was 4 bytes ago --- */ struct rt_mutex_waiter * pi_blocked_on; /* 1284 4 */ struct mutex_waiter * blocked_on; /* 1288 4 */ unsigned int irq_events; /* 1292 4 */ int hardirqs_enabled; /* 1296 4 */ long unsigned int hardirq_enable_ip; /* 1300 4 */ unsigned int hardirq_enable_event; /* 1304 4 */ long unsigned int hardirq_disable_ip; /* 1308 4 */ /* --- cacheline 41 boundary (1312 bytes) --- */ unsigned int hardirq_disable_event; /* 1312 4 */ int softirqs_enabled; /* 1316 4 */ long unsigned int softirq_disable_ip; /* 1320 4 */ unsigned int softirq_disable_event; /* 1324 4 */ long unsigned int softirq_enable_ip; /* 1328 4 */ unsigned int softirq_enable_event; /* 1332 4 */ int hardirq_context; /* 1336 4 */ int softirq_context; /* 1340 4 */ /* --- cacheline 42 boundary (1344 bytes) --- */ u64 curr_chain_key; /* 1344 8 */ int lockdep_depth; /* 1352 4 */ struct held_lock held_locks[30]; /* 1356 1200 */ /* --- cacheline 79 boundary (2528 bytes) was 28 bytes ago --- */ unsigned int lockdep_recursion; /* 2556 4 */ /* --- cacheline 80 boundary (2560 bytes) --- */ void * journal_info; /* 2560 4 */ struct reclaim_state * reclaim_state; /* 2564 4 */ struct backing_dev_info * backing_dev_info; /* 2568 4 */ struct io_context * io_context; /* 2572 4 */ long unsigned int ptrace_message; /* 2576 4 */ siginfo_t * last_siginfo; /* 2580 4 */ wait_queue_t * io_wait; /* 2584 4 */ u64 rchar; /* 2588 8 */ /* --- cacheline 81 boundary (2592 bytes) was 4 bytes ago --- */ u64 wchar; /* 2596 8 */ u64 syscr; /* 2604 8 */ u64 syscw; /* 2612 8 */ struct robust_list_head * robust_list; /* 2620 4 */ /* --- cacheline 82 boundary (2624 bytes) --- */ struct list_head pi_state_list; /* 2624 8 */ struct futex_pi_state * pi_state_cache; /* 2632 4 */ atomic_t fs_excl; /* 2636 4 */ struct rcu_head rcu; /* 2640 8 */ struct pipe_inode_info * splice_pipe; /* 2648 4 */ }; /* size: 2656, cachelines: 83 */ /* sum members: 2648, holes: 2, sum holes: 4 */ /* bit holes: 2, sum bit holes: 62 bits */ /* padding: 4 */ Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-07 15:26:50 +01:00
last->bitfield_end = 1;
bit_sum = 0;
}
[DWARVES]: Properly find holes in bitfields Make class__find_holes understand that when a byte offset goes backward it is because the compiler is "combining" small bitfields with previous fields, and using from the end of the combined bitfield + small fields. This made your head hurt, huh? One example: struct usb_bus { struct device * controller; /* 0 8 */ int busnum; /* 8 4 */ /* XXX 4 bytes hole, try to pack */ char * bus_name; /* 16 8 */ u8 uses_dma; /* 24 1 */ u8 otg_port; /* 25 1 */ /* Bitfield combined with previous fields */ unsigned int is_b_host:1; /* 24:15 4 */ unsigned int b_hnp_enable:1; /* 24:14 4 */ /* XXX 14 bits hole, try to pack */ int devnum_next; /* 28 4 */ struct usb_devmap devmap; /* 32 16 */ <SNIP> }; See? is_b_host:1 .. b_hnp_enable:1 makes a bitfield of just two bits. The programmer decided to make this a 'unsigned int' bitfield, so taking 4 bytes. And placed this "4" bytes bitfield just after two fields of one byte. The compiler put the "4" bytes bitfield "in the same place" as the "uses_dma" field, but its really not clobbering it neither "otg_port", as it allocates it from (offset 24 + sizeof(unsigned int) - 1), backwards. So at the end there is a, now correctly calculated, 14 bits hole, and that matches the bit offset used for the last field, that is "14", as offsets for bits and bytes starts at zero, all is explained now. One last thing is that since we actually have 14 bits we in fact have a one byte hole + a 6 bits hole, but that should be clear (haha) for those looking for holes :-) Nah, just run pahole reorganize on this beast and you'll have (for the complete structure, with the <SNIP> part back in: struct usb_bus { struct device * controller; /* 0 8 */ int busnum; /* 8 4 */ unsigned char is_b_host:1; /* 12:247 1 */ unsigned char b_hnp_enable:1; /* 12:246 1 */ /* XXX 6 bits hole, try to pack */ u8 otg_port; /* 13 1 */ u8 uses_dma; /* 14 1 */ /* XXX 1 byte hole, try to pack */ char * bus_name; /* 16 8 */ int bandwidth_isoc_reqs; /* 24 4 */ int devnum_next; /* 28 4 */ struct usb_devmap devmap; /* 32 16 */ struct usb_device * root_hub; /* 48 8 */ struct list_head bus_list; /* 56 16 */ /* --- cacheline 1 boundary (64 bytes) was 8 bytes ago --- */ int bandwidth_allocated; /* 72 4 */ int bandwidth_int_reqs; /* 76 4 */ struct dentry * usbfs_dentry; /* 80 8 */ struct class_device * class_dev; /* 88 8 */ struct mon_bus * mon_bus; /* 96 8 */ int monitored; /* 104 4 */ /* size: 112, cachelines: 2 */ /* sum members: 107, holes: 1, sum holes: 1 */ /* bit holes: 1, sum bit holes: 6 bits */ /* padding: 4 */ /* last cacheline: 48 bytes */ }; /* saved 8 bytes! */ And we save 8 bytes and reduce the previous complexity. Hey, but look at those bit offsets at is_b_host and b_hnp_enable... damn, exposing the bit offsets I just exposed another bug, that is: the reorganization code is not fixing up the bit offsets, one more for the TODO list, nah, just compile it and pass the results back to the dwarves and we get: struct usb_bus { struct device * controller; /* 0 8 */ int busnum; /* 8 4 */ unsigned char is_b_host:1; /* 12: 7 1 */ unsigned char b_hnp_enable:1; /* 12: 6 1 */ /* XXX 6 bits hole, try to pack */ u8 otg_port; /* 13 1 */ u8 uses_dma; /* 14 1 */ /* XXX 1 byte hole, try to pack */ char * bus_name; /* 16 8 */ int bandwidth_isoc_reqs; /* 24 4 */ int devnum_next; /* 28 4 */ struct usb_devmap devmap; /* 32 16 */ struct usb_device * root_hub; /* 48 8 */ struct list_head bus_list; /* 56 16 */ /* --- cacheline 1 boundary (64 bytes) was 8 bytes ago --- */ int bandwidth_allocated; /* 72 4 */ int bandwidth_int_reqs; /* 76 4 */ struct dentry * usbfs_dentry; /* 80 8 */ struct class_device * class_dev; /* 88 8 */ struct mon_bus * mon_bus; /* 96 8 */ int monitored; /* 104 4 */ /* size: 112, cachelines: 2 */ /* sum members: 107, holes: 1, sum holes: 1 */ /* bit holes: 1, sum bit holes: 6 bits */ /* padding: 4 */ /* last cacheline: 48 bytes */ }; See? this time gcc fixed up things for us and even agreed on the reorganization the dwarves did! 8-) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2007-12-07 18:03:27 +01:00
} else if (cc_last_size < 0 && bit_sum == 0)
bitfield_real_offset = last->offset + last_size;
}
[CLASSES]: Find bit holes An example is worth a thousand words, look for "XXX ... bit hole, try to pack" and the stats at the bottom: [acme@newtoy net-2.6]$ pahole ../OUTPUT/qemu/net-2.6/fs/inode.o task_struct /* include2/asm/system.h:11 */ struct task_struct { volatile long int state; /* 0 4 */ struct thread_info * thread_info; /* 4 4 */ atomic_t usage; /* 8 4 */ long unsigned int flags; /* 12 4 */ long unsigned int ptrace; /* 16 4 */ int lock_depth; /* 20 4 */ int load_weight; /* 24 4 */ int prio; /* 28 4 */ /* --- cacheline 1 boundary (32 bytes) --- */ int static_prio; /* 32 4 */ int normal_prio; /* 36 4 */ struct list_head run_list; /* 40 8 */ struct prio_array * array; /* 48 4 */ short unsigned int ioprio; /* 52 2 */ /* XXX 2 bytes hole, try to pack */ long unsigned int sleep_avg; /* 56 4 */ long long unsigned int timestamp; /* 60 8 */ /* --- cacheline 2 boundary (64 bytes) was 4 bytes ago --- */ long long unsigned int last_ran; /* 68 8 */ long long unsigned int sched_time; /* 76 8 */ enum sleep_type sleep_type; /* 84 4 */ long unsigned int policy; /* 88 4 */ cpumask_t cpus_allowed; /* 92 4 */ /* --- cacheline 3 boundary (96 bytes) --- */ unsigned int time_slice; /* 96 4 */ unsigned int first_time_slice; /* 100 4 */ struct list_head tasks; /* 104 8 */ struct list_head ptrace_children; /* 112 8 */ struct list_head ptrace_list; /* 120 8 */ /* --- cacheline 4 boundary (128 bytes) --- */ struct mm_struct * mm; /* 128 4 */ struct mm_struct * active_mm; /* 132 4 */ struct linux_binfmt * binfmt; /* 136 4 */ long int exit_state; /* 140 4 */ int exit_code; /* 144 4 */ int exit_signal; /* 148 4 */ int pdeath_signal; /* 152 4 */ long unsigned int personality; /* 156 4 */ /* --- cacheline 5 boundary (160 bytes) --- */ unsigned int did_exec:1; /* 160 4 */ /* XXX 31 bits hole, try to pack */ pid_t pid; /* 164 4 */ pid_t tgid; /* 168 4 */ struct task_struct * real_parent; /* 172 4 */ struct task_struct * parent; /* 176 4 */ struct list_head children; /* 180 8 */ struct list_head sibling; /* 188 8 */ /* --- cacheline 6 boundary (192 bytes) was 4 bytes ago --- */ struct task_struct * group_leader; /* 196 4 */ struct pid_link pids[3]; /* 200 36 */ /* --- cacheline 7 boundary (224 bytes) was 12 bytes ago --- */ struct list_head thread_group; /* 236 8 */ struct completion * vfork_done; /* 244 4 */ int * set_child_tid; /* 248 4 */ int * clear_child_tid; /* 252 4 */ /* --- cacheline 8 boundary (256 bytes) --- */ long unsigned int rt_priority; /* 256 4 */ cputime_t utime; /* 260 4 */ cputime_t stime; /* 264 4 */ long unsigned int nvcsw; /* 268 4 */ long unsigned int nivcsw; /* 272 4 */ struct timespec start_time; /* 276 8 */ long unsigned int min_flt; /* 284 4 */ /* --- cacheline 9 boundary (288 bytes) --- */ long unsigned int maj_flt; /* 288 4 */ cputime_t it_prof_expires; /* 292 4 */ cputime_t it_virt_expires; /* 296 4 */ long long unsigned int it_sched_expires; /* 300 8 */ struct list_head cpu_timers[3]; /* 308 24 */ /* --- cacheline 10 boundary (320 bytes) was 12 bytes ago --- */ uid_t uid; /* 332 4 */ uid_t euid; /* 336 4 */ uid_t suid; /* 340 4 */ uid_t fsuid; /* 344 4 */ gid_t gid; /* 348 4 */ /* --- cacheline 11 boundary (352 bytes) --- */ gid_t egid; /* 352 4 */ gid_t sgid; /* 356 4 */ gid_t fsgid; /* 360 4 */ struct group_info * group_info; /* 364 4 */ kernel_cap_t cap_effective; /* 368 4 */ kernel_cap_t cap_inheritable; /* 372 4 */ kernel_cap_t cap_permitted; /* 376 4 */ unsigned int keep_capabilities:1; /* 380 4 */ /* XXX 31 bits hole, try to pack */ /* --- cacheline 12 boundary (384 bytes) --- */ struct user_struct * user; /* 384 4 */ struct key * request_key_auth; /* 388 4 */ struct key * thread_keyring; /* 392 4 */ unsigned char jit_keyring; /* 396 1 */ unsigned char fpu_counter; /* 397 1 */ /* XXX 2 bytes hole, try to pack */ int oomkilladj; /* 400 4 */ char comm[16]; /* 404 16 */ /* --- cacheline 13 boundary (416 bytes) was 4 bytes ago --- */ int link_count; /* 420 4 */ int total_link_count; /* 424 4 */ struct sysv_sem sysvsem; /* 428 4 */ struct thread_struct thread; /* 432 656 */ /* --- cacheline 34 boundary (1088 bytes) --- */ struct fs_struct * fs; /* 1088 4 */ struct files_struct * files; /* 1092 4 */ struct nsproxy * nsproxy; /* 1096 4 */ struct signal_struct * signal; /* 1100 4 */ struct sighand_struct * sighand; /* 1104 4 */ sigset_t blocked; /* 1108 8 */ sigset_t real_blocked; /* 1116 8 */ /* --- cacheline 35 boundary (1120 bytes) was 4 bytes ago --- */ sigset_t saved_sigmask; /* 1124 8 */ struct sigpending pending; /* 1132 16 */ long unsigned int sas_ss_sp; /* 1148 4 */ /* --- cacheline 36 boundary (1152 bytes) --- */ size_t sas_ss_size; /* 1152 4 */ int (*notifier)(); /* 1156 4 */ void * notifier_data; /* 1160 4 */ sigset_t * notifier_mask; /* 1164 4 */ void * security; /* 1168 4 */ struct audit_context * audit_context; /* 1172 4 */ seccomp_t seccomp; /* 1176 0 */ u32 parent_exec_id; /* 1176 4 */ u32 self_exec_id; /* 1180 4 */ /* --- cacheline 37 boundary (1184 bytes) --- */ spinlock_t alloc_lock; /* 1184 40 */ /* --- cacheline 38 boundary (1216 bytes) was 8 bytes ago --- */ spinlock_t pi_lock; /* 1224 40 */ /* --- cacheline 39 boundary (1248 bytes) was 16 bytes ago --- */ struct plist_head pi_waiters; /* 1264 20 */ /* --- cacheline 40 boundary (1280 bytes) was 4 bytes ago --- */ struct rt_mutex_waiter * pi_blocked_on; /* 1284 4 */ struct mutex_waiter * blocked_on; /* 1288 4 */ unsigned int irq_events; /* 1292 4 */ int hardirqs_enabled; /* 1296 4 */ long unsigned int hardirq_enable_ip; /* 1300 4 */ unsigned int hardirq_enable_event; /* 1304 4 */ long unsigned int hardirq_disable_ip; /* 1308 4 */ /* --- cacheline 41 boundary (1312 bytes) --- */ unsigned int hardirq_disable_event; /* 1312 4 */ int softirqs_enabled; /* 1316 4 */ long unsigned int softirq_disable_ip; /* 1320 4 */ unsigned int softirq_disable_event; /* 1324 4 */ long unsigned int softirq_enable_ip; /* 1328 4 */ unsigned int softirq_enable_event; /* 1332 4 */ int hardirq_context; /* 1336 4 */ int softirq_context; /* 1340 4 */ /* --- cacheline 42 boundary (1344 bytes) --- */ u64 curr_chain_key; /* 1344 8 */ int lockdep_depth; /* 1352 4 */ struct held_lock held_locks[30]; /* 1356 1200 */ /* --- cacheline 79 boundary (2528 bytes) was 28 bytes ago --- */ unsigned int lockdep_recursion; /* 2556 4 */ /* --- cacheline 80 boundary (2560 bytes) --- */ void * journal_info; /* 2560 4 */ struct reclaim_state * reclaim_state; /* 2564 4 */ struct backing_dev_info * backing_dev_info; /* 2568 4 */ struct io_context * io_context; /* 2572 4 */ long unsigned int ptrace_message; /* 2576 4 */ siginfo_t * last_siginfo; /* 2580 4 */ wait_queue_t * io_wait; /* 2584 4 */ u64 rchar; /* 2588 8 */ /* --- cacheline 81 boundary (2592 bytes) was 4 bytes ago --- */ u64 wchar; /* 2596 8 */ u64 syscr; /* 2604 8 */ u64 syscw; /* 2612 8 */ struct robust_list_head * robust_list; /* 2620 4 */ /* --- cacheline 82 boundary (2624 bytes) --- */ struct list_head pi_state_list; /* 2624 8 */ struct futex_pi_state * pi_state_cache; /* 2632 4 */ atomic_t fs_excl; /* 2636 4 */ struct rcu_head rcu; /* 2640 8 */ struct pipe_inode_info * splice_pipe; /* 2648 4 */ }; /* size: 2656, cachelines: 83 */ /* sum members: 2648, holes: 2, sum holes: 4 */ /* bit holes: 2, sum bit holes: 62 bits */ /* padding: 4 */ Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-07 15:26:50 +01:00
bit_sum += pos->bit_size;
size = class_member__size(pos, cu);
/*
* check for bitfields, accounting for only the biggest of the
* byte_size in the fields in each bitfield set.
*/
if (last == NULL || last->offset != pos->offset ||
pos->bit_size == 0 || last->bit_size == 0) {
last_size = size;
} else if (size > last_size)
last_size = size;
last = pos;
}
[CLASSES]: Find bit holes An example is worth a thousand words, look for "XXX ... bit hole, try to pack" and the stats at the bottom: [acme@newtoy net-2.6]$ pahole ../OUTPUT/qemu/net-2.6/fs/inode.o task_struct /* include2/asm/system.h:11 */ struct task_struct { volatile long int state; /* 0 4 */ struct thread_info * thread_info; /* 4 4 */ atomic_t usage; /* 8 4 */ long unsigned int flags; /* 12 4 */ long unsigned int ptrace; /* 16 4 */ int lock_depth; /* 20 4 */ int load_weight; /* 24 4 */ int prio; /* 28 4 */ /* --- cacheline 1 boundary (32 bytes) --- */ int static_prio; /* 32 4 */ int normal_prio; /* 36 4 */ struct list_head run_list; /* 40 8 */ struct prio_array * array; /* 48 4 */ short unsigned int ioprio; /* 52 2 */ /* XXX 2 bytes hole, try to pack */ long unsigned int sleep_avg; /* 56 4 */ long long unsigned int timestamp; /* 60 8 */ /* --- cacheline 2 boundary (64 bytes) was 4 bytes ago --- */ long long unsigned int last_ran; /* 68 8 */ long long unsigned int sched_time; /* 76 8 */ enum sleep_type sleep_type; /* 84 4 */ long unsigned int policy; /* 88 4 */ cpumask_t cpus_allowed; /* 92 4 */ /* --- cacheline 3 boundary (96 bytes) --- */ unsigned int time_slice; /* 96 4 */ unsigned int first_time_slice; /* 100 4 */ struct list_head tasks; /* 104 8 */ struct list_head ptrace_children; /* 112 8 */ struct list_head ptrace_list; /* 120 8 */ /* --- cacheline 4 boundary (128 bytes) --- */ struct mm_struct * mm; /* 128 4 */ struct mm_struct * active_mm; /* 132 4 */ struct linux_binfmt * binfmt; /* 136 4 */ long int exit_state; /* 140 4 */ int exit_code; /* 144 4 */ int exit_signal; /* 148 4 */ int pdeath_signal; /* 152 4 */ long unsigned int personality; /* 156 4 */ /* --- cacheline 5 boundary (160 bytes) --- */ unsigned int did_exec:1; /* 160 4 */ /* XXX 31 bits hole, try to pack */ pid_t pid; /* 164 4 */ pid_t tgid; /* 168 4 */ struct task_struct * real_parent; /* 172 4 */ struct task_struct * parent; /* 176 4 */ struct list_head children; /* 180 8 */ struct list_head sibling; /* 188 8 */ /* --- cacheline 6 boundary (192 bytes) was 4 bytes ago --- */ struct task_struct * group_leader; /* 196 4 */ struct pid_link pids[3]; /* 200 36 */ /* --- cacheline 7 boundary (224 bytes) was 12 bytes ago --- */ struct list_head thread_group; /* 236 8 */ struct completion * vfork_done; /* 244 4 */ int * set_child_tid; /* 248 4 */ int * clear_child_tid; /* 252 4 */ /* --- cacheline 8 boundary (256 bytes) --- */ long unsigned int rt_priority; /* 256 4 */ cputime_t utime; /* 260 4 */ cputime_t stime; /* 264 4 */ long unsigned int nvcsw; /* 268 4 */ long unsigned int nivcsw; /* 272 4 */ struct timespec start_time; /* 276 8 */ long unsigned int min_flt; /* 284 4 */ /* --- cacheline 9 boundary (288 bytes) --- */ long unsigned int maj_flt; /* 288 4 */ cputime_t it_prof_expires; /* 292 4 */ cputime_t it_virt_expires; /* 296 4 */ long long unsigned int it_sched_expires; /* 300 8 */ struct list_head cpu_timers[3]; /* 308 24 */ /* --- cacheline 10 boundary (320 bytes) was 12 bytes ago --- */ uid_t uid; /* 332 4 */ uid_t euid; /* 336 4 */ uid_t suid; /* 340 4 */ uid_t fsuid; /* 344 4 */ gid_t gid; /* 348 4 */ /* --- cacheline 11 boundary (352 bytes) --- */ gid_t egid; /* 352 4 */ gid_t sgid; /* 356 4 */ gid_t fsgid; /* 360 4 */ struct group_info * group_info; /* 364 4 */ kernel_cap_t cap_effective; /* 368 4 */ kernel_cap_t cap_inheritable; /* 372 4 */ kernel_cap_t cap_permitted; /* 376 4 */ unsigned int keep_capabilities:1; /* 380 4 */ /* XXX 31 bits hole, try to pack */ /* --- cacheline 12 boundary (384 bytes) --- */ struct user_struct * user; /* 384 4 */ struct key * request_key_auth; /* 388 4 */ struct key * thread_keyring; /* 392 4 */ unsigned char jit_keyring; /* 396 1 */ unsigned char fpu_counter; /* 397 1 */ /* XXX 2 bytes hole, try to pack */ int oomkilladj; /* 400 4 */ char comm[16]; /* 404 16 */ /* --- cacheline 13 boundary (416 bytes) was 4 bytes ago --- */ int link_count; /* 420 4 */ int total_link_count; /* 424 4 */ struct sysv_sem sysvsem; /* 428 4 */ struct thread_struct thread; /* 432 656 */ /* --- cacheline 34 boundary (1088 bytes) --- */ struct fs_struct * fs; /* 1088 4 */ struct files_struct * files; /* 1092 4 */ struct nsproxy * nsproxy; /* 1096 4 */ struct signal_struct * signal; /* 1100 4 */ struct sighand_struct * sighand; /* 1104 4 */ sigset_t blocked; /* 1108 8 */ sigset_t real_blocked; /* 1116 8 */ /* --- cacheline 35 boundary (1120 bytes) was 4 bytes ago --- */ sigset_t saved_sigmask; /* 1124 8 */ struct sigpending pending; /* 1132 16 */ long unsigned int sas_ss_sp; /* 1148 4 */ /* --- cacheline 36 boundary (1152 bytes) --- */ size_t sas_ss_size; /* 1152 4 */ int (*notifier)(); /* 1156 4 */ void * notifier_data; /* 1160 4 */ sigset_t * notifier_mask; /* 1164 4 */ void * security; /* 1168 4 */ struct audit_context * audit_context; /* 1172 4 */ seccomp_t seccomp; /* 1176 0 */ u32 parent_exec_id; /* 1176 4 */ u32 self_exec_id; /* 1180 4 */ /* --- cacheline 37 boundary (1184 bytes) --- */ spinlock_t alloc_lock; /* 1184 40 */ /* --- cacheline 38 boundary (1216 bytes) was 8 bytes ago --- */ spinlock_t pi_lock; /* 1224 40 */ /* --- cacheline 39 boundary (1248 bytes) was 16 bytes ago --- */ struct plist_head pi_waiters; /* 1264 20 */ /* --- cacheline 40 boundary (1280 bytes) was 4 bytes ago --- */ struct rt_mutex_waiter * pi_blocked_on; /* 1284 4 */ struct mutex_waiter * blocked_on; /* 1288 4 */ unsigned int irq_events; /* 1292 4 */ int hardirqs_enabled; /* 1296 4 */ long unsigned int hardirq_enable_ip; /* 1300 4 */ unsigned int hardirq_enable_event; /* 1304 4 */ long unsigned int hardirq_disable_ip; /* 1308 4 */ /* --- cacheline 41 boundary (1312 bytes) --- */ unsigned int hardirq_disable_event; /* 1312 4 */ int softirqs_enabled; /* 1316 4 */ long unsigned int softirq_disable_ip; /* 1320 4 */ unsigned int softirq_disable_event; /* 1324 4 */ long unsigned int softirq_enable_ip; /* 1328 4 */ unsigned int softirq_enable_event; /* 1332 4 */ int hardirq_context; /* 1336 4 */ int softirq_context; /* 1340 4 */ /* --- cacheline 42 boundary (1344 bytes) --- */ u64 curr_chain_key; /* 1344 8 */ int lockdep_depth; /* 1352 4 */ struct held_lock held_locks[30]; /* 1356 1200 */ /* --- cacheline 79 boundary (2528 bytes) was 28 bytes ago --- */ unsigned int lockdep_recursion; /* 2556 4 */ /* --- cacheline 80 boundary (2560 bytes) --- */ void * journal_info; /* 2560 4 */ struct reclaim_state * reclaim_state; /* 2564 4 */ struct backing_dev_info * backing_dev_info; /* 2568 4 */ struct io_context * io_context; /* 2572 4 */ long unsigned int ptrace_message; /* 2576 4 */ siginfo_t * last_siginfo; /* 2580 4 */ wait_queue_t * io_wait; /* 2584 4 */ u64 rchar; /* 2588 8 */ /* --- cacheline 81 boundary (2592 bytes) was 4 bytes ago --- */ u64 wchar; /* 2596 8 */ u64 syscr; /* 2604 8 */ u64 syscw; /* 2612 8 */ struct robust_list_head * robust_list; /* 2620 4 */ /* --- cacheline 82 boundary (2624 bytes) --- */ struct list_head pi_state_list; /* 2624 8 */ struct futex_pi_state * pi_state_cache; /* 2632 4 */ atomic_t fs_excl; /* 2636 4 */ struct rcu_head rcu; /* 2640 8 */ struct pipe_inode_info * splice_pipe; /* 2648 4 */ }; /* size: 2656, cachelines: 83 */ /* sum members: 2648, holes: 2, sum holes: 4 */ /* bit holes: 2, sum bit holes: 62 bits */ /* padding: 4 */ Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-07 15:26:50 +01:00
if (last != NULL) {
if (last->offset + last_size != ctype->size)
self->padding = ctype->size -
(last->offset + last_size);
[CLASSES]: Find bit holes An example is worth a thousand words, look for "XXX ... bit hole, try to pack" and the stats at the bottom: [acme@newtoy net-2.6]$ pahole ../OUTPUT/qemu/net-2.6/fs/inode.o task_struct /* include2/asm/system.h:11 */ struct task_struct { volatile long int state; /* 0 4 */ struct thread_info * thread_info; /* 4 4 */ atomic_t usage; /* 8 4 */ long unsigned int flags; /* 12 4 */ long unsigned int ptrace; /* 16 4 */ int lock_depth; /* 20 4 */ int load_weight; /* 24 4 */ int prio; /* 28 4 */ /* --- cacheline 1 boundary (32 bytes) --- */ int static_prio; /* 32 4 */ int normal_prio; /* 36 4 */ struct list_head run_list; /* 40 8 */ struct prio_array * array; /* 48 4 */ short unsigned int ioprio; /* 52 2 */ /* XXX 2 bytes hole, try to pack */ long unsigned int sleep_avg; /* 56 4 */ long long unsigned int timestamp; /* 60 8 */ /* --- cacheline 2 boundary (64 bytes) was 4 bytes ago --- */ long long unsigned int last_ran; /* 68 8 */ long long unsigned int sched_time; /* 76 8 */ enum sleep_type sleep_type; /* 84 4 */ long unsigned int policy; /* 88 4 */ cpumask_t cpus_allowed; /* 92 4 */ /* --- cacheline 3 boundary (96 bytes) --- */ unsigned int time_slice; /* 96 4 */ unsigned int first_time_slice; /* 100 4 */ struct list_head tasks; /* 104 8 */ struct list_head ptrace_children; /* 112 8 */ struct list_head ptrace_list; /* 120 8 */ /* --- cacheline 4 boundary (128 bytes) --- */ struct mm_struct * mm; /* 128 4 */ struct mm_struct * active_mm; /* 132 4 */ struct linux_binfmt * binfmt; /* 136 4 */ long int exit_state; /* 140 4 */ int exit_code; /* 144 4 */ int exit_signal; /* 148 4 */ int pdeath_signal; /* 152 4 */ long unsigned int personality; /* 156 4 */ /* --- cacheline 5 boundary (160 bytes) --- */ unsigned int did_exec:1; /* 160 4 */ /* XXX 31 bits hole, try to pack */ pid_t pid; /* 164 4 */ pid_t tgid; /* 168 4 */ struct task_struct * real_parent; /* 172 4 */ struct task_struct * parent; /* 176 4 */ struct list_head children; /* 180 8 */ struct list_head sibling; /* 188 8 */ /* --- cacheline 6 boundary (192 bytes) was 4 bytes ago --- */ struct task_struct * group_leader; /* 196 4 */ struct pid_link pids[3]; /* 200 36 */ /* --- cacheline 7 boundary (224 bytes) was 12 bytes ago --- */ struct list_head thread_group; /* 236 8 */ struct completion * vfork_done; /* 244 4 */ int * set_child_tid; /* 248 4 */ int * clear_child_tid; /* 252 4 */ /* --- cacheline 8 boundary (256 bytes) --- */ long unsigned int rt_priority; /* 256 4 */ cputime_t utime; /* 260 4 */ cputime_t stime; /* 264 4 */ long unsigned int nvcsw; /* 268 4 */ long unsigned int nivcsw; /* 272 4 */ struct timespec start_time; /* 276 8 */ long unsigned int min_flt; /* 284 4 */ /* --- cacheline 9 boundary (288 bytes) --- */ long unsigned int maj_flt; /* 288 4 */ cputime_t it_prof_expires; /* 292 4 */ cputime_t it_virt_expires; /* 296 4 */ long long unsigned int it_sched_expires; /* 300 8 */ struct list_head cpu_timers[3]; /* 308 24 */ /* --- cacheline 10 boundary (320 bytes) was 12 bytes ago --- */ uid_t uid; /* 332 4 */ uid_t euid; /* 336 4 */ uid_t suid; /* 340 4 */ uid_t fsuid; /* 344 4 */ gid_t gid; /* 348 4 */ /* --- cacheline 11 boundary (352 bytes) --- */ gid_t egid; /* 352 4 */ gid_t sgid; /* 356 4 */ gid_t fsgid; /* 360 4 */ struct group_info * group_info; /* 364 4 */ kernel_cap_t cap_effective; /* 368 4 */ kernel_cap_t cap_inheritable; /* 372 4 */ kernel_cap_t cap_permitted; /* 376 4 */ unsigned int keep_capabilities:1; /* 380 4 */ /* XXX 31 bits hole, try to pack */ /* --- cacheline 12 boundary (384 bytes) --- */ struct user_struct * user; /* 384 4 */ struct key * request_key_auth; /* 388 4 */ struct key * thread_keyring; /* 392 4 */ unsigned char jit_keyring; /* 396 1 */ unsigned char fpu_counter; /* 397 1 */ /* XXX 2 bytes hole, try to pack */ int oomkilladj; /* 400 4 */ char comm[16]; /* 404 16 */ /* --- cacheline 13 boundary (416 bytes) was 4 bytes ago --- */ int link_count; /* 420 4 */ int total_link_count; /* 424 4 */ struct sysv_sem sysvsem; /* 428 4 */ struct thread_struct thread; /* 432 656 */ /* --- cacheline 34 boundary (1088 bytes) --- */ struct fs_struct * fs; /* 1088 4 */ struct files_struct * files; /* 1092 4 */ struct nsproxy * nsproxy; /* 1096 4 */ struct signal_struct * signal; /* 1100 4 */ struct sighand_struct * sighand; /* 1104 4 */ sigset_t blocked; /* 1108 8 */ sigset_t real_blocked; /* 1116 8 */ /* --- cacheline 35 boundary (1120 bytes) was 4 bytes ago --- */ sigset_t saved_sigmask; /* 1124 8 */ struct sigpending pending; /* 1132 16 */ long unsigned int sas_ss_sp; /* 1148 4 */ /* --- cacheline 36 boundary (1152 bytes) --- */ size_t sas_ss_size; /* 1152 4 */ int (*notifier)(); /* 1156 4 */ void * notifier_data; /* 1160 4 */ sigset_t * notifier_mask; /* 1164 4 */ void * security; /* 1168 4 */ struct audit_context * audit_context; /* 1172 4 */ seccomp_t seccomp; /* 1176 0 */ u32 parent_exec_id; /* 1176 4 */ u32 self_exec_id; /* 1180 4 */ /* --- cacheline 37 boundary (1184 bytes) --- */ spinlock_t alloc_lock; /* 1184 40 */ /* --- cacheline 38 boundary (1216 bytes) was 8 bytes ago --- */ spinlock_t pi_lock; /* 1224 40 */ /* --- cacheline 39 boundary (1248 bytes) was 16 bytes ago --- */ struct plist_head pi_waiters; /* 1264 20 */ /* --- cacheline 40 boundary (1280 bytes) was 4 bytes ago --- */ struct rt_mutex_waiter * pi_blocked_on; /* 1284 4 */ struct mutex_waiter * blocked_on; /* 1288 4 */ unsigned int irq_events; /* 1292 4 */ int hardirqs_enabled; /* 1296 4 */ long unsigned int hardirq_enable_ip; /* 1300 4 */ unsigned int hardirq_enable_event; /* 1304 4 */ long unsigned int hardirq_disable_ip; /* 1308 4 */ /* --- cacheline 41 boundary (1312 bytes) --- */ unsigned int hardirq_disable_event; /* 1312 4 */ int softirqs_enabled; /* 1316 4 */ long unsigned int softirq_disable_ip; /* 1320 4 */ unsigned int softirq_disable_event; /* 1324 4 */ long unsigned int softirq_enable_ip; /* 1328 4 */ unsigned int softirq_enable_event; /* 1332 4 */ int hardirq_context; /* 1336 4 */ int softirq_context; /* 1340 4 */ /* --- cacheline 42 boundary (1344 bytes) --- */ u64 curr_chain_key; /* 1344 8 */ int lockdep_depth; /* 1352 4 */ struct held_lock held_locks[30]; /* 1356 1200 */ /* --- cacheline 79 boundary (2528 bytes) was 28 bytes ago --- */ unsigned int lockdep_recursion; /* 2556 4 */ /* --- cacheline 80 boundary (2560 bytes) --- */ void * journal_info; /* 2560 4 */ struct reclaim_state * reclaim_state; /* 2564 4 */ struct backing_dev_info * backing_dev_info; /* 2568 4 */ struct io_context * io_context; /* 2572 4 */ long unsigned int ptrace_message; /* 2576 4 */ siginfo_t * last_siginfo; /* 2580 4 */ wait_queue_t * io_wait; /* 2584 4 */ u64 rchar; /* 2588 8 */ /* --- cacheline 81 boundary (2592 bytes) was 4 bytes ago --- */ u64 wchar; /* 2596 8 */ u64 syscr; /* 2604 8 */ u64 syscw; /* 2612 8 */ struct robust_list_head * robust_list; /* 2620 4 */ /* --- cacheline 82 boundary (2624 bytes) --- */ struct list_head pi_state_list; /* 2624 8 */ struct futex_pi_state * pi_state_cache; /* 2632 4 */ atomic_t fs_excl; /* 2636 4 */ struct rcu_head rcu; /* 2640 8 */ struct pipe_inode_info * splice_pipe; /* 2648 4 */ }; /* size: 2656, cachelines: 83 */ /* sum members: 2648, holes: 2, sum holes: 4 */ /* bit holes: 2, sum bit holes: 62 bits */ /* padding: 4 */ Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-07 15:26:50 +01:00
if (last->bit_size != 0)
self->bit_padding = (last_size * 8) - bit_sum;
} else
self->padding = ctype->size;
}
[LIB]: Introduce class__has_hole_ge() That returns if the class has a hole greater or equal to the size specified. Pahole now has a --hole_size_ge command line option to use it. Example on a linux kernel built for x86_64 where we list the structs that have holes bigger than 32 bytes, that provides an approximation of structs with ____cacheline_aligned_in_smp annotated members: [acme@filo pahole]$ pahole --hole_size_ge 32 examples/vmlinux-x86_64 inet_hashinfo rcu_ctrlblk hh_cache net_device files_struct module zone For instance, look at struct zone clever use of such construct: _pad1_ is defined with ZONE_PADDING(_pad1_), that is: /* <40e> /home/acme/git/net-2.6.22/include/linux/mmzone.h:179 */ struct zone { long unsigned int pages_min; /* 0 8 */ long unsigned int pages_low; /* 8 8 */ long unsigned int pages_high; /* 16 8 */ long unsigned int lowmem_reserve[3]; /* 24 24 */ int node; /* 48 4 */ /* XXX 4 bytes hole, try to pack */ long unsigned int min_unmapped_pages; /* 56 8 */ /* --- cacheline 1 boundary (64 bytes) --- */ long unsigned int min_slab_pages; /* 64 8 */ struct per_cpu_pageset * pageset[255]; /* 72 2040 */ /* --- cacheline 33 boundary (2112 bytes) --- */ spinlock_t lock; /* 2112 4 */ /* XXX 4 bytes hole, try to pack */ struct free_area free_area[11]; /* 2120 264 */ /* XXX 48 bytes hole, try to pack */ /* --- cacheline 38 boundary (2432 bytes) --- */ struct zone_padding _pad1_; /* 2432 0 */ spinlock_t lru_lock; /* 2432 4 */ /* XXX 4 bytes hole, try to pack */ struct list_head active_list; /* 2440 16 */ struct list_head inactive_list; /* 2456 16 */ long unsigned int nr_scan_active; /* 2472 8 */ long unsigned int nr_scan_inactive; /* 2480 8 */ long unsigned int pages_scanned; /* 2488 8 */ /* --- cacheline 39 boundary (2496 bytes) --- */ int all_unreclaimable; /* 2496 4 */ atomic_t reclaim_in_progress; /* 2500 4 */ atomic_long_t vm_stat[20]; /* 2504 160 */ /* --- cacheline 41 boundary (2624 bytes) was 40 bytes ago --- */ int prev_priority; /* 2664 4 */ /* XXX 20 bytes hole, try to pack */ /* --- cacheline 42 boundary (2688 bytes) --- */ struct zone_padding _pad2_; /* 2688 0 */ wait_queue_head_t * wait_table; /* 2688 8 */ long unsigned int wait_table_hash_nr_entries; /* 2696 8 */ long unsigned int wait_table_bits; /* 2704 8 */ struct pglist_data * zone_pgdat; /* 2712 8 */ long unsigned int zone_start_pfn; /* 2720 8 */ long unsigned int spanned_pages; /* 2728 8 */ long unsigned int present_pages; /* 2736 8 */ const char * name; /* 2744 8 */ /* --- cacheline 43 boundary (2752 bytes) --- */ }; /* size: 2752, cachelines: 43 */ /* sum members: 2672, holes: 5, sum holes: 80 */ /* definitions: 933 */ Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-05-11 18:32:53 +02:00
/** class__has_hole_ge - check if class has a hole greater or equal to @size
* @self - class instance
* @size - hole size to check
*/
int class__has_hole_ge(const struct class *self, const uint16_t size)
{
struct class_member *pos;
if (self->nr_holes == 0)
return 0;
type__for_each_data_member(&self->type, pos)
[LIB]: Introduce class__has_hole_ge() That returns if the class has a hole greater or equal to the size specified. Pahole now has a --hole_size_ge command line option to use it. Example on a linux kernel built for x86_64 where we list the structs that have holes bigger than 32 bytes, that provides an approximation of structs with ____cacheline_aligned_in_smp annotated members: [acme@filo pahole]$ pahole --hole_size_ge 32 examples/vmlinux-x86_64 inet_hashinfo rcu_ctrlblk hh_cache net_device files_struct module zone For instance, look at struct zone clever use of such construct: _pad1_ is defined with ZONE_PADDING(_pad1_), that is: /* <40e> /home/acme/git/net-2.6.22/include/linux/mmzone.h:179 */ struct zone { long unsigned int pages_min; /* 0 8 */ long unsigned int pages_low; /* 8 8 */ long unsigned int pages_high; /* 16 8 */ long unsigned int lowmem_reserve[3]; /* 24 24 */ int node; /* 48 4 */ /* XXX 4 bytes hole, try to pack */ long unsigned int min_unmapped_pages; /* 56 8 */ /* --- cacheline 1 boundary (64 bytes) --- */ long unsigned int min_slab_pages; /* 64 8 */ struct per_cpu_pageset * pageset[255]; /* 72 2040 */ /* --- cacheline 33 boundary (2112 bytes) --- */ spinlock_t lock; /* 2112 4 */ /* XXX 4 bytes hole, try to pack */ struct free_area free_area[11]; /* 2120 264 */ /* XXX 48 bytes hole, try to pack */ /* --- cacheline 38 boundary (2432 bytes) --- */ struct zone_padding _pad1_; /* 2432 0 */ spinlock_t lru_lock; /* 2432 4 */ /* XXX 4 bytes hole, try to pack */ struct list_head active_list; /* 2440 16 */ struct list_head inactive_list; /* 2456 16 */ long unsigned int nr_scan_active; /* 2472 8 */ long unsigned int nr_scan_inactive; /* 2480 8 */ long unsigned int pages_scanned; /* 2488 8 */ /* --- cacheline 39 boundary (2496 bytes) --- */ int all_unreclaimable; /* 2496 4 */ atomic_t reclaim_in_progress; /* 2500 4 */ atomic_long_t vm_stat[20]; /* 2504 160 */ /* --- cacheline 41 boundary (2624 bytes) was 40 bytes ago --- */ int prev_priority; /* 2664 4 */ /* XXX 20 bytes hole, try to pack */ /* --- cacheline 42 boundary (2688 bytes) --- */ struct zone_padding _pad2_; /* 2688 0 */ wait_queue_head_t * wait_table; /* 2688 8 */ long unsigned int wait_table_hash_nr_entries; /* 2696 8 */ long unsigned int wait_table_bits; /* 2704 8 */ struct pglist_data * zone_pgdat; /* 2712 8 */ long unsigned int zone_start_pfn; /* 2720 8 */ long unsigned int spanned_pages; /* 2728 8 */ long unsigned int present_pages; /* 2736 8 */ const char * name; /* 2744 8 */ /* --- cacheline 43 boundary (2752 bytes) --- */ }; /* size: 2752, cachelines: 43 */ /* sum members: 2672, holes: 5, sum holes: 80 */ /* definitions: 933 */ Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-05-11 18:32:53 +02:00
if (pos->hole >= size)
return 1;
return 0;
}
struct class_member *type__find_member_by_name(const struct type *self,
const char *name)
[CODIFF]: Detect and print all sorts of changes in structs [acme@newtoy examples]$ cat struct.c static struct foo { char a:2; unsigned int b; unsigned long c; unsigned long d; unsigned long e; } bar; int main(int argc, char *argv[]) { printf("%d", bar.a); } [acme@newtoy examples]$ Then change "a:2" to "a:4": [acme@newtoy examples]$ codiff -V old_struct new_struct struct.c: struct foo | +0 a:2; from: char /* 0(6) 1(2) */ to: char /* 0(4) 1(4) */ 1 struct changed Now, on top of that move a after b: [acme@newtoy examples]$ codiff -V old_struct new_struct struct.c: struct foo | +0 a:2; from: char /* 0(6) 1(2) */ to: char /* 4(4) 1(4) */ b; from: unsigned int /* 4(0) 4(0) */ to: unsigned int /* 0(0) 4(0) */ 1 struct changed [acme@newtoy examples]$ Move it back a to before b and change the type of e without changing its size, i.e. from unsigned long to long: [acme@newtoy examples]$ codiff -V old_struct new_struct struct.c: struct foo | +0 a:2; from: char /* 0(6) 1(2) */ to: char /* 0(4) 1(4) */ e; from: long unsigned int /* 16(0) 4(0) */ to: long int /* 16(0) 4(0) */ 1 struct changed [acme@newtoy examples]$ Now on top of this lets delete the c member: [acme@newtoy examples]$ codiff -V old_struct new_struct struct.c: struct foo | -4 nr_members: -1 -long unsigned int c; /* 8 4 */ a:2; from: char /* 0(6) 1(2) */ to: char /* 0(4) 1(4) */ d; from: long unsigned int /* 12(0) 4(0) */ to: long unsigned int /* 8(0) 4(0) */ e; from: long unsigned int /* 16(0) 4(0) */ to: long int /* 12(0) 4(0) */ 1 struct changed [acme@newtoy examples]$ WOW, many changes, what an ABI breakage, no? :-) It started as: [acme@newtoy examples]$ pahole old_struct foo /* /home/acme/pahole/examples/struct.c:3 */ struct foo { char a:2; /* 0 1 */ /* XXX 3 bytes hole, try to pack */ unsigned int b; /* 4 4 */ long unsigned int c; /* 8 4 */ long unsigned int d; /* 12 4 */ long unsigned int e; /* 16 4 */ }; /* size: 20, sum members: 17, holes: 1, sum holes: 3 */ And ended up as: [acme@newtoy examples]$ pahole new_struct foo /* /home/acme/pahole/examples/struct.c:3 */ struct foo { char a:4; /* 0 1 */ /* XXX 3 bytes hole, try to pack */ unsigned int b; /* 4 4 */ long unsigned int d; /* 8 4 */ long int e; /* 12 4 */ }; /* size: 16, sum members: 13, holes: 1, sum holes: 3 */ [acme@newtoy examples]$ Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 18:07:21 +01:00
{
if (name != NULL) {
struct class_member *pos;
type__for_each_data_member(self, pos)
if (pos->name != NULL && strcmp(pos->name, name) == 0)
return pos;
}
[CODIFF]: Detect and print all sorts of changes in structs [acme@newtoy examples]$ cat struct.c static struct foo { char a:2; unsigned int b; unsigned long c; unsigned long d; unsigned long e; } bar; int main(int argc, char *argv[]) { printf("%d", bar.a); } [acme@newtoy examples]$ Then change "a:2" to "a:4": [acme@newtoy examples]$ codiff -V old_struct new_struct struct.c: struct foo | +0 a:2; from: char /* 0(6) 1(2) */ to: char /* 0(4) 1(4) */ 1 struct changed Now, on top of that move a after b: [acme@newtoy examples]$ codiff -V old_struct new_struct struct.c: struct foo | +0 a:2; from: char /* 0(6) 1(2) */ to: char /* 4(4) 1(4) */ b; from: unsigned int /* 4(0) 4(0) */ to: unsigned int /* 0(0) 4(0) */ 1 struct changed [acme@newtoy examples]$ Move it back a to before b and change the type of e without changing its size, i.e. from unsigned long to long: [acme@newtoy examples]$ codiff -V old_struct new_struct struct.c: struct foo | +0 a:2; from: char /* 0(6) 1(2) */ to: char /* 0(4) 1(4) */ e; from: long unsigned int /* 16(0) 4(0) */ to: long int /* 16(0) 4(0) */ 1 struct changed [acme@newtoy examples]$ Now on top of this lets delete the c member: [acme@newtoy examples]$ codiff -V old_struct new_struct struct.c: struct foo | -4 nr_members: -1 -long unsigned int c; /* 8 4 */ a:2; from: char /* 0(6) 1(2) */ to: char /* 0(4) 1(4) */ d; from: long unsigned int /* 12(0) 4(0) */ to: long unsigned int /* 8(0) 4(0) */ e; from: long unsigned int /* 16(0) 4(0) */ to: long int /* 12(0) 4(0) */ 1 struct changed [acme@newtoy examples]$ WOW, many changes, what an ABI breakage, no? :-) It started as: [acme@newtoy examples]$ pahole old_struct foo /* /home/acme/pahole/examples/struct.c:3 */ struct foo { char a:2; /* 0 1 */ /* XXX 3 bytes hole, try to pack */ unsigned int b; /* 4 4 */ long unsigned int c; /* 8 4 */ long unsigned int d; /* 12 4 */ long unsigned int e; /* 16 4 */ }; /* size: 20, sum members: 17, holes: 1, sum holes: 3 */ And ended up as: [acme@newtoy examples]$ pahole new_struct foo /* /home/acme/pahole/examples/struct.c:3 */ struct foo { char a:4; /* 0 1 */ /* XXX 3 bytes hole, try to pack */ unsigned int b; /* 4 4 */ long unsigned int d; /* 8 4 */ long int e; /* 12 4 */ }; /* size: 16, sum members: 13, holes: 1, sum holes: 3 */ [acme@newtoy examples]$ Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 18:07:21 +01:00
return NULL;
}
uint32_t type__nr_members_of_type(const struct type *self, const Dwarf_Off type)
{
struct class_member *pos;
uint32_t nr_members_of_type = 0;
type__for_each_member(self, pos)
if (pos->tag.type == type)
++nr_members_of_type;
return nr_members_of_type;
}
static void lexblock__account_inline_expansions(struct lexblock *self,
const struct cu *cu)
{
struct tag *pos, *type;
if (self->nr_inline_expansions == 0)
return;
list_for_each_entry(pos, &self->tags, node) {
if (pos->tag == DW_TAG_lexical_block) {
lexblock__account_inline_expansions(tag__lexblock(pos),
cu);
continue;
} else if (pos->tag != DW_TAG_inlined_subroutine)
continue;
type = cu__find_tag_by_id(cu, pos->type);
if (type != NULL) {
struct function *ftype = tag__function(type);
ftype->cu_total_nr_inline_expansions++;
ftype->cu_total_size_inline_expansions +=
tag__inline_expansion(pos)->size;
}
}
}
void cu__account_inline_expansions(struct cu *self)
{
struct tag *pos;
struct function *fpos;
list_for_each_entry(pos, &self->tags, node) {
if (pos->tag != DW_TAG_subprogram)
continue;
fpos = tag__function(pos);
lexblock__account_inline_expansions(&fpos->lexblock, self);
self->nr_inline_expansions += fpos->lexblock.nr_inline_expansions;
self->size_inline_expansions += fpos->lexblock.size_inline_expansions;
}
}
static size_t ftype__fprintf_parms(const struct ftype *self,
const struct cu *cu, int indent,
FILE *fp)
{
struct parameter *pos;
int first_parm = 1;
char sbf[128];
struct tag *type;
const char *name, *stype;
size_t printed = fprintf(fp, "(");
ftype__for_each_parameter(self, pos) {
if (!first_parm) {
if (indent == 0)
printed += fprintf(fp, ", ");
else
printed += fprintf(fp, ",\n%.*s",
indent, tabs);
} else
first_parm = 0;
name = parameter__name(pos, cu);
type = cu__find_tag_by_id(cu, parameter__type(pos, cu));
if (type == NULL) {
stype = "<ERROR>";
goto print_it;
}
if (type->tag == DW_TAG_pointer_type) {
if (type->type != 0) {
struct tag *ptype =
cu__find_tag_by_id(cu, type->type);
if (ptype == NULL) {
printed += fprintf(fp, ">>>ERROR: type "
"for %s not found!",
name);
continue;
}
if (ptype->tag == DW_TAG_subroutine_type) {
printed +=
ftype__fprintf(tag__ftype(ptype),
cu, name, 0, 1, 0,
fp);
continue;
}
}
} else if (type->tag == DW_TAG_subroutine_type) {
printed += ftype__fprintf(tag__ftype(type), cu, name,
0, 0, 0, fp);
continue;
}
print_it:
stype = tag__name(type, cu, sbf, sizeof(sbf));
printed += fprintf(fp, "%s%s%s", stype, name ? " " : "",
name ?: "");
}
/* No parameters? */
if (first_parm)
printed += fprintf(fp, "void)");
else if (self->unspec_parms)
printed += fprintf(fp, ", ...)");
else
printed += fprintf(fp, ")");
return printed;
}
static size_t function__tag_fprintf(const struct tag *tag, const struct cu *cu,
struct function *function,
uint16_t indent, FILE *fp)
{
char bf[512];
size_t printed = 0, n;
const void *vtag = tag;
int c;
if (indent >= sizeof(tabs))
indent = sizeof(tabs) - 1;
c = indent * 8;
switch (tag->tag) {
case DW_TAG_inlined_subroutine: {
const struct inline_expansion *exp = vtag;
const struct tag *talias =
cu__find_tag_by_id(cu, exp->tag.type);
struct function *alias = tag__function(talias);
const char *name;
if (alias == NULL) {
tag__type_not_found(&exp->tag);
break;
}
printed = fprintf(fp, "%.*s", indent, tabs);
name = function__name(alias, cu);
n = fprintf(fp, "%s", name);
n += ftype__fprintf_parms(&alias->proto, cu,
indent + (strlen(name) + 7) / 8,
fp);
n += fprintf(fp, "; /* size=%zd, low_pc=%#llx */",
exp->size, (unsigned long long)exp->low_pc);
#if 0
n = fprintf(fp, "%s(); /* size=%zd, low_pc=%#llx */",
function__name(alias, cu), exp->size,
(unsigned long long)exp->low_pc);
#endif
c = 69;
printed += n;
}
break;
case DW_TAG_variable:
printed = fprintf(fp, "%.*s", indent, tabs);
n = fprintf(fp, "%s %s;",
variable__type_name(vtag, cu, bf, sizeof(bf)),
variable__name(vtag, cu));
c += n;
printed += n;
break;
case DW_TAG_label: {
const struct label *label = vtag;
printed = fprintf(fp, "%.*s", indent, tabs);
fputc('\n', fp);
++printed;
c = fprintf(fp, "%s:", label->name);
printed += c;
[CLASSES]: Add support for DW_TAG_inlined_subroutine Output of pfunct using this information (all for a make allyesconfig build): Top 5 functions by size of inlined functions in net/ipv4: [acme@newtoy guinea_pig-2.6]$ pfunct -I net/ipv4/built-in.o | sort -k3 -nr | head -5 ip_route_input: 19 7086 tcp_ack: 33 6415 do_ip_vs_set_ctl: 23 4193 q931_help: 8 3822 ip_defrag: 19 3318 [acme@newtoy guinea_pig-2.6]$ And by number of inline expansions: [acme@newtoy guinea_pig-2.6]$ pfunct -I net/ipv4/built-in.o | sort -k2 -nr | head -5 dump_packet: 35 905 tcp_v4_rcv: 34 1773 tcp_recvmsg: 34 928 tcp_ack: 33 6415 tcp_rcv_established: 31 1195 [acme@newtoy guinea_pig-2.6]$ And the list of expansions on a specific function: [acme@newtoy guinea_pig-2.6]$ pfunct -i net/ipv4/built-in.o tcp_v4_rcv /* net/ipv4/tcp_ipv4.c:1054 */ int tcp_v4_rcv(struct sk_buff * skb); /* size: 2189, variables: 8, goto labels: 6, inline expansions: 34 (1773 bytes) */ /* inline expansions in tcp_v4_rcv: current_thread_info: 8 pskb_may_pull: 36 pskb_may_pull: 29 tcp_v4_checksum_init: 139 __fswab32: 2 __fswab32: 2 inet_iif: 12 __inet_lookup: 292 __fswab16: 20 inet_ehashfn: 25 inet_ehash_bucket: 18 prefetch: 4 prefetch: 4 prefetch: 4 sock_hold: 4 xfrm4_policy_check: 59 nf_reset: 66 sk_filter: 135 __skb_trim: 20 get_softnet_dma: 68 tcp_prequeue: 257 sk_add_backlog: 40 sock_put: 27 xfrm4_policy_check: 46 tcp_checksum_complete: 29 current_thread_info: 8 sock_put: 20 xfrm4_policy_check: 50 tcp_checksum_complete: 29 current_thread_info: 8 inet_iif: 9 inet_lookup_listener: 36 inet_twsk_put: 114 tcp_v4_timewait_ack: 153 */ [acme@newtoy guinea_pig-2.6]$ Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-03 16:41:19 +01:00
}
break;
case DW_TAG_lexical_block:
printed = lexblock__fprintf(vtag, cu, function, indent, fp);
fputc('\n', fp);
return printed + 1;
default:
printed = fprintf(fp, "%.*s", indent, tabs);
n = fprintf(fp, "%s <%llx>", dwarf_tag_name(tag->tag),
(unsigned long long)tag->id);
c += n;
printed += n;
break;
}
return printed + fprintf(fp, "%-*.*s// %5u\n", 70 - c, 70 - c, " ",
tag->decl_line);
[CLASSES]: Add support for DW_TAG_inlined_subroutine Output of pfunct using this information (all for a make allyesconfig build): Top 5 functions by size of inlined functions in net/ipv4: [acme@newtoy guinea_pig-2.6]$ pfunct -I net/ipv4/built-in.o | sort -k3 -nr | head -5 ip_route_input: 19 7086 tcp_ack: 33 6415 do_ip_vs_set_ctl: 23 4193 q931_help: 8 3822 ip_defrag: 19 3318 [acme@newtoy guinea_pig-2.6]$ And by number of inline expansions: [acme@newtoy guinea_pig-2.6]$ pfunct -I net/ipv4/built-in.o | sort -k2 -nr | head -5 dump_packet: 35 905 tcp_v4_rcv: 34 1773 tcp_recvmsg: 34 928 tcp_ack: 33 6415 tcp_rcv_established: 31 1195 [acme@newtoy guinea_pig-2.6]$ And the list of expansions on a specific function: [acme@newtoy guinea_pig-2.6]$ pfunct -i net/ipv4/built-in.o tcp_v4_rcv /* net/ipv4/tcp_ipv4.c:1054 */ int tcp_v4_rcv(struct sk_buff * skb); /* size: 2189, variables: 8, goto labels: 6, inline expansions: 34 (1773 bytes) */ /* inline expansions in tcp_v4_rcv: current_thread_info: 8 pskb_may_pull: 36 pskb_may_pull: 29 tcp_v4_checksum_init: 139 __fswab32: 2 __fswab32: 2 inet_iif: 12 __inet_lookup: 292 __fswab16: 20 inet_ehashfn: 25 inet_ehash_bucket: 18 prefetch: 4 prefetch: 4 prefetch: 4 sock_hold: 4 xfrm4_policy_check: 59 nf_reset: 66 sk_filter: 135 __skb_trim: 20 get_softnet_dma: 68 tcp_prequeue: 257 sk_add_backlog: 40 sock_put: 27 xfrm4_policy_check: 46 tcp_checksum_complete: 29 current_thread_info: 8 sock_put: 20 xfrm4_policy_check: 50 tcp_checksum_complete: 29 current_thread_info: 8 inet_iif: 9 inet_lookup_listener: 36 inet_twsk_put: 114 tcp_v4_timewait_ack: 153 */ [acme@newtoy guinea_pig-2.6]$ Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-03 16:41:19 +01:00
}
size_t lexblock__fprintf(const struct lexblock *self, const struct cu *cu,
struct function *function, uint16_t indent, FILE *fp)
{
struct tag *pos;
size_t printed;
if (indent >= sizeof(tabs))
indent = sizeof(tabs) - 1;
printed = fprintf(fp, "%.*s{", indent, tabs);
if (self->low_pc != 0) {
Dwarf_Off offset = self->low_pc - function->lexblock.low_pc;
if (offset == 0)
printed += fprintf(fp, " /* low_pc=%#llx */",
(unsigned long long)self->low_pc);
else
printed += fprintf(fp, " /* %s+%#llx */",
function__name(function, cu),
(unsigned long long)offset);
}
printed += fprintf(fp, "\n");
list_for_each_entry(pos, &self->tags, node)
printed += function__tag_fprintf(pos, cu, function, indent + 1, fp);
printed += fprintf(fp, "%.*s}", indent, tabs);
if (function->lexblock.low_pc != self->low_pc) {
const size_t size = self->high_pc - self->low_pc;
printed += fprintf(fp, " /* lexblock size=%zd */", size);
}
return printed;
}
size_t ftype__fprintf(const struct ftype *self, const struct cu *cu,
const char *name, const int inlined,
const int is_pointer, int type_spacing, FILE *fp)
{
struct tag *type = cu__find_tag_by_id(cu, self->tag.type);
char sbf[128];
const char *stype = tag__name(type, cu, sbf, sizeof(sbf));
size_t printed = fprintf(fp, "%s%-*s %s%s%s%s",
inlined ? "inline " : "",
type_spacing, stype,
self->tag.tag == DW_TAG_subroutine_type ?
"(" : "",
is_pointer ? "*" : "", name ?: "",
self->tag.tag == DW_TAG_subroutine_type ?
")" : "");
return printed + ftype__fprintf_parms(self, cu, 0, fp);
}
static size_t function__fprintf(const struct tag *tag_self,
const struct cu *cu, FILE *fp)
{
struct function *self = tag__function(tag_self);
size_t printed = 0;
if (self->virtuality == DW_VIRTUALITY_virtual ||
self->virtuality == DW_VIRTUALITY_pure_virtual)
printed += fprintf(fp, "virtual ");
printed += ftype__fprintf(&self->proto, cu, function__name(self, cu),
function__declared_inline(self), 0, 0, fp);
if (self->virtuality == DW_VIRTUALITY_pure_virtual)
printed += fprintf(fp, " = 0");
return printed;
}
size_t function__fprintf_stats(const struct tag *tag_self,
const struct cu *cu, FILE *fp)
{
struct function *self = tag__function(tag_self);
size_t printed = lexblock__fprintf(&self->lexblock, cu, self, 0, fp);
printed += fprintf(fp, "/* size: %zd", function__size(self));
if (self->lexblock.nr_variables > 0)
printed += fprintf(fp, ", variables: %u",
self->lexblock.nr_variables);
if (self->lexblock.nr_labels > 0)
printed += fprintf(fp, ", goto labels: %u",
self->lexblock.nr_labels);
if (self->lexblock.nr_inline_expansions > 0)
printed += fprintf(fp, ", inline expansions: %u (%zd bytes)",
self->lexblock.nr_inline_expansions,
self->lexblock.size_inline_expansions);
return printed + fprintf(fp, " */\n");
}
static size_t class__fprintf_cacheline_boundary(uint32_t last_cacheline,
size_t sum, size_t sum_holes,
uint8_t *newline,
uint32_t *cacheline,
int indent, FILE *fp)
{
const size_t real_sum = sum + sum_holes;
size_t printed = 0;
*cacheline = real_sum / cacheline_size;
if (*cacheline > last_cacheline) {
const uint32_t cacheline_pos = real_sum % cacheline_size;
const uint32_t cacheline_in_bytes = real_sum - cacheline_pos;
if (*newline) {
fputc('\n', fp);
*newline = 0;
++printed;
}
printed += fprintf(fp, "%.*s", indent, tabs);
[CLASSES]: Fully support nested classes Example: [acme@newtoy pahole]$ pahole net/ipv4/tcp.o flowi /* include/net/flow.h:13 */ struct flowi { int oif; /* 0 4 */ int iif; /* 4 4 */ __u32 mark; /* 8 4 */ union { struct { __be32 daddr; /* 0 4 */ __be32 saddr; /* 4 4 */ __u8 tos; /* 8 1 */ __u8 scope; /* 9 1 */ } ip4_u; /* 12 */ struct { struct in6_addr daddr; /* 0 16 */ struct in6_addr saddr; /* 16 16 */ /* --- cacheline 1 boundary (32 bytes) --- */ __be32 flowlabel; /* 32 4 */ } ip6_u; /* 36 */ struct { __le16 daddr; /* 0 2 */ __le16 saddr; /* 2 2 */ __u8 scope; /* 4 1 */ } dn_u; /* 6 */ } nl_u; /* 12 36 */ /* --- cacheline 1 boundary (32 bytes) was 16 bytes ago --- */ __u8 proto; /* 48 1 */ __u8 flags; /* 49 1 */ /* XXX 2 bytes hole, try to pack */ union { struct { __be16 sport; /* 0 2 */ __be16 dport; /* 2 2 */ } ports; /* 4 */ struct { __u8 type; /* 0 1 */ __u8 code; /* 1 1 */ } icmpt; /* 2 */ struct { __le16 sport; /* 0 2 */ __le16 dport; /* 2 2 */ } dnports; /* 4 */ __be32 spi; /* 4 */ } uli_u; /* 52 4 */ __u32 secid; /* 56 4 */ }; /* size: 60, cachelines: 2 */ /* sum members: 58, holes: 1, sum holes: 2 */ /* last cacheline: 28 bytes */ Supporting anonymous structs and unions just fine, even combinations of both, like in struct page, in the Linux kernel: [acme@newtoy pahole]$ pahole mm/mmap.o page /* include/linux/mmzone.h:391 */ struct page { long unsigned int flags; /* 0 4 */ atomic_t _count; /* 4 4 */ atomic_t _mapcount; /* 8 4 */ union { struct { long unsigned int private; /* 0 4 */ struct address_space * mapping; /* 4 4 */ }; /* 8 */ }; /* 12 8 */ long unsigned int index; /* 20 4 */ struct list_head lru; /* 24 8 */ /* --- cacheline 1 boundary (32 bytes) --- */ }; /* size: 32, cachelines: 1 */ Or struct freebsd_sys_getdents_args in the OpenBSD kernel: /* /usr/home/leonardo/openbsd/src/sys/compat/freebsd/freebsd_syscallargs.h:231 */ struct freebsd_sys_getdents_args { union { register_t pad; /* 4 */ struct { int datum; /* 0 4 */ } le; /* 4 */ struct { int8_t pad[0]; /* 0 0 */ int datum; /* 0 4 */ } be; /* 4 */ } fd; /* 0 4 */ union { register_t pad; /* 4 */ struct { void * datum; /* 0 4 */ } le; /* 4 */ struct { int8_t pad[0]; /* 0 0 */ void * datum; /* 0 4 */ } be; /* 4 */ } dirent; /* 4 4 */ union { register_t pad; /* 4 */ struct { unsigned int datum; /* 0 4 */ } le; /* 4 */ struct { int8_t pad[0]; /* 0 0 */ unsigned int datum; /* 0 4 */ } be; /* 4 */ } count; /* 8 4 */ }; /* size: 12, cachelines: 1 */ /* last cacheline: 12 bytes */ /* definitions: 7 */ One more from the OpenBSD kernel: /* /usr/home/leonardo/openbsd/src/sys/nfs/nfs.h:344 */ struct nfssvc_sock { struct { struct nfssvc_sock * tqe_next; /* 0 4 */ struct nfssvc_sock * * tqe_prev; /* 4 4 */ } ns_chain; /* 0 8 */ struct { struct nfsuid * tqh_first; /* 0 4 */ struct nfsuid * * tqh_last; /* 4 4 */ } ns_uidlruhead; /* 8 8 */ struct file * ns_fp; /* 16 4 */ struct socket * ns_so; /* 20 4 */ struct mbuf * ns_nam; /* 24 4 */ struct mbuf * ns_raw; /* 28 4 */ /* --- cacheline 1 boundary (32 bytes) --- */ struct mbuf * ns_rawend; /* 32 4 */ struct mbuf * ns_rec; /* 36 4 */ struct mbuf * ns_recend; /* 40 4 */ struct mbuf * ns_frag; /* 44 4 */ int ns_flag; /* 48 4 */ int ns_solock; /* 52 4 */ int ns_cc; /* 56 4 */ int ns_reclen; /* 60 4 */ /* --- cacheline 2 boundary (64 bytes) --- */ int ns_numuids; /* 64 4 */ u_int32_t ns_sref; /* 68 4 */ struct { struct nfsrv_descript * lh_first; /* 0 4 */ } ns_tq; /* 72 4 */ struct ns_uidhashtbl[29]; /* 76 116 */ /* --- cacheline 6 boundary (192 bytes) --- */ struct nfsrvw_delayhash ns_wdelayhashtbl[16]; /* 192 64 */ /* --- cacheline 8 boundary (256 bytes) --- */ }; /* size: 256, cachelines: 8 */ /* definitions: 12 */ Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 22:46:47 +01:00
if (cacheline_pos == 0)
printed += fprintf(fp, "/* --- cacheline %u boundary "
"(%u bytes) --- */\n", *cacheline,
cacheline_in_bytes);
else
printed += fprintf(fp, "/* --- cacheline %u boundary "
"(%u bytes) was %u bytes ago --- "
"*/\n", *cacheline,
cacheline_in_bytes, cacheline_pos);
}
return printed;
}
static size_t class__vtable_fprintf(struct class *self,
const struct conf_fprintf *conf, FILE *fp)
{
struct function *pos;
size_t printed = 0;
if (self->nr_vtable_entries == 0)
goto out;
printed += fprintf(fp, "%.*s/* vtable has %u entries: {\n",
conf->indent, tabs, self->nr_vtable_entries);
list_for_each_entry(pos, &self->vtable, vtable_node) {
printed += fprintf(fp, "%.*s [%d] = %s(%s), \n",
conf->indent, tabs, pos->vtable_entry,
pos->name, pos->linkage_name);
}
printed += fprintf(fp, "%.*s} */", conf->indent, tabs);
out:
return printed;
}
size_t class__fprintf(struct class *self, const struct cu *cu,
const struct conf_fprintf *conf, FILE *fp)
{
struct type *tself = &self->type;
size_t last_size = 0, size;
uint8_t newline = 0;
uint16_t nr_paddings = 0;
uint32_t sum = 0;
uint32_t sum_holes = 0;
uint32_t sum_paddings = 0;
uint32_t sum_bit_holes = 0;
uint32_t last_cacheline = 0;
uint32_t bitfield_real_offset = 0;
int first = 1;
struct class_member *pos, *last = NULL;
struct tag *tag_pos;
const char *current_accessibility = NULL;
struct conf_fprintf cconf = conf ? *conf : conf_fprintf__defaults;
size_t printed = fprintf(fp, "%s%sstruct%s%s",
cconf.prefix ?: "", cconf.prefix ? " " : "",
type__name(tself, cu) ? " " : "",
type__name(tself, cu) ?: "");
int indent = cconf.indent;
if (indent >= (int)sizeof(tabs))
indent = sizeof(tabs) - 1;
[CLASSES]: Fully support nested classes Example: [acme@newtoy pahole]$ pahole net/ipv4/tcp.o flowi /* include/net/flow.h:13 */ struct flowi { int oif; /* 0 4 */ int iif; /* 4 4 */ __u32 mark; /* 8 4 */ union { struct { __be32 daddr; /* 0 4 */ __be32 saddr; /* 4 4 */ __u8 tos; /* 8 1 */ __u8 scope; /* 9 1 */ } ip4_u; /* 12 */ struct { struct in6_addr daddr; /* 0 16 */ struct in6_addr saddr; /* 16 16 */ /* --- cacheline 1 boundary (32 bytes) --- */ __be32 flowlabel; /* 32 4 */ } ip6_u; /* 36 */ struct { __le16 daddr; /* 0 2 */ __le16 saddr; /* 2 2 */ __u8 scope; /* 4 1 */ } dn_u; /* 6 */ } nl_u; /* 12 36 */ /* --- cacheline 1 boundary (32 bytes) was 16 bytes ago --- */ __u8 proto; /* 48 1 */ __u8 flags; /* 49 1 */ /* XXX 2 bytes hole, try to pack */ union { struct { __be16 sport; /* 0 2 */ __be16 dport; /* 2 2 */ } ports; /* 4 */ struct { __u8 type; /* 0 1 */ __u8 code; /* 1 1 */ } icmpt; /* 2 */ struct { __le16 sport; /* 0 2 */ __le16 dport; /* 2 2 */ } dnports; /* 4 */ __be32 spi; /* 4 */ } uli_u; /* 52 4 */ __u32 secid; /* 56 4 */ }; /* size: 60, cachelines: 2 */ /* sum members: 58, holes: 1, sum holes: 2 */ /* last cacheline: 28 bytes */ Supporting anonymous structs and unions just fine, even combinations of both, like in struct page, in the Linux kernel: [acme@newtoy pahole]$ pahole mm/mmap.o page /* include/linux/mmzone.h:391 */ struct page { long unsigned int flags; /* 0 4 */ atomic_t _count; /* 4 4 */ atomic_t _mapcount; /* 8 4 */ union { struct { long unsigned int private; /* 0 4 */ struct address_space * mapping; /* 4 4 */ }; /* 8 */ }; /* 12 8 */ long unsigned int index; /* 20 4 */ struct list_head lru; /* 24 8 */ /* --- cacheline 1 boundary (32 bytes) --- */ }; /* size: 32, cachelines: 1 */ Or struct freebsd_sys_getdents_args in the OpenBSD kernel: /* /usr/home/leonardo/openbsd/src/sys/compat/freebsd/freebsd_syscallargs.h:231 */ struct freebsd_sys_getdents_args { union { register_t pad; /* 4 */ struct { int datum; /* 0 4 */ } le; /* 4 */ struct { int8_t pad[0]; /* 0 0 */ int datum; /* 0 4 */ } be; /* 4 */ } fd; /* 0 4 */ union { register_t pad; /* 4 */ struct { void * datum; /* 0 4 */ } le; /* 4 */ struct { int8_t pad[0]; /* 0 0 */ void * datum; /* 0 4 */ } be; /* 4 */ } dirent; /* 4 4 */ union { register_t pad; /* 4 */ struct { unsigned int datum; /* 0 4 */ } le; /* 4 */ struct { int8_t pad[0]; /* 0 0 */ unsigned int datum; /* 0 4 */ } be; /* 4 */ } count; /* 8 4 */ }; /* size: 12, cachelines: 1 */ /* last cacheline: 12 bytes */ /* definitions: 7 */ One more from the OpenBSD kernel: /* /usr/home/leonardo/openbsd/src/sys/nfs/nfs.h:344 */ struct nfssvc_sock { struct { struct nfssvc_sock * tqe_next; /* 0 4 */ struct nfssvc_sock * * tqe_prev; /* 4 4 */ } ns_chain; /* 0 8 */ struct { struct nfsuid * tqh_first; /* 0 4 */ struct nfsuid * * tqh_last; /* 4 4 */ } ns_uidlruhead; /* 8 8 */ struct file * ns_fp; /* 16 4 */ struct socket * ns_so; /* 20 4 */ struct mbuf * ns_nam; /* 24 4 */ struct mbuf * ns_raw; /* 28 4 */ /* --- cacheline 1 boundary (32 bytes) --- */ struct mbuf * ns_rawend; /* 32 4 */ struct mbuf * ns_rec; /* 36 4 */ struct mbuf * ns_recend; /* 40 4 */ struct mbuf * ns_frag; /* 44 4 */ int ns_flag; /* 48 4 */ int ns_solock; /* 52 4 */ int ns_cc; /* 56 4 */ int ns_reclen; /* 60 4 */ /* --- cacheline 2 boundary (64 bytes) --- */ int ns_numuids; /* 64 4 */ u_int32_t ns_sref; /* 68 4 */ struct { struct nfsrv_descript * lh_first; /* 0 4 */ } ns_tq; /* 72 4 */ struct ns_uidhashtbl[29]; /* 76 116 */ /* --- cacheline 6 boundary (192 bytes) --- */ struct nfsrvw_delayhash ns_wdelayhashtbl[16]; /* 192 64 */ /* --- cacheline 8 boundary (256 bytes) --- */ }; /* size: 256, cachelines: 8 */ /* definitions: 12 */ Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 22:46:47 +01:00
cconf.indent = indent + 1;
cconf.no_semicolon = 0;
/* First look if we have DW_TAG_inheritance */
type__for_each_tag(tself, tag_pos) {
struct tag *type;
const char *accessibility;
if (tag_pos->tag != DW_TAG_inheritance)
continue;
if (first) {
printed += fprintf(fp, " :");
first = 0;
} else
printed += fprintf(fp, ",");
pos = tag__class_member(tag_pos);
if (pos->virtuality == DW_VIRTUALITY_virtual)
printed += fprintf(fp, " virtual");
accessibility = tag__accessibility(tag_pos);
if (accessibility != NULL)
printed += fprintf(fp, " %s", accessibility);
type = cu__find_tag_by_id(cu, tag_pos->type);
if (type != NULL)
printed += fprintf(fp, " %s", type__name(tag__type(type), cu));
else
printed += fprintf(fp, " <ERROR: type %#llx not found!>",
(unsigned long long)tag_pos->type);
}
printed += fprintf(fp, " {\n");
type__for_each_tag(tself, tag_pos) {
[CLASSES]: Ditch class_member__names Was a awful function, to replace it added some new __snprintf methods for more classes (array_type, class_member, etc), the end result is a much nicer rendering, for instance: @@ -6549,11 +6549,11 @@ /* XXX 2 bytes hole, try to pack */ union { - struct ff_constant_effect constant; /* 10 */ - struct ff_ramp_effect ramp; /* 12 */ - struct ff_periodic_effect periodic; /* 28 */ - struct ff_condition_effect condition[2]; /* 24 */ - struct ff_rumble_effect rumble; /* 4 */ + struct ff_constant_effect constant; /* 10 */ + struct ff_ramp_effect ramp; /* 12 */ + struct ff_periodic_effect periodic; /* 28 */ + struct ff_condition_effect condition[2]; /* 24 */ + struct ff_rumble_effect rumble; /* 4 */ } u; /* 16 28 */ /* --- cacheline 1 boundary (32 bytes) was 12 bytes ago --- */ }; /* size: 44, cachelines: 2 */ Previously when such big class members appeared the comments with the size and offset were unaligned, now its only in extreme cases, such as the array above that things get unaligned. End result is a smaller library: [acme@newtoy pahole]$ codiff -V build/libclasses.so.orig build/libclasses.so /home/acme/pahole/classes.c: struct array_type | -4 nr_members: -1 -const char *name /* 36 4 */ 1 struct changed enumeration__print | +10 # 175 -> 185 union__snprintf | +32 # 576 -> 608 union__print | +16 # 182 -> 198 class_member__names | -851 (removed) class_member__print | -721 # 1218 -> 497 class__print_struct | +54 # 1403 -> 1457 6 functions changed, 112 bytes added, 1572 bytes removed, diff: -1460 /home/acme/pahole/classes.c: array_type__snprintf | +249 (added) class_member__snprintf | +892 (added) 2 functions changed, 1141 bytes added build/libclasses.so: 8 functions changed, 1253 bytes added, 1572 bytes removed, diff: -319 Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 17:19:55 +01:00
struct tag *type;
const char *accessibility = tag__accessibility(tag_pos);
if (accessibility != NULL &&
accessibility != current_accessibility) {
current_accessibility = accessibility;
printed += fprintf(fp, "%.*s%s:\n\n",
cconf.indent - 1, tabs,
accessibility);
}
if (tag_pos->tag != DW_TAG_member &&
tag_pos->tag != DW_TAG_inheritance) {
if (!cconf.show_only_data_members) {
printed += tag__fprintf(tag_pos, cu, &cconf, fp);
printed += fprintf(fp, "\n\n");
}
continue;
}
pos = tag__class_member(tag_pos);
if (last != NULL &&
pos->offset != last->offset &&
!cconf.suppress_comments)
printed +=
class__fprintf_cacheline_boundary(last_cacheline,
sum, sum_holes,
&newline,
&last_cacheline,
cconf.indent,
fp);
/*
* These paranoid checks doesn't make much sense on
* DW_TAG_inheritance, have to understand why virtual public
* ancestors make the offset go backwards...
*/
if (last != NULL && tag_pos->tag == DW_TAG_member) {
if (pos->offset < last->offset ||
(pos->offset == last->offset &&
last->bit_size == 0 &&
/*
* This is just when transitioning from a non-bitfield to
* a bitfield, think about zero sized arrays in the middle
* of a struct.
*/
pos->bit_size != 0)) {
if (!cconf.suppress_comments) {
if (!newline++) {
fputc('\n', fp);
++printed;
}
printed += fprintf(fp, "%.*s/* Bitfield combined"
" with previous fields */\n",
cconf.indent, tabs);
}
if (pos->offset != last->offset)
bitfield_real_offset = last->offset + last_size;
} else {
const ssize_t cc_last_size = ((ssize_t)pos->offset -
(ssize_t)last->offset);
if (cc_last_size > 0 &&
(size_t)cc_last_size < last_size) {
if (!cconf.suppress_comments) {
if (!newline++) {
fputc('\n', fp);
++printed;
}
printed += fprintf(fp, "%.*s/* Bitfield combined"
" with next fields */\n",
cconf.indent, tabs);
}
sum -= last_size;
sum += cc_last_size;
[CLASSES]: Fully support nested classes Example: [acme@newtoy pahole]$ pahole net/ipv4/tcp.o flowi /* include/net/flow.h:13 */ struct flowi { int oif; /* 0 4 */ int iif; /* 4 4 */ __u32 mark; /* 8 4 */ union { struct { __be32 daddr; /* 0 4 */ __be32 saddr; /* 4 4 */ __u8 tos; /* 8 1 */ __u8 scope; /* 9 1 */ } ip4_u; /* 12 */ struct { struct in6_addr daddr; /* 0 16 */ struct in6_addr saddr; /* 16 16 */ /* --- cacheline 1 boundary (32 bytes) --- */ __be32 flowlabel; /* 32 4 */ } ip6_u; /* 36 */ struct { __le16 daddr; /* 0 2 */ __le16 saddr; /* 2 2 */ __u8 scope; /* 4 1 */ } dn_u; /* 6 */ } nl_u; /* 12 36 */ /* --- cacheline 1 boundary (32 bytes) was 16 bytes ago --- */ __u8 proto; /* 48 1 */ __u8 flags; /* 49 1 */ /* XXX 2 bytes hole, try to pack */ union { struct { __be16 sport; /* 0 2 */ __be16 dport; /* 2 2 */ } ports; /* 4 */ struct { __u8 type; /* 0 1 */ __u8 code; /* 1 1 */ } icmpt; /* 2 */ struct { __le16 sport; /* 0 2 */ __le16 dport; /* 2 2 */ } dnports; /* 4 */ __be32 spi; /* 4 */ } uli_u; /* 52 4 */ __u32 secid; /* 56 4 */ }; /* size: 60, cachelines: 2 */ /* sum members: 58, holes: 1, sum holes: 2 */ /* last cacheline: 28 bytes */ Supporting anonymous structs and unions just fine, even combinations of both, like in struct page, in the Linux kernel: [acme@newtoy pahole]$ pahole mm/mmap.o page /* include/linux/mmzone.h:391 */ struct page { long unsigned int flags; /* 0 4 */ atomic_t _count; /* 4 4 */ atomic_t _mapcount; /* 8 4 */ union { struct { long unsigned int private; /* 0 4 */ struct address_space * mapping; /* 4 4 */ }; /* 8 */ }; /* 12 8 */ long unsigned int index; /* 20 4 */ struct list_head lru; /* 24 8 */ /* --- cacheline 1 boundary (32 bytes) --- */ }; /* size: 32, cachelines: 1 */ Or struct freebsd_sys_getdents_args in the OpenBSD kernel: /* /usr/home/leonardo/openbsd/src/sys/compat/freebsd/freebsd_syscallargs.h:231 */ struct freebsd_sys_getdents_args { union { register_t pad; /* 4 */ struct { int datum; /* 0 4 */ } le; /* 4 */ struct { int8_t pad[0]; /* 0 0 */ int datum; /* 0 4 */ } be; /* 4 */ } fd; /* 0 4 */ union { register_t pad; /* 4 */ struct { void * datum; /* 0 4 */ } le; /* 4 */ struct { int8_t pad[0]; /* 0 0 */ void * datum; /* 0 4 */ } be; /* 4 */ } dirent; /* 4 4 */ union { register_t pad; /* 4 */ struct { unsigned int datum; /* 0 4 */ } le; /* 4 */ struct { int8_t pad[0]; /* 0 0 */ unsigned int datum; /* 0 4 */ } be; /* 4 */ } count; /* 8 4 */ }; /* size: 12, cachelines: 1 */ /* last cacheline: 12 bytes */ /* definitions: 7 */ One more from the OpenBSD kernel: /* /usr/home/leonardo/openbsd/src/sys/nfs/nfs.h:344 */ struct nfssvc_sock { struct { struct nfssvc_sock * tqe_next; /* 0 4 */ struct nfssvc_sock * * tqe_prev; /* 4 4 */ } ns_chain; /* 0 8 */ struct { struct nfsuid * tqh_first; /* 0 4 */ struct nfsuid * * tqh_last; /* 4 4 */ } ns_uidlruhead; /* 8 8 */ struct file * ns_fp; /* 16 4 */ struct socket * ns_so; /* 20 4 */ struct mbuf * ns_nam; /* 24 4 */ struct mbuf * ns_raw; /* 28 4 */ /* --- cacheline 1 boundary (32 bytes) --- */ struct mbuf * ns_rawend; /* 32 4 */ struct mbuf * ns_rec; /* 36 4 */ struct mbuf * ns_recend; /* 40 4 */ struct mbuf * ns_frag; /* 44 4 */ int ns_flag; /* 48 4 */ int ns_solock; /* 52 4 */ int ns_cc; /* 56 4 */ int ns_reclen; /* 60 4 */ /* --- cacheline 2 boundary (64 bytes) --- */ int ns_numuids; /* 64 4 */ u_int32_t ns_sref; /* 68 4 */ struct { struct nfsrv_descript * lh_first; /* 0 4 */ } ns_tq; /* 72 4 */ struct ns_uidhashtbl[29]; /* 76 116 */ /* --- cacheline 6 boundary (192 bytes) --- */ struct nfsrvw_delayhash ns_wdelayhashtbl[16]; /* 192 64 */ /* --- cacheline 8 boundary (256 bytes) --- */ }; /* size: 256, cachelines: 8 */ /* definitions: 12 */ Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 22:46:47 +01:00
}
}
}
if (newline) {
fputc('\n', fp);
newline = 0;
++printed;
}
[CLASSES]: Ditch class_member__names Was a awful function, to replace it added some new __snprintf methods for more classes (array_type, class_member, etc), the end result is a much nicer rendering, for instance: @@ -6549,11 +6549,11 @@ /* XXX 2 bytes hole, try to pack */ union { - struct ff_constant_effect constant; /* 10 */ - struct ff_ramp_effect ramp; /* 12 */ - struct ff_periodic_effect periodic; /* 28 */ - struct ff_condition_effect condition[2]; /* 24 */ - struct ff_rumble_effect rumble; /* 4 */ + struct ff_constant_effect constant; /* 10 */ + struct ff_ramp_effect ramp; /* 12 */ + struct ff_periodic_effect periodic; /* 28 */ + struct ff_condition_effect condition[2]; /* 24 */ + struct ff_rumble_effect rumble; /* 4 */ } u; /* 16 28 */ /* --- cacheline 1 boundary (32 bytes) was 12 bytes ago --- */ }; /* size: 44, cachelines: 2 */ Previously when such big class members appeared the comments with the size and offset were unaligned, now its only in extreme cases, such as the array above that things get unaligned. End result is a smaller library: [acme@newtoy pahole]$ codiff -V build/libclasses.so.orig build/libclasses.so /home/acme/pahole/classes.c: struct array_type | -4 nr_members: -1 -const char *name /* 36 4 */ 1 struct changed enumeration__print | +10 # 175 -> 185 union__snprintf | +32 # 576 -> 608 union__print | +16 # 182 -> 198 class_member__names | -851 (removed) class_member__print | -721 # 1218 -> 497 class__print_struct | +54 # 1403 -> 1457 6 functions changed, 112 bytes added, 1572 bytes removed, diff: -1460 /home/acme/pahole/classes.c: array_type__snprintf | +249 (added) class_member__snprintf | +892 (added) 2 functions changed, 1141 bytes added build/libclasses.so: 8 functions changed, 1253 bytes added, 1572 bytes removed, diff: -319 Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 17:19:55 +01:00
type = cu__find_tag_by_id(cu, pos->tag.type);
if (type == NULL) {
tag__type_not_found(&pos->tag);
printed += fprintf(fp, "%.*s>>>ERROR: type(%#llx) for %s not "
"found!\n", cconf.indent, tabs,
(unsigned long long)pos->tag.type,
pos->name);
continue;
}
size = tag__size(type, cu);
printed += fprintf(fp, "%.*s", cconf.indent, tabs);
printed += struct_member__fprintf(pos, type, cu, &cconf, fp);
if (tag__is_struct(type) && !cconf.suppress_comments) {
const uint16_t padding = tag__class(type)->padding;
if (padding > 0) {
++nr_paddings;
sum_paddings += padding;
if (!newline++) {
fputc('\n', fp);
++printed;
}
printed += fprintf(fp, "\n%.*s/* XXX last "
"struct has %d byte%s of "
"padding */", cconf.indent,
tabs, padding,
padding != 1 ? "s" : "");
}
}
if (pos->bit_hole != 0 && !cconf.suppress_comments) {
if (!newline++) {
fputc('\n', fp);
++printed;
}
printed += fprintf(fp, "\n%.*s/* XXX %d bit%s hole, "
"try to pack */", cconf.indent, tabs,
pos->bit_hole,
pos->bit_hole != 1 ? "s" : "");
sum_bit_holes += pos->bit_hole;
}
if (pos->hole > 0 && !cconf.suppress_comments) {
if (!newline++) {
fputc('\n', fp);
++printed;
}
printed += fprintf(fp, "\n%.*s/* XXX %d byte%s hole, "
"try to pack */",
cconf.indent, tabs, pos->hole,
pos->hole != 1 ? "s" : "");
sum_holes += pos->hole;
}
fputc('\n', fp);
++printed;
/* XXX for now just skip these */
if (tag_pos->tag == DW_TAG_inheritance &&
pos->virtuality == DW_VIRTUALITY_virtual)
continue;
/*
* Check if we have to adjust size because bitfields were
* combined with previous fields.
*/
if (bitfield_real_offset != 0 && last->bitfield_end) {
size_t real_last_size = pos->offset - bitfield_real_offset;
sum -= last_size;
sum += real_last_size;
bitfield_real_offset = 0;
}
if (last == NULL || /* First member */
/*
* Last member was a zero sized array, typedef, struct, etc
*/
last_size == 0 ||
/*
* We moved to a new offset
*/
last->offset != pos->offset) {
sum += size;
last_size = size;
} else if (last->bit_size == 0 && pos->bit_size != 0) {
/*
* Transitioned from from a non-bitfield to a
* bitfield sharing the same offset
*/
/*
* Compensate by removing the size of the
* last member that is "inside" this new
* member at the same offset.
*
* E.g.:
* struct foo {
* u8 a; / 0 1 /
* int b:1; / 0:23 4 /
* }
*/
sum += size - last_size;
last_size = size;
}
last = pos;
}
/*
* Check if we have to adjust size because bitfields were
* combined with previous fields and were the last fields
* in the struct.
*/
if (bitfield_real_offset != 0) {
size_t real_last_size = tself->size - bitfield_real_offset;
sum -= last_size;
sum += real_last_size;
bitfield_real_offset = 0;
}
if (!cconf.suppress_comments)
printed += class__fprintf_cacheline_boundary(last_cacheline,
sum, sum_holes,
&newline,
&last_cacheline,
cconf.indent, fp);
class__vtable_fprintf(self, &cconf, fp);
if (!cconf.emit_stats)
[CLASSES]: Fully support nested classes Example: [acme@newtoy pahole]$ pahole net/ipv4/tcp.o flowi /* include/net/flow.h:13 */ struct flowi { int oif; /* 0 4 */ int iif; /* 4 4 */ __u32 mark; /* 8 4 */ union { struct { __be32 daddr; /* 0 4 */ __be32 saddr; /* 4 4 */ __u8 tos; /* 8 1 */ __u8 scope; /* 9 1 */ } ip4_u; /* 12 */ struct { struct in6_addr daddr; /* 0 16 */ struct in6_addr saddr; /* 16 16 */ /* --- cacheline 1 boundary (32 bytes) --- */ __be32 flowlabel; /* 32 4 */ } ip6_u; /* 36 */ struct { __le16 daddr; /* 0 2 */ __le16 saddr; /* 2 2 */ __u8 scope; /* 4 1 */ } dn_u; /* 6 */ } nl_u; /* 12 36 */ /* --- cacheline 1 boundary (32 bytes) was 16 bytes ago --- */ __u8 proto; /* 48 1 */ __u8 flags; /* 49 1 */ /* XXX 2 bytes hole, try to pack */ union { struct { __be16 sport; /* 0 2 */ __be16 dport; /* 2 2 */ } ports; /* 4 */ struct { __u8 type; /* 0 1 */ __u8 code; /* 1 1 */ } icmpt; /* 2 */ struct { __le16 sport; /* 0 2 */ __le16 dport; /* 2 2 */ } dnports; /* 4 */ __be32 spi; /* 4 */ } uli_u; /* 52 4 */ __u32 secid; /* 56 4 */ }; /* size: 60, cachelines: 2 */ /* sum members: 58, holes: 1, sum holes: 2 */ /* last cacheline: 28 bytes */ Supporting anonymous structs and unions just fine, even combinations of both, like in struct page, in the Linux kernel: [acme@newtoy pahole]$ pahole mm/mmap.o page /* include/linux/mmzone.h:391 */ struct page { long unsigned int flags; /* 0 4 */ atomic_t _count; /* 4 4 */ atomic_t _mapcount; /* 8 4 */ union { struct { long unsigned int private; /* 0 4 */ struct address_space * mapping; /* 4 4 */ }; /* 8 */ }; /* 12 8 */ long unsigned int index; /* 20 4 */ struct list_head lru; /* 24 8 */ /* --- cacheline 1 boundary (32 bytes) --- */ }; /* size: 32, cachelines: 1 */ Or struct freebsd_sys_getdents_args in the OpenBSD kernel: /* /usr/home/leonardo/openbsd/src/sys/compat/freebsd/freebsd_syscallargs.h:231 */ struct freebsd_sys_getdents_args { union { register_t pad; /* 4 */ struct { int datum; /* 0 4 */ } le; /* 4 */ struct { int8_t pad[0]; /* 0 0 */ int datum; /* 0 4 */ } be; /* 4 */ } fd; /* 0 4 */ union { register_t pad; /* 4 */ struct { void * datum; /* 0 4 */ } le; /* 4 */ struct { int8_t pad[0]; /* 0 0 */ void * datum; /* 0 4 */ } be; /* 4 */ } dirent; /* 4 4 */ union { register_t pad; /* 4 */ struct { unsigned int datum; /* 0 4 */ } le; /* 4 */ struct { int8_t pad[0]; /* 0 0 */ unsigned int datum; /* 0 4 */ } be; /* 4 */ } count; /* 8 4 */ }; /* size: 12, cachelines: 1 */ /* last cacheline: 12 bytes */ /* definitions: 7 */ One more from the OpenBSD kernel: /* /usr/home/leonardo/openbsd/src/sys/nfs/nfs.h:344 */ struct nfssvc_sock { struct { struct nfssvc_sock * tqe_next; /* 0 4 */ struct nfssvc_sock * * tqe_prev; /* 4 4 */ } ns_chain; /* 0 8 */ struct { struct nfsuid * tqh_first; /* 0 4 */ struct nfsuid * * tqh_last; /* 4 4 */ } ns_uidlruhead; /* 8 8 */ struct file * ns_fp; /* 16 4 */ struct socket * ns_so; /* 20 4 */ struct mbuf * ns_nam; /* 24 4 */ struct mbuf * ns_raw; /* 28 4 */ /* --- cacheline 1 boundary (32 bytes) --- */ struct mbuf * ns_rawend; /* 32 4 */ struct mbuf * ns_rec; /* 36 4 */ struct mbuf * ns_recend; /* 40 4 */ struct mbuf * ns_frag; /* 44 4 */ int ns_flag; /* 48 4 */ int ns_solock; /* 52 4 */ int ns_cc; /* 56 4 */ int ns_reclen; /* 60 4 */ /* --- cacheline 2 boundary (64 bytes) --- */ int ns_numuids; /* 64 4 */ u_int32_t ns_sref; /* 68 4 */ struct { struct nfsrv_descript * lh_first; /* 0 4 */ } ns_tq; /* 72 4 */ struct ns_uidhashtbl[29]; /* 76 116 */ /* --- cacheline 6 boundary (192 bytes) --- */ struct nfsrvw_delayhash ns_wdelayhashtbl[16]; /* 192 64 */ /* --- cacheline 8 boundary (256 bytes) --- */ }; /* size: 256, cachelines: 8 */ /* definitions: 12 */ Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 22:46:47 +01:00
goto out;
printed += fprintf(fp, "\n%.*s/* size: %zd, cachelines: %zd */",
cconf.indent, tabs,
tself->size, tag__nr_cachelines(class__tag(self),
cu));
if (sum_holes > 0)
printed += fprintf(fp, "\n%.*s/* sum members: %u, holes: %d, "
"sum holes: %u */",
cconf.indent, tabs,
sum, self->nr_holes, sum_holes);
if (sum_bit_holes > 0)
printed += fprintf(fp, "\n%.*s/* bit holes: %d, sum bit "
"holes: %u bits */",
cconf.indent, tabs,
self->nr_bit_holes, sum_bit_holes);
if (self->padding > 0)
printed += fprintf(fp, "\n%.*s/* padding: %u */",
cconf.indent,
tabs, self->padding);
if (nr_paddings > 0)
printed += fprintf(fp, "\n%.*s/* paddings: %u, sum paddings: "
"%u */",
cconf.indent, tabs,
nr_paddings, sum_paddings);
if (self->bit_padding > 0)
printed += fprintf(fp, "\n%.*s/* bit_padding: %u bits */",
cconf.indent, tabs,
self->bit_padding);
last_cacheline = tself->size % cacheline_size;
if (last_cacheline != 0)
printed += fprintf(fp, "\n%.*s/* last cacheline: %u bytes */",
cconf.indent, tabs,
last_cacheline);
if (cconf.show_first_biggest_size_base_type_member &&
tself->nr_members != 0) {
struct class_member *m = type__find_first_biggest_size_base_type_member(tself, cu);
printed += fprintf(fp, "\n%.*s/* first biggest size base type member: %s %u %zd */",
cconf.indent, tabs, m->name, m->offset,
class_member__size(m, cu));
}
if (sum + sum_holes != tself->size - self->padding)
printed += fprintf(fp, "\n\n%.*s/* BRAIN FART ALERT! %zd != %u "
"+ %u(holes), diff = %zd */\n",
cconf.indent, tabs,
tself->size, sum, sum_holes,
tself->size - (sum + sum_holes));
fputc('\n', fp);
[CLASSES]: Fully support nested classes Example: [acme@newtoy pahole]$ pahole net/ipv4/tcp.o flowi /* include/net/flow.h:13 */ struct flowi { int oif; /* 0 4 */ int iif; /* 4 4 */ __u32 mark; /* 8 4 */ union { struct { __be32 daddr; /* 0 4 */ __be32 saddr; /* 4 4 */ __u8 tos; /* 8 1 */ __u8 scope; /* 9 1 */ } ip4_u; /* 12 */ struct { struct in6_addr daddr; /* 0 16 */ struct in6_addr saddr; /* 16 16 */ /* --- cacheline 1 boundary (32 bytes) --- */ __be32 flowlabel; /* 32 4 */ } ip6_u; /* 36 */ struct { __le16 daddr; /* 0 2 */ __le16 saddr; /* 2 2 */ __u8 scope; /* 4 1 */ } dn_u; /* 6 */ } nl_u; /* 12 36 */ /* --- cacheline 1 boundary (32 bytes) was 16 bytes ago --- */ __u8 proto; /* 48 1 */ __u8 flags; /* 49 1 */ /* XXX 2 bytes hole, try to pack */ union { struct { __be16 sport; /* 0 2 */ __be16 dport; /* 2 2 */ } ports; /* 4 */ struct { __u8 type; /* 0 1 */ __u8 code; /* 1 1 */ } icmpt; /* 2 */ struct { __le16 sport; /* 0 2 */ __le16 dport; /* 2 2 */ } dnports; /* 4 */ __be32 spi; /* 4 */ } uli_u; /* 52 4 */ __u32 secid; /* 56 4 */ }; /* size: 60, cachelines: 2 */ /* sum members: 58, holes: 1, sum holes: 2 */ /* last cacheline: 28 bytes */ Supporting anonymous structs and unions just fine, even combinations of both, like in struct page, in the Linux kernel: [acme@newtoy pahole]$ pahole mm/mmap.o page /* include/linux/mmzone.h:391 */ struct page { long unsigned int flags; /* 0 4 */ atomic_t _count; /* 4 4 */ atomic_t _mapcount; /* 8 4 */ union { struct { long unsigned int private; /* 0 4 */ struct address_space * mapping; /* 4 4 */ }; /* 8 */ }; /* 12 8 */ long unsigned int index; /* 20 4 */ struct list_head lru; /* 24 8 */ /* --- cacheline 1 boundary (32 bytes) --- */ }; /* size: 32, cachelines: 1 */ Or struct freebsd_sys_getdents_args in the OpenBSD kernel: /* /usr/home/leonardo/openbsd/src/sys/compat/freebsd/freebsd_syscallargs.h:231 */ struct freebsd_sys_getdents_args { union { register_t pad; /* 4 */ struct { int datum; /* 0 4 */ } le; /* 4 */ struct { int8_t pad[0]; /* 0 0 */ int datum; /* 0 4 */ } be; /* 4 */ } fd; /* 0 4 */ union { register_t pad; /* 4 */ struct { void * datum; /* 0 4 */ } le; /* 4 */ struct { int8_t pad[0]; /* 0 0 */ void * datum; /* 0 4 */ } be; /* 4 */ } dirent; /* 4 4 */ union { register_t pad; /* 4 */ struct { unsigned int datum; /* 0 4 */ } le; /* 4 */ struct { int8_t pad[0]; /* 0 0 */ unsigned int datum; /* 0 4 */ } be; /* 4 */ } count; /* 8 4 */ }; /* size: 12, cachelines: 1 */ /* last cacheline: 12 bytes */ /* definitions: 7 */ One more from the OpenBSD kernel: /* /usr/home/leonardo/openbsd/src/sys/nfs/nfs.h:344 */ struct nfssvc_sock { struct { struct nfssvc_sock * tqe_next; /* 0 4 */ struct nfssvc_sock * * tqe_prev; /* 4 4 */ } ns_chain; /* 0 8 */ struct { struct nfsuid * tqh_first; /* 0 4 */ struct nfsuid * * tqh_last; /* 4 4 */ } ns_uidlruhead; /* 8 8 */ struct file * ns_fp; /* 16 4 */ struct socket * ns_so; /* 20 4 */ struct mbuf * ns_nam; /* 24 4 */ struct mbuf * ns_raw; /* 28 4 */ /* --- cacheline 1 boundary (32 bytes) --- */ struct mbuf * ns_rawend; /* 32 4 */ struct mbuf * ns_rec; /* 36 4 */ struct mbuf * ns_recend; /* 40 4 */ struct mbuf * ns_frag; /* 44 4 */ int ns_flag; /* 48 4 */ int ns_solock; /* 52 4 */ int ns_cc; /* 56 4 */ int ns_reclen; /* 60 4 */ /* --- cacheline 2 boundary (64 bytes) --- */ int ns_numuids; /* 64 4 */ u_int32_t ns_sref; /* 68 4 */ struct { struct nfsrv_descript * lh_first; /* 0 4 */ } ns_tq; /* 72 4 */ struct ns_uidhashtbl[29]; /* 76 116 */ /* --- cacheline 6 boundary (192 bytes) --- */ struct nfsrvw_delayhash ns_wdelayhashtbl[16]; /* 192 64 */ /* --- cacheline 8 boundary (256 bytes) --- */ }; /* size: 256, cachelines: 8 */ /* definitions: 12 */ Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 22:46:47 +01:00
out:
return printed + fprintf(fp, "%.*s}%s%s", indent, tabs,
cconf.suffix ? " ": "", cconf.suffix ?: "");
}
static size_t variable__fprintf(const struct tag *tag, const struct cu *cu,
const struct conf_fprintf *conf, FILE *fp)
{
const struct variable *var = tag__variable(tag);
const char *name = variable__name(var, cu);
size_t printed = 0;
if (name != NULL) {
struct tag *type = variable__type(var, cu);
if (type != NULL) {
const char *varprefix = variable__prefix(var);
if (varprefix != NULL)
printed += fprintf(fp, "%s", varprefix);
printed += type__fprintf(type, cu, name, conf, fp);
}
}
return printed;
}
static size_t namespace__fprintf(const struct tag *tself, const struct cu *cu,
const struct conf_fprintf *conf, FILE *fp)
{
struct namespace *self = tag__namespace(tself);
struct conf_fprintf cconf = *conf;
size_t printed = fprintf(fp, "namespace %s {\n", self->name);
struct tag *pos;
++cconf.indent;
cconf.no_semicolon = 0;
namespace__for_each_tag(self, pos) {
printed += tag__fprintf(pos, cu, &cconf, fp);
printed += fprintf(fp, "\n\n");
}
return printed + fprintf(fp, "}");
}
size_t tag__fprintf(struct tag *self, const struct cu *cu,
const struct conf_fprintf *conf, FILE *fp)
{
size_t printed = 0;
struct conf_fprintf tconf;
const struct conf_fprintf *pconf = conf;
if (conf == NULL) {
tconf = conf_fprintf__defaults;
pconf = &tconf;
if (tconf.expand_types)
tconf.name_spacing = 55;
else if (tag__is_union(self))
tconf.name_spacing = 21;
} else if (conf->name_spacing == 0 || conf->type_spacing == 0) {
tconf = *conf;
pconf = &tconf;
if (tconf.name_spacing == 0) {
if (tconf.expand_types)
tconf.name_spacing = 55;
else
tconf.name_spacing =
tag__is_union(self) ? 21 : 23;
}
if (tconf.type_spacing == 0)
tconf.type_spacing = 26;
}
if (pconf->expand_types)
++self->recursivity_level;
if (pconf->show_decl_info) {
printed += fprintf(fp, "%.*s", pconf->indent, tabs);
printed += tag__fprintf_decl_info(self, fp);
}
printed += fprintf(fp, "%.*s", pconf->indent, tabs);
switch (self->tag) {
case DW_TAG_enumeration_type:
printed += enumeration__fprintf(self, cu, pconf, fp);
break;
case DW_TAG_typedef:
printed += typedef__fprintf(self, cu, pconf, fp);
break;
case DW_TAG_structure_type:
printed += class__fprintf(tag__class(self), cu, pconf, fp);
break;
case DW_TAG_namespace:
printed += namespace__fprintf(self, cu, pconf, fp);
break;
case DW_TAG_subprogram:
printed += function__fprintf(self, cu, fp);
break;
case DW_TAG_union_type:
printed += union__fprintf(tag__type(self), cu, pconf, fp);
break;
case DW_TAG_variable:
printed += variable__fprintf(self, cu, pconf, fp);
break;
case DW_TAG_imported_declaration:
printed += imported_declaration__fprintf(self, cu, fp);
break;
case DW_TAG_imported_module:
printed += imported_module__fprintf(self, cu, fp);
break;
default:
printed += fprintf(fp, "/* %s: %s tag not supported! */", __func__,
dwarf_tag_name(self->tag));
break;
}
if (!pconf->no_semicolon) {
fputc(';', fp);
++printed;
}
if (self->tag == DW_TAG_subprogram &&
!pconf->suppress_comments) {
const struct function *fself = tag__function(self);
if (fself->linkage_name != NULL)
printed += fprintf(fp, " /* linkage=%s */", fself->linkage_name);
}
if (pconf->expand_types)
--self->recursivity_level;
return printed;
}
int cu__for_each_tag(struct cu *self,
int (*iterator)(struct tag *tag, struct cu *cu,
void *cookie),
void *cookie,
struct tag *(*filter)(struct tag *tag, struct cu *cu,
void *cookie))
{
struct tag *pos;
list_for_each_entry(pos, &self->tags, node) {
struct tag *tag = pos;
if (filter != NULL) {
tag = filter(pos, self, cookie);
if (tag == NULL)
continue;
}
if (iterator(tag, self, cookie))
return 1;
}
return 0;
}
void cus__for_each_cu(struct cus *self,
int (*iterator)(struct cu *cu, void *cookie),
void *cookie,
struct cu *(*filter)(struct cu *cu))
{
struct cu *pos;
list_for_each_entry(pos, &self->cus, node) {
struct cu *cu = pos;
if (filter != NULL) {
cu = filter(pos);
if (cu == NULL)
continue;
}
if (iterator(cu, cookie))
break;
}
}
int cus__load_dir(struct cus *self, const char *dirname,
const char *filename_mask, const int recursive)
{
struct dirent *entry;
int err = -1;
DIR *dir = opendir(dirname);
if (dir == NULL)
goto out;
err = 0;
while ((entry = readdir(dir)) != NULL) {
char pathname[PATH_MAX];
struct stat st;
if (strcmp(entry->d_name, ".") == 0 ||
strcmp(entry->d_name, "..") == 0)
continue;
snprintf(pathname, sizeof(pathname), "%s/%s",
dirname, entry->d_name);
err = lstat(pathname, &st);
if (err != 0)
break;
if (S_ISDIR(st.st_mode)) {
if (!recursive)
continue;
err = cus__load_dir(self, pathname,
filename_mask, recursive);
if (err != 0)
break;
} else if (fnmatch(filename_mask, entry->d_name, 0) == 0) {
err = cus__load(self, pathname);
if (err != 0)
break;
}
}
if (err == -1)
puts(dirname);
closedir(dir);
out:
return err;
}
int cus__load(struct cus *self, const char *filename)
{
int err = dwarf__load_filename(self, filename);
/*
* See cus__loadfl.
*/
return err;
}
int cus__loadfl(struct cus *self, struct argp *argp, int argc, char *argv[])
{
int err = dwarf__load(self, argp, argc, argv);
/*
* If dwarf__load fails, try ctf__load. Eventually we should just
* register all the shared objects at some directory and ask them
* for the magic types they support or just pass them the file,
* unloading the shared object if it says its not the type they
* support.
* FIXME: for now we just check if no DWARF info was found
* by looking at the list of CUs found:
*/
if (list_empty(&self->cus))
err = ctf__load(self, argp, argc, argv);
return err;
}
void cus__print_error_msg(const char *progname, const char *filename,
const int err)
{
if (err == -EINVAL)
fprintf(stderr, "%s: couldn't load DWARF info from %s\n",
progname, filename);
else
fprintf(stderr, "%s: %s\n", progname, strerror(err));
}
struct cus *cus__new(struct list_head *definitions,
struct list_head *fwd_decls)
{
struct cus *self = malloc(sizeof(*self));
if (self != NULL) {
INIT_LIST_HEAD(&self->cus);
INIT_LIST_HEAD(&self->priv_definitions);
INIT_LIST_HEAD(&self->priv_fwd_decls);
self->definitions = definitions ?: &self->priv_definitions;
self->fwd_decls = fwd_decls ?: &self->priv_fwd_decls;
}
return self;
}
void dwarves__init(size_t user_cacheline_size)
{
if (user_cacheline_size == 0) {
long sys_cacheline_size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
if (sys_cacheline_size > 0)
cacheline_size = sys_cacheline_size;
else
cacheline_size = 64; /* Fall back to a sane value */
} else
cacheline_size = user_cacheline_size;
}