2006-12-14 16:18:07 +01:00
|
|
|
/*
|
2006-10-28 23:22:42 +02:00
|
|
|
Copyright (C) 2006 Mandriva Conectiva S.A.
|
|
|
|
Copyright (C) 2006 Arnaldo Carvalho de Melo <acme@mandriva.com>
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it
|
|
|
|
under the terms of version 2 of the GNU General Public License as
|
|
|
|
published by the Free Software Foundation.
|
|
|
|
*/
|
|
|
|
|
2006-11-20 18:43:39 +01:00
|
|
|
#define _GNU_SOURCE
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
#include <assert.h>
|
2006-12-27 17:57:19 +01:00
|
|
|
#include <dirent.h>
|
2006-10-28 23:22:42 +02:00
|
|
|
#include <dwarf.h>
|
|
|
|
#include <fcntl.h>
|
2006-12-27 17:57:19 +01:00
|
|
|
#include <fnmatch.h>
|
2006-10-28 23:22:42 +02:00
|
|
|
#include <libelf.h>
|
2006-11-04 21:37:23 +01:00
|
|
|
#include <search.h>
|
2006-10-28 23:22:42 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include "list.h"
|
2007-01-11 19:07:05 +01:00
|
|
|
#include "dwarves.h"
|
2006-10-28 23:22:42 +02:00
|
|
|
|
2006-11-18 19:32:05 +01:00
|
|
|
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",
|
|
|
|
};
|
|
|
|
|
2006-12-28 14:18:43 +01:00
|
|
|
const char *dwarf_tag_name(const uint32_t tag)
|
2006-11-18 19:32:05 +01:00
|
|
|
{
|
|
|
|
if (tag >= DW_TAG_array_type && tag <= DW_TAG_shared_type)
|
|
|
|
return dwarf_tag_names[tag];
|
|
|
|
return "INVALID";
|
|
|
|
}
|
|
|
|
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
static const char tabs[] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
|
|
|
|
|
2006-12-25 01:27:22 +01:00
|
|
|
size_t cacheline_size = DEFAULT_CACHELINE_SIZE;
|
2006-11-05 18:34:54 +01:00
|
|
|
|
2006-10-28 23:22:42 +02:00
|
|
|
static void *zalloc(const size_t size)
|
|
|
|
{
|
|
|
|
void *s = malloc(size);
|
|
|
|
if (s != NULL)
|
|
|
|
memset(s, 0, size);
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2006-12-08 15:58:46 +01:00
|
|
|
void *memdup(const void *src, size_t len)
|
|
|
|
{
|
|
|
|
void *s = malloc(len);
|
|
|
|
if (s != NULL)
|
|
|
|
memcpy(s, src, len);
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2006-11-04 21:37:23 +01:00
|
|
|
static void *strings;
|
|
|
|
|
|
|
|
static int strings__compare(const void *a, const void *b)
|
|
|
|
{
|
|
|
|
return strcmp(a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
static 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;
|
|
|
|
}
|
|
|
|
|
2007-01-03 23:22:51 +01:00
|
|
|
/* Number decoding macros. See 7.6 Variable Length Data. */
|
|
|
|
|
|
|
|
#define get_uleb128_step(var, addr, nth, break) \
|
|
|
|
__b = *(addr)++; \
|
|
|
|
var |= (uintmax_t) (__b & 0x7f) << (nth * 7); \
|
|
|
|
if ((__b & 0x80) == 0) \
|
|
|
|
break
|
|
|
|
|
|
|
|
#define get_uleb128_rest_return(var, i, addrp) \
|
|
|
|
do { \
|
|
|
|
for (; i < 10; ++i) { \
|
|
|
|
get_uleb128_step(var, *addrp, i, \
|
|
|
|
return var); \
|
|
|
|
} \
|
|
|
|
/* Other implementations set VALUE to UINT_MAX in this \
|
|
|
|
case. So we better do this as well. */ \
|
|
|
|
return UINT64_MAX; \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
static uint64_t __libdw_get_uleb128(uint64_t acc, uint32_t i,
|
|
|
|
const uint8_t **addrp)
|
|
|
|
{
|
|
|
|
uint8_t __b;
|
|
|
|
get_uleb128_rest_return (acc, i, addrp);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define get_uleb128(var, addr) \
|
|
|
|
do { \
|
|
|
|
uint8_t __b; \
|
|
|
|
var = 0; \
|
|
|
|
get_uleb128_step(var, addr, 0, break); \
|
|
|
|
var = __libdw_get_uleb128 (var, 1, &(addr)); \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
static uint64_t attr_numeric(Dwarf_Die *die, uint32_t name)
|
|
|
|
{
|
|
|
|
Dwarf_Attribute attr;
|
|
|
|
uint32_t form;
|
|
|
|
|
|
|
|
if (dwarf_attr(die, name, &attr) == NULL)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
form = dwarf_whatform(&attr);
|
|
|
|
|
|
|
|
switch (form) {
|
|
|
|
case DW_FORM_addr: {
|
|
|
|
Dwarf_Addr addr;
|
|
|
|
if (dwarf_formaddr(&attr, &addr) == 0)
|
|
|
|
return addr;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case DW_FORM_data1:
|
|
|
|
case DW_FORM_data2:
|
|
|
|
case DW_FORM_data4:
|
|
|
|
case DW_FORM_data8:
|
|
|
|
case DW_FORM_sdata:
|
|
|
|
case DW_FORM_udata: {
|
|
|
|
Dwarf_Word value;
|
|
|
|
if (dwarf_formudata(&attr, &value) == 0)
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case DW_FORM_ref1:
|
|
|
|
case DW_FORM_ref2:
|
|
|
|
case DW_FORM_ref4:
|
|
|
|
case DW_FORM_ref8:
|
|
|
|
case DW_FORM_ref_addr:
|
|
|
|
case DW_FORM_ref_udata: {
|
|
|
|
Dwarf_Off ref;
|
|
|
|
if (dwarf_formref(&attr, &ref) == 0)
|
|
|
|
return (uintmax_t)ref;
|
|
|
|
}
|
|
|
|
case DW_FORM_flag:
|
|
|
|
return 1;
|
|
|
|
default:
|
|
|
|
printf("DW_AT_<0x%x>=0x%x\n", name, form);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Dwarf_Off attr_offset(Dwarf_Die *die)
|
|
|
|
{
|
|
|
|
Dwarf_Attribute attr;
|
|
|
|
|
|
|
|
if (dwarf_attr(die, DW_AT_data_member_location, &attr) != NULL) {
|
|
|
|
Dwarf_Block block;
|
|
|
|
|
|
|
|
if (dwarf_formblock(&attr, &block) == 0) {
|
|
|
|
uint64_t uleb;
|
|
|
|
const uint8_t *data = block.data + 1;
|
|
|
|
get_uleb128(uleb, data);
|
|
|
|
return uleb;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-01-04 20:27:24 +01:00
|
|
|
static const char *attr_string(Dwarf_Die *die, uint32_t name)
|
2007-01-03 23:22:51 +01:00
|
|
|
{
|
2007-01-04 20:27:24 +01:00
|
|
|
Dwarf_Attribute attr;
|
|
|
|
if (dwarf_attr(die, name, &attr) != NULL)
|
|
|
|
return dwarf_formstring(&attr);
|
2007-01-03 23:22:51 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void tag__init(struct tag *self, Dwarf_Die *die)
|
|
|
|
{
|
|
|
|
uint32_t decl_line;
|
|
|
|
|
|
|
|
self->tag = dwarf_tag(die);
|
|
|
|
self->id = dwarf_cuoffset(die);
|
|
|
|
self->type = attr_numeric(die, DW_AT_type);
|
|
|
|
self->decl_file = strings__add(dwarf_decl_file(die));
|
|
|
|
dwarf_decl_line(die, &decl_line);
|
2006-11-18 14:54:02 +01:00
|
|
|
self->decl_line = decl_line;
|
|
|
|
}
|
|
|
|
|
2007-01-03 23:22:51 +01:00
|
|
|
static struct tag *tag__new(Dwarf_Die *die)
|
2006-12-29 19:34:11 +01:00
|
|
|
{
|
|
|
|
struct tag *self = malloc(sizeof(*self));
|
|
|
|
|
|
|
|
if (self != NULL)
|
2007-01-03 23:22:51 +01:00
|
|
|
tag__init(self, die);
|
2006-12-29 19:34:11 +01:00
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2007-01-12 19:29:53 +01:00
|
|
|
static void __tag__type_not_found(const struct tag *self, const struct cu *cu,
|
|
|
|
const char *fn)
|
|
|
|
{
|
|
|
|
char bf[64];
|
|
|
|
|
|
|
|
fprintf(stderr, "%s: %#llx type not found for %s (id=%#llx)\n",
|
|
|
|
fn, self->type, dwarf_tag_name(self->tag), self->id);
|
|
|
|
fflush(stdout);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define tag__type_not_found(self, cu) \
|
|
|
|
__tag__type_not_found(self, cu, __FUNCTION__)
|
|
|
|
|
2007-01-12 19:11:37 +01:00
|
|
|
void tag__print_decl_info(const struct tag *self)
|
|
|
|
{
|
2007-01-13 13:58:58 +01:00
|
|
|
printf("/* <%llx> %s:%u */\n",
|
|
|
|
self->id, self->decl_file, self->decl_line);
|
2007-01-12 19:11:37 +01:00
|
|
|
}
|
|
|
|
|
2007-01-03 23:22:51 +01:00
|
|
|
static struct base_type *base_type__new(Dwarf_Die *die)
|
2006-12-29 23:58:03 +01:00
|
|
|
{
|
|
|
|
struct base_type *self = zalloc(sizeof(*self));
|
|
|
|
|
|
|
|
if (self != NULL) {
|
2007-01-03 23:22:51 +01:00
|
|
|
tag__init(&self->tag, die);
|
2007-01-04 20:27:24 +01:00
|
|
|
self->name = strings__add(attr_string(die, DW_AT_name));
|
2007-01-03 23:22:51 +01:00
|
|
|
self->size = attr_numeric(die, DW_AT_byte_size);
|
2006-12-29 23:58:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2007-01-07 15:30:58 +01:00
|
|
|
static void type__init(struct type *self, Dwarf_Die *die)
|
2007-01-06 18:17:58 +01:00
|
|
|
{
|
2007-01-07 15:30:58 +01:00
|
|
|
tag__init(&self->tag, die);
|
|
|
|
INIT_LIST_HEAD(&self->node);
|
2007-01-09 13:00:47 +01:00
|
|
|
INIT_LIST_HEAD(&self->members);
|
2007-01-07 15:30:58 +01:00
|
|
|
self->name = strings__add(attr_string(die, DW_AT_name));
|
2007-01-09 13:00:47 +01:00
|
|
|
self->size = attr_numeric(die, DW_AT_byte_size);
|
|
|
|
self->declaration = attr_numeric(die, DW_AT_declaration);
|
2007-01-07 15:30:58 +01:00
|
|
|
self->definition_emitted = 0;
|
|
|
|
self->fwd_decl_emitted = 0;
|
2007-01-09 13:00:47 +01:00
|
|
|
self->nr_members = 0;
|
2007-01-07 15:30:58 +01:00
|
|
|
}
|
2007-01-06 18:17:58 +01:00
|
|
|
|
2007-01-07 15:30:58 +01:00
|
|
|
static struct type *type__new(Dwarf_Die *die)
|
|
|
|
{
|
|
|
|
struct type *self = malloc(sizeof(*self));
|
|
|
|
|
|
|
|
if (self != NULL)
|
|
|
|
type__init(self, die);
|
2007-01-06 18:17:58 +01:00
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2007-01-12 16:04:05 +01:00
|
|
|
static void typedef__print(const struct tag *tag_self, const struct cu *cu)
|
|
|
|
{
|
|
|
|
const struct type *self = tag__type(tag_self);
|
|
|
|
const struct tag *type = cu__find_tag_by_id(cu, tag_self->type);
|
|
|
|
const struct tag *ptr_type;
|
|
|
|
int is_pointer = 0;
|
|
|
|
char bf[512];
|
|
|
|
|
2007-01-12 19:29:53 +01:00
|
|
|
if (type == NULL) {
|
|
|
|
tag__type_not_found(tag_self, cu);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-01-12 16:04:05 +01:00
|
|
|
switch (type->tag) {
|
|
|
|
case DW_TAG_pointer_type:
|
|
|
|
ptr_type = cu__find_tag_by_id(cu, type->type);
|
|
|
|
if (ptr_type->tag != DW_TAG_subroutine_type)
|
|
|
|
break;
|
|
|
|
type = ptr_type;
|
|
|
|
is_pointer = 1;
|
|
|
|
/* Fall thru */
|
|
|
|
case DW_TAG_subroutine_type:
|
|
|
|
ftype__snprintf(tag__ftype(type), cu, bf, sizeof(bf),
|
|
|
|
self->name, 0, is_pointer, 0);
|
|
|
|
fputs("typedef ", stdout);
|
2007-01-12 20:23:14 +01:00
|
|
|
fputs(bf, stdout);
|
2007-01-12 16:04:05 +01:00
|
|
|
return;
|
|
|
|
case DW_TAG_structure_type: {
|
|
|
|
const struct type *ctype = tag__type(type);
|
|
|
|
|
|
|
|
if (ctype->name != NULL)
|
2007-01-12 20:23:14 +01:00
|
|
|
printf("typedef struct %s %s",
|
2007-01-12 16:04:05 +01:00
|
|
|
ctype->name, self->name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-01-12 20:23:14 +01:00
|
|
|
printf("typedef %s %s", tag__name(type, cu, bf, sizeof(bf)),
|
2007-01-12 16:04:05 +01:00
|
|
|
self->name);
|
|
|
|
}
|
|
|
|
|
2007-01-07 16:27:12 +01:00
|
|
|
static size_t enumeration__snprintf(const struct tag *tag_self,
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
char *bf, size_t len,
|
2007-01-13 13:40:33 +01:00
|
|
|
const char *suffix, uint8_t indent)
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
{
|
2007-01-09 13:00:47 +01:00
|
|
|
const struct type *self = tag__type(tag_self);
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
struct enumerator *pos;
|
|
|
|
char *s = bf;
|
|
|
|
size_t printed = 0, n;
|
|
|
|
|
2007-01-13 13:40:33 +01:00
|
|
|
if (indent >= sizeof(tabs))
|
|
|
|
indent = sizeof(tabs) - 1;
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
|
|
|
|
n = snprintf(s, len, "enum%s%s {\n",
|
2007-01-09 13:00:47 +01:00
|
|
|
self->name ? " " : "", self->name ?: "");
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
s += n;
|
|
|
|
len -= n;
|
|
|
|
printed += n;
|
|
|
|
list_for_each_entry(pos, &self->members, tag.node) {
|
2007-01-13 13:40:33 +01:00
|
|
|
n = snprintf(s, len, "%.*s\t%s = %u,\n", indent, tabs,
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
pos->name, pos->value);
|
|
|
|
s += n;
|
|
|
|
len -= n;
|
|
|
|
printed += n;
|
|
|
|
}
|
|
|
|
|
2007-01-13 13:40:33 +01:00
|
|
|
n = snprintf(s, len, "%.*s}%s%s", indent, tabs,
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
suffix ? " " : "", suffix ?: "");
|
|
|
|
return printed + n;
|
|
|
|
}
|
|
|
|
|
2007-01-07 16:27:12 +01:00
|
|
|
static void enumeration__print(const struct tag *tag_self,
|
2007-01-13 13:40:33 +01:00
|
|
|
const char *suffix, uint8_t indent)
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
{
|
|
|
|
char bf[4096];
|
|
|
|
|
2007-01-13 13:40:33 +01:00
|
|
|
if (indent >= sizeof(tabs))
|
|
|
|
indent = sizeof(tabs) - 1;
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
|
2007-01-13 13:40:33 +01:00
|
|
|
enumeration__snprintf(tag_self, bf, sizeof(bf), suffix, indent);
|
2007-01-12 20:40:12 +01:00
|
|
|
fputs(bf, stdout);
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
}
|
|
|
|
|
2007-01-03 23:22:51 +01:00
|
|
|
static struct enumerator *enumerator__new(Dwarf_Die *die)
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
{
|
|
|
|
struct enumerator *self = zalloc(sizeof(*self));
|
|
|
|
|
|
|
|
if (self != NULL) {
|
2007-01-03 23:22:51 +01:00
|
|
|
tag__init(&self->tag, die);
|
2007-01-04 20:27:24 +01:00
|
|
|
self->name = strings__add(attr_string(die, DW_AT_name));
|
2007-01-03 23:22:51 +01:00
|
|
|
self->value = attr_numeric(die, DW_AT_const_value);
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2007-01-03 23:22:51 +01:00
|
|
|
static struct variable *variable__new(Dwarf_Die *die)
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
{
|
|
|
|
struct variable *self = malloc(sizeof(*self));
|
|
|
|
|
|
|
|
if (self != NULL) {
|
2007-01-03 23:22:51 +01:00
|
|
|
tag__init(&self->tag, die);
|
2007-01-04 20:27:24 +01:00
|
|
|
self->name = strings__add(attr_string(die, DW_AT_name));
|
2007-01-03 23:22:51 +01:00
|
|
|
self->abstract_origin = attr_numeric(die,
|
|
|
|
DW_AT_abstract_origin);
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2006-11-11 19:31:04 +01:00
|
|
|
static void cus__add(struct cus *self, struct cu *cu)
|
2006-10-31 20:12:42 +01:00
|
|
|
{
|
2006-11-11 19:31:04 +01:00
|
|
|
list_add_tail(&cu->node, &self->cus);
|
2006-10-31 20:12:42 +01:00
|
|
|
}
|
|
|
|
|
2006-12-29 19:34:11 +01:00
|
|
|
static struct cu *cu__new(uint32_t cu, const char *name, uint8_t addr_size)
|
2006-10-31 20:12:42 +01:00
|
|
|
{
|
|
|
|
struct cu *self = malloc(sizeof(*self));
|
|
|
|
|
2006-11-03 18:38:43 +01:00
|
|
|
if (self != NULL) {
|
2007-01-04 00:29:24 +01:00
|
|
|
INIT_LIST_HEAD(&self->tags);
|
2006-12-20 15:07:09 +01:00
|
|
|
INIT_LIST_HEAD(&self->tool_list);
|
2006-12-29 19:34:11 +01:00
|
|
|
|
|
|
|
self->name = strings__add(name);
|
|
|
|
self->addr_size = addr_size;
|
|
|
|
|
2006-11-03 18:38:43 +01:00
|
|
|
self->nr_inline_expansions = 0;
|
|
|
|
self->size_inline_expansions = 0;
|
2006-11-12 15:29:33 +01:00
|
|
|
self->nr_structures_changed = 0;
|
2006-11-11 19:31:04 +01:00
|
|
|
self->nr_functions_changed = 0;
|
2006-11-12 15:29:33 +01:00
|
|
|
self->max_len_changed_item = 0;
|
2006-11-11 19:31:04 +01:00
|
|
|
self->function_bytes_added = 0;
|
|
|
|
self->function_bytes_removed = 0;
|
2006-11-03 18:38:43 +01:00
|
|
|
}
|
2006-10-31 20:12:42 +01:00
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
static void cu__add_tag(struct cu *self, struct tag *tag)
|
2006-10-31 20:12:42 +01:00
|
|
|
{
|
2007-01-04 00:29:24 +01:00
|
|
|
list_add_tail(&tag->node, &self->tags);
|
2006-10-31 20:12:42 +01:00
|
|
|
}
|
2006-10-28 23:22:42 +02:00
|
|
|
|
2006-11-18 17:33:48 +01:00
|
|
|
static void cu__add_function(struct cu *self, struct function *function)
|
|
|
|
{
|
2007-01-04 00:29:24 +01:00
|
|
|
list_add_tail(&function->proto.tag.node, &self->tags);
|
2006-11-18 17:33:48 +01:00
|
|
|
}
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
static const char *tag__prefix(const struct cu *cu, const uint32_t tag)
|
2006-10-28 23:22:42 +02:00
|
|
|
{
|
|
|
|
switch (tag) {
|
|
|
|
case DW_TAG_enumeration_type: return "enum ";
|
2006-12-07 20:21:52 +01:00
|
|
|
case DW_TAG_structure_type:
|
|
|
|
return cu->language == DW_LANG_C_plus_plus ? "class " :
|
|
|
|
"struct ";
|
2006-10-28 23:22:42 +02:00
|
|
|
case DW_TAG_union_type: return "union ";
|
|
|
|
case DW_TAG_pointer_type: return " *";
|
2007-01-12 14:06:59 +01:00
|
|
|
case DW_TAG_reference_type: return " &";
|
2006-10-28 23:22:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
struct tag *cu__find_tag_by_id(const struct cu *self, const Dwarf_Off id)
|
2006-12-20 17:10:07 +01:00
|
|
|
{
|
2006-12-29 18:28:58 +01:00
|
|
|
struct tag *pos;
|
2006-12-20 17:10:07 +01:00
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
if (id == 0)
|
|
|
|
return NULL;
|
2006-12-20 17:10:07 +01:00
|
|
|
|
2007-01-04 00:29:24 +01:00
|
|
|
list_for_each_entry(pos, &self->tags, node)
|
2006-12-29 18:28:58 +01:00
|
|
|
if (pos->id == id)
|
|
|
|
return pos;
|
2006-12-20 17:10:07 +01:00
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
return NULL;
|
2006-12-20 17:10:07 +01:00
|
|
|
}
|
|
|
|
|
2007-01-07 16:11:20 +01:00
|
|
|
struct tag *cu__find_struct_by_name(const struct cu *self, const char *name)
|
2006-10-28 23:22:42 +02:00
|
|
|
{
|
2006-12-29 18:28:58 +01:00
|
|
|
struct tag *pos;
|
2006-10-28 23:22:42 +02:00
|
|
|
|
2006-11-11 19:31:04 +01:00
|
|
|
if (name == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2007-01-04 00:29:24 +01:00
|
|
|
list_for_each_entry(pos, &self->tags, node) {
|
2007-01-07 16:11:20 +01:00
|
|
|
struct type *type;
|
2006-12-29 23:58:03 +01:00
|
|
|
|
|
|
|
if (pos->tag != DW_TAG_structure_type)
|
|
|
|
continue;
|
|
|
|
|
2007-01-07 16:11:20 +01:00
|
|
|
type = tag__type(pos);
|
|
|
|
if (type->name != NULL && strcmp(type->name, name) == 0)
|
|
|
|
return pos;
|
2006-12-29 18:28:58 +01:00
|
|
|
}
|
2006-10-28 23:22:42 +02:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-01-07 16:11:20 +01:00
|
|
|
struct tag *cus__find_struct_by_name(const struct cus *self,
|
|
|
|
struct cu **cu, const char *name)
|
2006-10-28 23:22:42 +02:00
|
|
|
{
|
2006-11-12 20:33:37 +01:00
|
|
|
struct cu *pos;
|
2006-10-28 23:22:42 +02:00
|
|
|
|
2006-11-12 20:33:37 +01:00
|
|
|
list_for_each_entry(pos, &self->cus, node) {
|
2007-01-07 16:11:20 +01:00
|
|
|
struct tag *tag = cu__find_struct_by_name(pos, name);
|
2006-10-31 21:23:16 +01:00
|
|
|
|
2007-01-07 16:11:20 +01:00
|
|
|
if (tag != NULL) {
|
2007-01-04 00:57:35 +01:00
|
|
|
if (cu != NULL)
|
|
|
|
*cu = pos;
|
2007-01-07 16:11:20 +01:00
|
|
|
return tag;
|
2007-01-04 00:57:35 +01:00
|
|
|
}
|
2006-10-31 21:23:16 +01:00
|
|
|
}
|
2006-10-31 20:12:42 +01:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-01-12 18:47:26 +01:00
|
|
|
struct tag *cus__find_function_by_name(const struct cus *self,
|
|
|
|
struct cu **cu, const char *name)
|
2006-12-23 21:46:05 +01:00
|
|
|
{
|
|
|
|
struct cu *pos;
|
|
|
|
|
|
|
|
list_for_each_entry(pos, &self->cus, node) {
|
2007-01-12 18:47:26 +01:00
|
|
|
struct tag *function = cu__find_function_by_name(pos, name);
|
2006-12-23 21:46:05 +01:00
|
|
|
|
2007-01-04 00:57:35 +01:00
|
|
|
if (function != NULL) {
|
|
|
|
if (cu != NULL)
|
|
|
|
*cu = pos;
|
2006-12-23 21:46:05 +01:00
|
|
|
return function;
|
2007-01-04 00:57:35 +01:00
|
|
|
}
|
2006-12-23 21:46:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2006-11-13 03:31:48 +01:00
|
|
|
struct cu *cus__find_cu_by_name(const struct cus *self, const char *name)
|
2006-11-11 19:31:04 +01:00
|
|
|
{
|
|
|
|
struct cu *pos;
|
|
|
|
|
|
|
|
list_for_each_entry(pos, &self->cus, node)
|
|
|
|
if (strcmp(pos->name, name) == 0)
|
|
|
|
return pos;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-01-07 15:30:58 +01:00
|
|
|
struct type *cus__find_definition(const struct cus *self, const char *name)
|
2006-12-23 21:53:25 +01:00
|
|
|
{
|
2007-01-07 15:30:58 +01:00
|
|
|
struct type *pos;
|
2006-12-23 21:53:25 +01:00
|
|
|
|
2006-12-24 01:35:38 +01:00
|
|
|
if (name == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2006-12-27 17:39:37 +01:00
|
|
|
list_for_each_entry(pos, self->definitions, node)
|
2006-12-24 01:35:38 +01:00
|
|
|
if (pos->name != NULL && strcmp(pos->name, name) == 0)
|
2006-12-23 21:53:25 +01:00
|
|
|
return pos;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-01-07 15:30:58 +01:00
|
|
|
struct type *cus__find_fwd_decl(const struct cus *self, const char *name)
|
2006-12-23 21:53:25 +01:00
|
|
|
{
|
2007-01-07 15:30:58 +01:00
|
|
|
struct type *pos;
|
2006-12-23 21:53:25 +01:00
|
|
|
|
2006-12-27 17:39:37 +01:00
|
|
|
list_for_each_entry(pos, self->fwd_decls, node)
|
2006-12-23 21:53:25 +01:00
|
|
|
if (strcmp(pos->name, name) == 0)
|
|
|
|
return pos;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-01-07 15:30:58 +01:00
|
|
|
static void cus__add_definition(struct cus *self, struct type *type)
|
2006-12-23 21:53:25 +01:00
|
|
|
{
|
2007-01-07 15:30:58 +01:00
|
|
|
type->definition_emitted = 1;
|
|
|
|
if (!list_empty(&type->node))
|
|
|
|
list_del(&type->node);
|
|
|
|
list_add_tail(&type->node, self->definitions);
|
2006-12-23 21:53:25 +01:00
|
|
|
}
|
|
|
|
|
2007-01-07 15:30:58 +01:00
|
|
|
static void cus__add_fwd_decl(struct cus *self, struct type *type)
|
2007-01-06 18:17:58 +01:00
|
|
|
{
|
2007-01-07 15:30:58 +01:00
|
|
|
type->fwd_decl_emitted = 1;
|
|
|
|
if (list_empty(&type->node))
|
|
|
|
list_add_tail(&type->node, self->fwd_decls);
|
2006-12-23 21:53:25 +01:00
|
|
|
}
|
|
|
|
|
2007-01-12 18:47:26 +01:00
|
|
|
struct tag *cu__find_function_by_name(const struct cu *self, const char *name)
|
2006-11-18 17:33:48 +01:00
|
|
|
{
|
2007-01-04 00:29:24 +01:00
|
|
|
struct tag *pos;
|
|
|
|
struct function *fpos;
|
2006-11-18 17:33:48 +01:00
|
|
|
|
|
|
|
if (name == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2007-01-04 00:29:24 +01:00
|
|
|
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)
|
2007-01-12 18:47:26 +01:00
|
|
|
return pos;
|
2007-01-04 00:29:24 +01:00
|
|
|
}
|
2006-11-18 17:33:48 +01:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-01-04 16:13:21 +01:00
|
|
|
static struct tag *lexblock__find_tag_by_id(const struct lexblock *self,
|
|
|
|
const Dwarf_Off id)
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
{
|
2007-01-04 16:13:21 +01:00
|
|
|
struct tag *pos;
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
|
2007-01-04 16:13:21 +01:00
|
|
|
list_for_each_entry(pos, &self->tags, node) {
|
|
|
|
/* Allow find DW_TAG_lexical_block tags */
|
|
|
|
if (pos->id == id)
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
return pos;
|
2007-01-04 16:13:21 +01:00
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-01-13 14:37:41 +01:00
|
|
|
static struct tag *ftype__find_parm_by_id(const struct ftype *self,
|
|
|
|
const Dwarf_Off id)
|
|
|
|
{
|
|
|
|
struct tag *pos;
|
|
|
|
|
|
|
|
list_for_each_entry(pos, &self->parms, node)
|
|
|
|
if (pos->id == id)
|
|
|
|
return pos;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-01-07 20:57:00 +01:00
|
|
|
static struct parameter *cu__find_parameter_by_id(const struct cu *self,
|
|
|
|
const Dwarf_Off id)
|
|
|
|
{
|
|
|
|
struct tag *pos;
|
|
|
|
|
|
|
|
list_for_each_entry(pos, &self->tags, node)
|
|
|
|
if (pos->id == id)
|
|
|
|
return tag__parameter(pos);
|
|
|
|
|
|
|
|
if (pos->tag == DW_TAG_subprogram) {
|
|
|
|
struct function *fn = tag__function(pos);
|
2007-01-13 14:37:41 +01:00
|
|
|
struct tag *tag = ftype__find_parm_by_id(&fn->proto,
|
|
|
|
id);
|
|
|
|
if (tag != NULL) {
|
|
|
|
tag = lexblock__find_tag_by_id(&fn->lexblock,
|
|
|
|
id);
|
|
|
|
if (tag != NULL)
|
|
|
|
return tag__parameter(tag);
|
|
|
|
}
|
2007-01-07 20:57:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
int tag__is_struct(const struct tag *self, struct tag **typedef_alias,
|
|
|
|
const struct cu *cu)
|
2006-11-05 05:17:19 +01:00
|
|
|
{
|
|
|
|
*typedef_alias = NULL;
|
2006-12-29 18:28:58 +01:00
|
|
|
if (self->tag == DW_TAG_typedef) {
|
|
|
|
*typedef_alias = cu__find_tag_by_id(cu, self->type);
|
2007-01-12 02:09:06 +01:00
|
|
|
if (*typedef_alias == NULL) {
|
|
|
|
tag__type_not_found(self, cu);
|
2006-11-05 05:17:19 +01:00
|
|
|
return 0;
|
2007-01-12 02:09:06 +01:00
|
|
|
}
|
2006-11-05 05:17:19 +01:00
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
return (*typedef_alias)->tag == DW_TAG_structure_type;
|
2006-11-05 05:17:19 +01:00
|
|
|
}
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
return self->tag == DW_TAG_structure_type;
|
2006-11-05 05:17:19 +01:00
|
|
|
}
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
static size_t array_type__nr_entries(const struct array_type *self)
|
2006-12-08 15:58:46 +01:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
size_t nr_entries = 1;
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
for (i = 0; i < self->dimensions; ++i)
|
|
|
|
nr_entries *= self->nr_entries[i];
|
2006-12-08 15:58:46 +01:00
|
|
|
|
|
|
|
return nr_entries;
|
|
|
|
}
|
|
|
|
|
2007-01-09 18:10:31 +01:00
|
|
|
size_t tag__size(const struct tag *self, const struct cu *cu)
|
2006-10-28 23:22:42 +02:00
|
|
|
{
|
2006-12-29 19:34:11 +01:00
|
|
|
size_t size;
|
2006-10-28 23:22:42 +02:00
|
|
|
|
2006-12-29 23:58:03 +01:00
|
|
|
switch (self->tag) {
|
2007-01-12 14:06:59 +01:00
|
|
|
case DW_TAG_pointer_type:
|
|
|
|
case DW_TAG_reference_type: return cu->addr_size;
|
2007-01-07 16:27:12 +01:00
|
|
|
case DW_TAG_base_type: return tag__base_type(self)->size;
|
2007-01-09 13:00:47 +01:00
|
|
|
case DW_TAG_enumeration_type: return tag__type(self)->size;
|
2006-12-29 23:58:03 +01:00
|
|
|
}
|
2006-12-29 19:34:11 +01:00
|
|
|
|
2007-01-07 16:27:12 +01:00
|
|
|
if (self->type == 0) /* struct class: unions, structs */
|
2007-01-09 13:00:47 +01:00
|
|
|
size = tag__type(self)->size;
|
2006-12-29 19:34:11 +01:00
|
|
|
else {
|
|
|
|
const struct tag *type = cu__find_tag_by_id(cu, self->type);
|
|
|
|
|
2007-01-12 02:09:06 +01:00
|
|
|
if (type == NULL) {
|
|
|
|
tag__type_not_found(self, cu);
|
|
|
|
return -1;
|
|
|
|
}
|
2006-12-29 19:34:11 +01:00
|
|
|
size = tag__size(type, cu);
|
|
|
|
}
|
2006-10-28 23:22:42 +02:00
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
if (self->tag == DW_TAG_array_type)
|
|
|
|
return size * array_type__nr_entries(tag__array_type(self));
|
2006-10-28 23:22:42 +02:00
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2007-01-12 14:06:59 +01:00
|
|
|
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, cu);
|
|
|
|
snprintf(bf, len,
|
|
|
|
"<ERROR: type not found!> %c", ptr_char);
|
|
|
|
} else {
|
|
|
|
char tmpbf[128];
|
|
|
|
snprintf(bf, len, "%s %c",
|
|
|
|
tag__name(type, cu,
|
|
|
|
tmpbf, sizeof(tmpbf)), ptr_char);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return bf;
|
|
|
|
}
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
const char *tag__name(const struct tag *self, const struct cu *cu,
|
|
|
|
char *bf, size_t len)
|
2006-10-28 23:22:42 +02:00
|
|
|
{
|
2006-12-29 18:28:58 +01:00
|
|
|
struct tag *type;
|
|
|
|
|
2006-12-19 12:20:52 +01:00
|
|
|
if (self == NULL)
|
|
|
|
strncpy(bf, "void", len);
|
2007-01-13 19:04:21 +01:00
|
|
|
else switch (self->tag) {
|
|
|
|
case DW_TAG_base_type:
|
2006-12-29 23:58:03 +01:00
|
|
|
strncpy(bf, tag__base_type(self)->name, len);
|
2007-01-13 19:04:21 +01:00
|
|
|
break;
|
|
|
|
case DW_TAG_subprogram:
|
2007-01-07 20:13:39 +01:00
|
|
|
strncpy(bf, function__name(tag__function(self), cu), len);
|
2007-01-13 19:04:21 +01:00
|
|
|
break;
|
|
|
|
case DW_TAG_pointer_type:
|
2007-01-12 14:06:59 +01:00
|
|
|
return tag__ptr_name(self, cu, bf, len, '*');
|
2007-01-13 19:04:21 +01:00
|
|
|
break;
|
|
|
|
case DW_TAG_reference_type:
|
2007-01-12 14:06:59 +01:00
|
|
|
return tag__ptr_name(self, cu, bf, len, '&');
|
2007-01-13 19:04:21 +01:00
|
|
|
break;
|
|
|
|
case DW_TAG_volatile_type:
|
|
|
|
case DW_TAG_const_type:
|
2006-12-29 18:28:58 +01:00
|
|
|
type = cu__find_tag_by_id(cu, self->type);
|
2007-01-12 02:09:06 +01:00
|
|
|
if (type == NULL && self->type != 0) {
|
|
|
|
tag__type_not_found(self, cu);
|
|
|
|
strncpy(bf, "<ERROR>", len);
|
2007-01-13 19:04:21 +01:00
|
|
|
} else {
|
|
|
|
char tmpbf[128];
|
2007-01-12 02:09:06 +01:00
|
|
|
snprintf(bf, len, "%s %s ",
|
|
|
|
self->tag == DW_TAG_volatile_type ?
|
|
|
|
"volatile" : "const",
|
|
|
|
tag__name(type, cu, tmpbf, sizeof(tmpbf)));
|
2007-01-13 19:04:21 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case DW_TAG_array_type:
|
2006-12-29 18:28:58 +01:00
|
|
|
type = cu__find_tag_by_id(cu, self->type);
|
2007-01-12 02:09:06 +01:00
|
|
|
if (type == NULL) {
|
|
|
|
tag__type_not_found(self, cu);
|
|
|
|
strncpy(bf, "<ERROR>", len);
|
|
|
|
} else
|
|
|
|
return tag__name(type, cu, bf, len);
|
2007-01-13 19:04:21 +01:00
|
|
|
break;
|
|
|
|
case DW_TAG_subroutine_type:
|
2007-01-04 16:06:29 +01:00
|
|
|
ftype__snprintf(tag__ftype(self), cu, bf, len, NULL, 0, 0, 0);
|
2007-01-13 19:04:21 +01:00
|
|
|
break;
|
|
|
|
default:
|
2006-12-29 18:28:58 +01:00
|
|
|
snprintf(bf, len, "%s%s", tag__prefix(cu, self->tag),
|
2007-01-07 15:30:58 +01:00
|
|
|
tag__type(self)->name ?: "");
|
2007-01-13 19:04:21 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2006-10-28 23:22:42 +02:00
|
|
|
return bf;
|
|
|
|
}
|
|
|
|
|
2006-11-20 18:43:39 +01:00
|
|
|
const char *variable__type_name(const struct variable *self,
|
2007-01-03 01:26:01 +01:00
|
|
|
const struct cu *cu,
|
2006-11-20 18:43:39 +01:00
|
|
|
char *bf, size_t len)
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
{
|
2006-11-18 14:54:02 +01:00
|
|
|
if (self->tag.type != 0) {
|
2007-01-03 01:26:01 +01:00
|
|
|
struct tag *tag = cu__find_tag_by_id(cu, self->tag.type);
|
|
|
|
return tag__name(tag, cu, bf, len);
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
} else if (self->abstract_origin != 0) {
|
2007-01-04 16:13:21 +01:00
|
|
|
struct variable *var =
|
|
|
|
cu__find_variable_by_id(cu, self->abstract_origin);
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
|
|
|
|
if (var != NULL)
|
2007-01-03 01:26:01 +01:00
|
|
|
return variable__type_name(var, cu, bf, len);
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-01-03 01:26:01 +01:00
|
|
|
const char *variable__name(const struct variable *self, const struct cu *cu)
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
{
|
2007-01-04 16:13:21 +01:00
|
|
|
if (self->name != NULL)
|
|
|
|
return self->name;
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
|
2007-01-04 16:13:21 +01:00
|
|
|
if (self->abstract_origin != 0) {
|
|
|
|
struct variable *var =
|
|
|
|
cu__find_variable_by_id(cu, self->abstract_origin);
|
|
|
|
if (var != NULL)
|
|
|
|
return var->name;
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
}
|
2007-01-04 16:13:21 +01:00
|
|
|
return NULL;
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
}
|
|
|
|
|
2007-01-03 23:22:51 +01:00
|
|
|
static struct class_member *class_member__new(Dwarf_Die *die)
|
2006-10-28 23:22:42 +02:00
|
|
|
{
|
|
|
|
struct class_member *self = zalloc(sizeof(*self));
|
|
|
|
|
|
|
|
if (self != NULL) {
|
2007-01-03 23:22:51 +01:00
|
|
|
tag__init(&self->tag, die);
|
|
|
|
self->offset = attr_offset(die);
|
|
|
|
self->bit_size = attr_numeric(die, DW_AT_bit_size);
|
|
|
|
self->bit_offset = attr_numeric(die, DW_AT_bit_offset);
|
2007-01-04 20:27:24 +01:00
|
|
|
self->name = strings__add(attr_string(die, DW_AT_name));
|
2006-10-28 23:22:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2007-01-04 04:41:11 +01:00
|
|
|
static size_t class_member__size(const struct class_member *self,
|
|
|
|
const struct cu *cu)
|
2006-10-28 23:22:42 +02:00
|
|
|
{
|
2007-01-04 04:41:11 +01:00
|
|
|
struct tag *type = cu__find_tag_by_id(cu, self->tag.type);
|
2007-01-12 02:09:06 +01:00
|
|
|
if (type == NULL) {
|
|
|
|
tag__type_not_found(&self->tag, cu);
|
|
|
|
return -1;
|
|
|
|
}
|
2007-01-04 04:41:11 +01:00
|
|
|
return tag__size(type, cu);
|
2006-10-28 23:22:42 +02:00
|
|
|
}
|
|
|
|
|
2007-01-03 23:22:51 +01:00
|
|
|
static struct parameter *parameter__new(Dwarf_Die *die)
|
2006-11-18 17:33:48 +01:00
|
|
|
{
|
|
|
|
struct parameter *self = zalloc(sizeof(*self));
|
|
|
|
|
|
|
|
if (self != NULL) {
|
2007-01-03 23:22:51 +01:00
|
|
|
tag__init(&self->tag, die);
|
2007-01-07 20:57:00 +01:00
|
|
|
self->name = strings__add(attr_string(die,
|
|
|
|
DW_AT_name));
|
|
|
|
self->abstract_origin = attr_numeric(die,
|
|
|
|
DW_AT_abstract_origin);
|
2006-11-18 17:33:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2007-01-07 20:57:00 +01:00
|
|
|
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 parameter *alias =
|
|
|
|
cu__find_parameter_by_id(cu, self->abstract_origin);
|
2007-01-12 02:09:06 +01:00
|
|
|
if (alias == NULL) {
|
|
|
|
tag__type_not_found(&self->tag, cu);
|
|
|
|
return NULL;
|
|
|
|
}
|
2007-01-07 20:57:00 +01:00
|
|
|
/* Now cache the result in this tag ->name field */
|
|
|
|
self->name = 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 parameter *alias =
|
|
|
|
cu__find_parameter_by_id(cu, self->abstract_origin);
|
2007-01-12 02:09:06 +01:00
|
|
|
if (alias == NULL) {
|
|
|
|
tag__type_not_found(&self->tag, cu);
|
|
|
|
return 0;
|
|
|
|
}
|
2007-01-07 20:57:00 +01:00
|
|
|
/* Now cache the result in this tag ->name and type fields */
|
|
|
|
self->name = alias->name;
|
|
|
|
self->tag.type = alias->tag.type;
|
|
|
|
}
|
|
|
|
|
|
|
|
return self->tag.type;
|
|
|
|
}
|
|
|
|
|
2007-01-03 23:22:51 +01:00
|
|
|
static struct inline_expansion *inline_expansion__new(Dwarf_Die *die)
|
2006-11-03 16:41:19 +01:00
|
|
|
{
|
|
|
|
struct inline_expansion *self = zalloc(sizeof(*self));
|
|
|
|
|
|
|
|
if (self != NULL) {
|
2007-01-03 23:22:51 +01:00
|
|
|
tag__init(&self->tag, die);
|
|
|
|
self->tag.decl_file =
|
2007-01-04 20:27:24 +01:00
|
|
|
strings__add(attr_string(die, DW_AT_call_file));
|
2007-01-03 23:22:51 +01:00
|
|
|
self->tag.decl_line = attr_numeric(die, DW_AT_call_line);
|
|
|
|
self->tag.type = attr_numeric(die, DW_AT_abstract_origin);
|
|
|
|
|
|
|
|
if (dwarf_lowpc(die, &self->low_pc))
|
|
|
|
self->low_pc = 0;
|
|
|
|
if (dwarf_lowpc(die, &self->high_pc))
|
|
|
|
self->high_pc = 0;
|
|
|
|
|
|
|
|
self->size = self->high_pc - self->low_pc;
|
|
|
|
if (self->size == 0) {
|
|
|
|
Dwarf_Addr base, start;
|
|
|
|
ptrdiff_t offset = 0;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
offset = dwarf_ranges(die, offset, &base, &start,
|
|
|
|
&self->high_pc);
|
|
|
|
start = (unsigned long)start;
|
|
|
|
self->high_pc = (unsigned long)self->high_pc;
|
|
|
|
if (offset <= 0)
|
|
|
|
break;
|
|
|
|
self->size += self->high_pc - start;
|
|
|
|
if (self->low_pc == 0)
|
|
|
|
self->low_pc = start;
|
|
|
|
}
|
|
|
|
}
|
2006-11-03 16:41:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2007-01-03 23:22:51 +01:00
|
|
|
static struct label *label__new(Dwarf_Die *die)
|
2006-11-20 19:17:42 +01:00
|
|
|
{
|
|
|
|
struct label *self = malloc(sizeof(*self));
|
|
|
|
|
|
|
|
if (self != NULL) {
|
2007-01-03 23:22:51 +01:00
|
|
|
tag__init(&self->tag, die);
|
2007-01-04 20:27:24 +01:00
|
|
|
self->name = strings__add(attr_string(die, DW_AT_name));
|
2007-01-03 23:22:51 +01:00
|
|
|
if (dwarf_lowpc(die, &self->low_pc))
|
|
|
|
self->low_pc = 0;
|
2006-11-20 19:17:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2007-01-03 23:22:51 +01:00
|
|
|
static struct array_type *array_type__new(Dwarf_Die *die)
|
2006-12-29 18:28:58 +01:00
|
|
|
{
|
|
|
|
struct array_type *self = zalloc(sizeof(*self));
|
|
|
|
|
|
|
|
if (self != NULL)
|
2007-01-03 23:22:51 +01:00
|
|
|
tag__init(&self->tag, die);
|
2006-12-29 18:28:58 +01:00
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
[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 array_type__snprintf(const struct tag *tag_self,
|
|
|
|
const struct cu *cu,
|
|
|
|
char *bf, const size_t len,
|
|
|
|
const char *name,
|
|
|
|
size_t type_spacing)
|
|
|
|
{
|
|
|
|
struct array_type *self = tag__array_type(tag_self);
|
|
|
|
char tbf[128];
|
|
|
|
size_t l = len;
|
|
|
|
size_t n = snprintf(bf, l, "%-*s %s", type_spacing,
|
|
|
|
tag__name(tag_self, cu, tbf, sizeof(tbf)),
|
|
|
|
name);
|
|
|
|
int i;
|
|
|
|
|
|
|
|
bf += n; l -= n;
|
|
|
|
|
|
|
|
for (i = 0; i < self->dimensions; ++i) {
|
|
|
|
n = snprintf(bf, l, "[%u]", self->nr_entries[i]);
|
|
|
|
bf += n; l -= n;
|
|
|
|
}
|
|
|
|
|
|
|
|
return len - l;
|
|
|
|
}
|
|
|
|
|
|
|
|
static size_t union__snprintf(const struct type *self, const struct cu *cu,
|
|
|
|
char *bf, size_t len, const char *suffix,
|
2007-01-13 13:40:33 +01:00
|
|
|
uint8_t indent, size_t type_spacing,
|
[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
|
|
|
size_t name_spacing);
|
[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 class__snprintf(const struct class *self, const struct cu *cu,
|
|
|
|
char *bf, size_t len,
|
|
|
|
const char *prefix, const char *suffix,
|
2007-01-13 13:40:33 +01:00
|
|
|
uint8_t indent, size_t type_spacing,
|
[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
|
|
|
size_t name_spacing, int emit_stats);
|
[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 class_member__snprintf(struct class_member *self,
|
[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
|
|
|
struct tag *type, const struct cu *cu,
|
2007-01-13 13:40:33 +01:00
|
|
|
char *bf, size_t len, size_t indent,
|
[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
|
|
|
size_t type_spacing, size_t name_spacing)
|
[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];
|
2007-01-13 19:14:45 +01:00
|
|
|
struct type *ctype;
|
[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)
|
|
|
|
return snprintf(bf, len, "%-*s %s",
|
|
|
|
type_spacing, "<ERROR>", self->name);
|
|
|
|
|
2007-01-13 19:12:41 +01:00
|
|
|
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->tag == DW_TAG_subroutine_type) {
|
|
|
|
return ftype__snprintf(tag__ftype(ptype), cu,
|
|
|
|
bf, len, self->name,
|
|
|
|
0, 1, type_spacing);
|
|
|
|
}
|
|
|
|
}
|
2007-01-13 19:12:41 +01:00
|
|
|
break;
|
|
|
|
case DW_TAG_subroutine_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
|
|
|
return ftype__snprintf(tag__ftype(type), cu, bf, len,
|
|
|
|
self->name, 0, 0, type_spacing);
|
2007-01-13 19:12:41 +01:00
|
|
|
case DW_TAG_array_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
|
|
|
return array_type__snprintf(type, cu, bf, len, self->name,
|
|
|
|
type_spacing);
|
2007-01-13 19:14:45 +01:00
|
|
|
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 (ctype->name != NULL)
|
|
|
|
return snprintf(bf, len, "struct %-*s %s",
|
|
|
|
type_spacing - 7, ctype->name,
|
|
|
|
self->name);
|
|
|
|
|
|
|
|
return class__snprintf(tag__class(type), cu, bf, len,
|
2007-01-13 13:40:33 +01:00
|
|
|
NULL, self->name, indent,
|
[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
|
|
|
type_spacing - 8, name_spacing, 0);
|
2007-01-13 19:14:45 +01:00
|
|
|
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 (ctype->name != NULL)
|
|
|
|
return snprintf(bf, len, "union %-*s %s",
|
|
|
|
type_spacing - 6, ctype->name,
|
|
|
|
self->name);
|
|
|
|
|
2007-01-13 13:40:33 +01:00
|
|
|
return union__snprintf(ctype, cu, bf, len, self->name, indent,
|
[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_spacing - 8, name_spacing);
|
2007-01-13 19:14:45 +01:00
|
|
|
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 (ctype->name != NULL)
|
|
|
|
return snprintf(bf, len, "enum %-*s %s",
|
|
|
|
type_spacing - 5, ctype->name,
|
|
|
|
self->name);
|
|
|
|
|
2007-01-13 13:40:33 +01:00
|
|
|
return enumeration__snprintf(type, bf, len, self->name, indent);
|
[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
|
|
|
}
|
2007-01-13 19:12:41 +01:00
|
|
|
|
[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 snprintf(bf, len, "%-*s %s", type_spacing,
|
|
|
|
tag__name(type, cu, tbf, sizeof(tbf)),
|
|
|
|
self->name);
|
|
|
|
}
|
|
|
|
|
2007-01-10 19:39:20 +01:00
|
|
|
static size_t struct_member__snprintf(struct class_member *self,
|
|
|
|
struct tag *type, const struct cu *cu,
|
2007-01-13 13:40:33 +01:00
|
|
|
char *bf, size_t len, size_t indent,
|
2007-01-10 19:39:20 +01:00
|
|
|
size_t type_spacing, size_t name_spacing)
|
[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
|
|
|
{
|
2007-01-10 19:39:20 +01:00
|
|
|
size_t l = len;
|
[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
|
|
|
ssize_t spacing;
|
2007-01-10 19:39:20 +01:00
|
|
|
const size_t size = tag__size(type, cu);
|
2007-01-13 13:40:33 +01:00
|
|
|
size_t n = class_member__snprintf(self, type, cu, bf, l, indent,
|
[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_spacing, name_spacing);
|
|
|
|
|
2007-01-10 19:39:20 +01:00
|
|
|
bf += n; l -= n;
|
[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)
|
2007-01-10 19:39:20 +01:00
|
|
|
n = snprintf(bf, l, ":%u;", self->bit_size);
|
[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
|
|
|
else
|
2007-01-10 19:39:20 +01:00
|
|
|
n = snprintf(bf, l, ";");
|
|
|
|
bf += n; l -= n;
|
|
|
|
|
[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->tag == DW_TAG_union_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
|
|
|
type->tag == DW_TAG_enumeration_type ||
|
|
|
|
type->tag == DW_TAG_structure_type) &&
|
|
|
|
/* Look if is a type defined inline */
|
[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
|
|
|
tag__type(type)->name == NULL) {
|
|
|
|
/* Check if this is a anonymous union */
|
|
|
|
const size_t slen = self->name != NULL ?
|
[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
|
|
|
strlen(self->name) : -1;
|
|
|
|
return len -
|
|
|
|
(l - snprintf(bf, l, "%*s/* %5u %5u */",
|
|
|
|
type_spacing + name_spacing - slen - 3,
|
|
|
|
" ", self->offset, size));
|
2007-01-10 19:39:20 +01:00
|
|
|
}
|
[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
|
|
|
spacing = type_spacing + name_spacing - (len - l);
|
|
|
|
return len - (l - snprintf(bf, l, "%*s/* %5u %5u */",
|
|
|
|
spacing > 0 ? spacing : 0, " ",
|
|
|
|
self->offset, size));
|
|
|
|
}
|
|
|
|
|
|
|
|
static size_t union_member__snprintf(struct class_member *self,
|
|
|
|
struct tag *type, const struct cu *cu,
|
2007-01-13 13:40:33 +01:00
|
|
|
char *bf, size_t len, size_t indent,
|
[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
|
|
|
size_t type_spacing, size_t name_spacing)
|
|
|
|
{
|
|
|
|
size_t l = len;
|
|
|
|
ssize_t spacing;
|
|
|
|
const size_t size = tag__size(type, cu);
|
2007-01-13 13:40:33 +01:00
|
|
|
size_t n = class_member__snprintf(self, type, cu, bf, l, indent,
|
[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
|
|
|
type_spacing, name_spacing);
|
|
|
|
|
|
|
|
bf += n; l -= n;
|
|
|
|
if ((type->tag == DW_TAG_union_type ||
|
|
|
|
type->tag == DW_TAG_enumeration_type ||
|
|
|
|
type->tag == DW_TAG_structure_type) &&
|
|
|
|
/* Look if is a type defined inline */
|
|
|
|
tag__type(type)->name == NULL) {
|
|
|
|
/* Check if this is a anonymous union */
|
|
|
|
const size_t slen = self->name != NULL ?
|
|
|
|
strlen(self->name) : -1;
|
|
|
|
return n + snprintf(bf, l, ";%*s/* %11u */",
|
|
|
|
type_spacing + name_spacing - slen - 3, " ",
|
|
|
|
size);
|
|
|
|
}
|
|
|
|
spacing = type_spacing + name_spacing - (len - (l - 1));
|
|
|
|
return n + snprintf(bf, l, ";%*s/* %11u */",
|
|
|
|
spacing > 0 ? spacing : 0, " ", size);
|
[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__snprintf(const struct type *self, const struct cu *cu,
|
|
|
|
char *bf, size_t len,
|
2007-01-13 13:40:33 +01:00
|
|
|
const char *suffix, uint8_t indent,
|
[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
|
|
|
size_t type_spacing, size_t name_spacing)
|
|
|
|
{
|
|
|
|
struct class_member *pos;
|
|
|
|
char *s = bf;
|
|
|
|
size_t l = len, n;
|
|
|
|
|
2007-01-13 13:40:33 +01:00
|
|
|
if (indent >= 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
|
|
|
|
|
|
|
n = snprintf(s, l, "union%s%s {\n",
|
|
|
|
self->name ? " " : "", self->name ?: "");
|
|
|
|
s += n;
|
|
|
|
l -= n;
|
|
|
|
list_for_each_entry(pos, &self->members, tag.node) {
|
|
|
|
struct tag *type = cu__find_tag_by_id(cu, pos->tag.type);
|
|
|
|
|
2007-01-13 13:40:33 +01:00
|
|
|
n = snprintf(s, l, "%.*s", indent + 1, tabs);
|
[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
|
|
|
s += n; l -= n;
|
2007-01-13 13:40:33 +01:00
|
|
|
n = union_member__snprintf(pos, type, cu, s, l, indent + 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
|
|
|
type_spacing, name_spacing);
|
[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
|
|
|
s += n; l -= n;
|
[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
|
|
|
n = snprintf(s, l, "\n");
|
[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
|
|
|
s += n; l -= n;
|
|
|
|
}
|
|
|
|
|
2007-01-13 13:40:33 +01:00
|
|
|
n = snprintf(s, len, "%.*s}%s%s", indent, tabs,
|
[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
|
|
|
suffix ? " " : "", suffix ?: "");
|
|
|
|
l -= n;
|
|
|
|
return len - l;
|
|
|
|
}
|
|
|
|
|
2007-01-12 21:00:32 +01:00
|
|
|
static void union__print(const struct tag *tag, const struct cu *cu,
|
|
|
|
const char *suffix)
|
|
|
|
{
|
|
|
|
const struct type *utype = tag__type(tag);
|
|
|
|
char bf[32768];
|
|
|
|
|
|
|
|
union__snprintf(utype, cu, bf, sizeof(bf), suffix, 0, 26, 23);
|
|
|
|
fputs(bf, stdout);
|
|
|
|
}
|
|
|
|
|
2007-01-03 23:22:51 +01:00
|
|
|
static struct class *class__new(Dwarf_Die *die)
|
2006-10-28 23:22:42 +02:00
|
|
|
{
|
2006-11-18 17:33:48 +01:00
|
|
|
struct class *self = zalloc(sizeof(*self));
|
2006-10-28 23:22:42 +02:00
|
|
|
|
2007-01-09 13:00:47 +01:00
|
|
|
if (self != NULL)
|
2007-01-07 15:30:58 +01:00
|
|
|
type__init(&self->type, die);
|
2006-10-28 23:22:42 +02:00
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2007-01-09 13:00:47 +01:00
|
|
|
static void type__add_member(struct type *self, struct class_member *member)
|
2006-10-28 23:22:42 +02:00
|
|
|
{
|
2006-11-01 14:34:42 +01:00
|
|
|
++self->nr_members;
|
2006-11-18 14:54:02 +01:00
|
|
|
list_add_tail(&member->tag.node, &self->members);
|
2006-10-28 23:22:42 +02:00
|
|
|
}
|
|
|
|
|
2007-01-09 13:00:47 +01:00
|
|
|
static void enumeration__add(struct type *self, struct enumerator *enumerator)
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
{
|
|
|
|
++self->nr_members;
|
|
|
|
list_add_tail(&enumerator->tag.node, &self->members);
|
|
|
|
}
|
|
|
|
|
2007-01-03 23:22:51 +01:00
|
|
|
static void lexblock__init(struct lexblock *self, Dwarf_Die *die)
|
2006-11-20 19:54:39 +01:00
|
|
|
{
|
2007-01-03 23:22:51 +01:00
|
|
|
if (dwarf_highpc(die, &self->high_pc))
|
|
|
|
self->high_pc = 0;
|
|
|
|
if (dwarf_lowpc(die, &self->low_pc))
|
|
|
|
self->low_pc = 0;
|
|
|
|
|
2007-01-03 01:26:01 +01:00
|
|
|
INIT_LIST_HEAD(&self->tags);
|
2006-11-20 19:54:39 +01:00
|
|
|
|
2007-01-02 16:25:56 +01:00
|
|
|
self->nr_inline_expansions =
|
|
|
|
self->nr_labels =
|
|
|
|
self->nr_lexblocks =
|
|
|
|
self->nr_variables = 0;
|
|
|
|
}
|
|
|
|
|
2007-01-03 23:22:51 +01:00
|
|
|
static struct lexblock *lexblock__new(Dwarf_Die *die)
|
2007-01-02 16:25:56 +01:00
|
|
|
{
|
|
|
|
struct lexblock *self = malloc(sizeof(*self));
|
|
|
|
|
|
|
|
if (self != NULL) {
|
2007-01-03 23:22:51 +01:00
|
|
|
tag__init(&self->tag, die);
|
|
|
|
lexblock__init(self, die);
|
2007-01-02 16:25:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void lexblock__add_lexblock(struct lexblock *self,
|
|
|
|
struct lexblock *child)
|
|
|
|
{
|
|
|
|
++self->nr_lexblocks;
|
2007-01-03 01:26:01 +01:00
|
|
|
list_add_tail(&child->tag.node, &self->tags);
|
2006-11-20 19:54:39 +01:00
|
|
|
}
|
|
|
|
|
2007-01-03 23:22:51 +01:00
|
|
|
static ftype__init(struct ftype *self, Dwarf_Die *die)
|
2006-12-30 19:34:20 +01:00
|
|
|
{
|
2007-01-03 23:22:51 +01:00
|
|
|
const uint16_t tag = dwarf_tag(die);
|
2006-12-30 19:34:20 +01:00
|
|
|
assert(tag == DW_TAG_subprogram || tag == DW_TAG_subroutine_type);
|
|
|
|
|
2007-01-03 23:22:51 +01:00
|
|
|
tag__init(&self->tag, die);
|
2006-12-30 19:34:20 +01:00
|
|
|
INIT_LIST_HEAD(&self->parms);
|
[CLASSES]: Introduce DW_TAG_subroutine_type specific parser
So that we handle DW_TAG_formal_parameters in this tag, fixing
these cases:
--- /tmp/ctracer.c.before 2006-12-29 13:27:24.000000000 -0200
+++ /tmp/ctracer.c 2007-01-02 02:34:18.000000000 -0200
<SNIP>
@@ -62,7 +62,7 @@
}; /* size: 68, cachelines: 3 */
/* last cacheline: 4 bytes */
-typedef int (*kretprobe_handler_t)(void /* FIXME: add parm list */);
+typedef int (*kretprobe_handler_t)(struct kretprobe_instance *, struct pt_regs *);
/* /pub/scm/linux/kernel/git/acme/linux-2.6/include/linux/list.h:607 */
struct hlist_head {
struct hlist_node * first; /* 0 4 */
[acme@newtoy ctracer_example]$
--- /tmp/pfunct.before 2006-12-30 16:18:25.000000000 -0200
+++ /tmp/pfunct.after 2007-01-02 02:08:50.000000000 -0200
@@ -249,7 +249,7 @@
/* definitions: 1 */
/* /pub/scm/linux/kernel/git/acme/linux-2.6/lib/klist.c:57 */
-void klist_init(struct klist * k, * get, * put);
+void klist_init(struct klist * k, void (*get)(struct klist_node *), void (*put)(struct klist_node *));
/* size: 12, inline expansions: 1 (5 bytes) */
/* definitions: 1 */
The struct/union case still needs fixing, but we're getting there...
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-02 05:42:33 +01:00
|
|
|
self->nr_parms = 0;
|
|
|
|
self->unspec_parms = 0;
|
|
|
|
}
|
|
|
|
|
2007-01-03 23:22:51 +01:00
|
|
|
static struct ftype *ftype__new(Dwarf_Die *die)
|
[CLASSES]: Introduce DW_TAG_subroutine_type specific parser
So that we handle DW_TAG_formal_parameters in this tag, fixing
these cases:
--- /tmp/ctracer.c.before 2006-12-29 13:27:24.000000000 -0200
+++ /tmp/ctracer.c 2007-01-02 02:34:18.000000000 -0200
<SNIP>
@@ -62,7 +62,7 @@
}; /* size: 68, cachelines: 3 */
/* last cacheline: 4 bytes */
-typedef int (*kretprobe_handler_t)(void /* FIXME: add parm list */);
+typedef int (*kretprobe_handler_t)(struct kretprobe_instance *, struct pt_regs *);
/* /pub/scm/linux/kernel/git/acme/linux-2.6/include/linux/list.h:607 */
struct hlist_head {
struct hlist_node * first; /* 0 4 */
[acme@newtoy ctracer_example]$
--- /tmp/pfunct.before 2006-12-30 16:18:25.000000000 -0200
+++ /tmp/pfunct.after 2007-01-02 02:08:50.000000000 -0200
@@ -249,7 +249,7 @@
/* definitions: 1 */
/* /pub/scm/linux/kernel/git/acme/linux-2.6/lib/klist.c:57 */
-void klist_init(struct klist * k, * get, * put);
+void klist_init(struct klist * k, void (*get)(struct klist_node *), void (*put)(struct klist_node *));
/* size: 12, inline expansions: 1 (5 bytes) */
/* definitions: 1 */
The struct/union case still needs fixing, but we're getting there...
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-02 05:42:33 +01:00
|
|
|
{
|
|
|
|
struct ftype *self = malloc(sizeof(*self));
|
|
|
|
|
|
|
|
if (self != NULL)
|
2007-01-03 23:22:51 +01:00
|
|
|
ftype__init(self, die);
|
[CLASSES]: Introduce DW_TAG_subroutine_type specific parser
So that we handle DW_TAG_formal_parameters in this tag, fixing
these cases:
--- /tmp/ctracer.c.before 2006-12-29 13:27:24.000000000 -0200
+++ /tmp/ctracer.c 2007-01-02 02:34:18.000000000 -0200
<SNIP>
@@ -62,7 +62,7 @@
}; /* size: 68, cachelines: 3 */
/* last cacheline: 4 bytes */
-typedef int (*kretprobe_handler_t)(void /* FIXME: add parm list */);
+typedef int (*kretprobe_handler_t)(struct kretprobe_instance *, struct pt_regs *);
/* /pub/scm/linux/kernel/git/acme/linux-2.6/include/linux/list.h:607 */
struct hlist_head {
struct hlist_node * first; /* 0 4 */
[acme@newtoy ctracer_example]$
--- /tmp/pfunct.before 2006-12-30 16:18:25.000000000 -0200
+++ /tmp/pfunct.after 2007-01-02 02:08:50.000000000 -0200
@@ -249,7 +249,7 @@
/* definitions: 1 */
/* /pub/scm/linux/kernel/git/acme/linux-2.6/lib/klist.c:57 */
-void klist_init(struct klist * k, * get, * put);
+void klist_init(struct klist * k, void (*get)(struct klist_node *), void (*put)(struct klist_node *));
/* size: 12, inline expansions: 1 (5 bytes) */
/* definitions: 1 */
The struct/union case still needs fixing, but we're getting there...
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-02 05:42:33 +01:00
|
|
|
|
|
|
|
return self;
|
2006-12-30 19:34:20 +01:00
|
|
|
}
|
|
|
|
|
2007-01-03 23:22:51 +01:00
|
|
|
static struct function *function__new(Dwarf_Die *die)
|
2006-11-18 17:33:48 +01:00
|
|
|
{
|
|
|
|
struct function *self = zalloc(sizeof(*self));
|
|
|
|
|
|
|
|
if (self != NULL) {
|
2007-01-03 23:22:51 +01:00
|
|
|
ftype__init(&self->proto, die);
|
|
|
|
lexblock__init(&self->lexblock, die);
|
2007-01-04 20:27:24 +01:00
|
|
|
self->name = strings__add(attr_string(die, DW_AT_name));
|
2007-01-03 23:22:51 +01:00
|
|
|
self->inlined = attr_numeric(die, DW_AT_inline);
|
|
|
|
self->external = dwarf_hasattr(die, DW_AT_external);
|
2007-01-07 20:13:39 +01:00
|
|
|
self->abstract_origin = attr_numeric(die,
|
|
|
|
DW_AT_abstract_origin);
|
2007-01-13 14:37:41 +01:00
|
|
|
self->specification = attr_numeric(die, DW_AT_specification);
|
2006-11-18 17:33:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2007-01-07 20:13:39 +01:00
|
|
|
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);
|
2007-01-12 02:09:06 +01:00
|
|
|
if (tag == NULL) {
|
2007-01-13 14:37:41 +01:00
|
|
|
/* ... or a DW_TAG_specification... */
|
|
|
|
tag = cu__find_tag_by_id(cu, self->specification);
|
|
|
|
if (tag == NULL) {
|
|
|
|
tag__type_not_found(&self->proto.tag, cu);
|
|
|
|
return NULL;
|
|
|
|
}
|
2007-01-12 02:09:06 +01:00
|
|
|
}
|
2007-01-07 20:13:39 +01:00
|
|
|
/* ... and now we cache the result in this tag ->name field */
|
|
|
|
self->name = tag__function(tag)->name;
|
|
|
|
}
|
|
|
|
|
|
|
|
return self->name;
|
|
|
|
}
|
|
|
|
|
2006-12-30 19:34:20 +01:00
|
|
|
int ftype__has_parm_of_type(const struct ftype *self, const struct tag *target,
|
|
|
|
const struct cu *cu)
|
2006-12-20 15:03:12 +01:00
|
|
|
{
|
2006-12-30 19:34:20 +01:00
|
|
|
struct parameter *pos;
|
2006-12-20 15:03:12 +01:00
|
|
|
|
2006-12-30 19:34:20 +01:00
|
|
|
list_for_each_entry(pos, &self->parms, tag.node) {
|
2007-01-07 20:57:00 +01:00
|
|
|
struct tag *type =
|
|
|
|
cu__find_tag_by_id(cu, parameter__type(pos, cu));
|
2006-12-20 15:03:12 +01:00
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
if (type != NULL && type->tag == DW_TAG_pointer_type) {
|
2006-12-30 19:34:20 +01:00
|
|
|
type = cu__find_tag_by_id(cu, type->type);
|
2006-12-29 18:28:58 +01:00
|
|
|
if (type != NULL && type->id == target->id)
|
2006-12-20 15:03:12 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-12-30 19:34:20 +01:00
|
|
|
static void ftype__add_parameter(struct ftype *self, struct parameter *parm)
|
2006-11-18 17:33:48 +01:00
|
|
|
{
|
2006-12-30 19:34:20 +01:00
|
|
|
++self->nr_parms;
|
|
|
|
list_add_tail(&parm->tag.node, &self->parms);
|
2006-11-18 17:33:48 +01:00
|
|
|
}
|
|
|
|
|
2006-11-20 19:51:42 +01:00
|
|
|
static void lexblock__add_inline_expansion(struct lexblock *self,
|
2006-11-18 17:33:48 +01:00
|
|
|
struct inline_expansion *exp)
|
2006-11-03 16:41:19 +01:00
|
|
|
{
|
2006-11-20 19:51:42 +01:00
|
|
|
++self->nr_inline_expansions;
|
2006-11-03 16:41:19 +01:00
|
|
|
self->size_inline_expansions += exp->size;
|
2007-01-03 01:26:01 +01:00
|
|
|
list_add_tail(&exp->tag.node, &self->tags);
|
2006-11-03 16:41:19 +01:00
|
|
|
}
|
|
|
|
|
2006-11-20 19:51:42 +01:00
|
|
|
static void lexblock__add_variable(struct lexblock *self, struct variable *var)
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
{
|
2006-11-20 19:51:42 +01:00
|
|
|
++self->nr_variables;
|
2007-01-03 01:26:01 +01:00
|
|
|
list_add_tail(&var->tag.node, &self->tags);
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
}
|
|
|
|
|
2006-11-20 19:51:42 +01:00
|
|
|
static void lexblock__add_label(struct lexblock *self, struct label *label)
|
2006-11-20 19:17:42 +01:00
|
|
|
{
|
2006-11-20 19:51:42 +01:00
|
|
|
++self->nr_labels;
|
2007-01-03 01:26:01 +01:00
|
|
|
list_add_tail(&label->tag.node, &self->tags);
|
2006-11-20 19:17:42 +01:00
|
|
|
}
|
|
|
|
|
2006-12-07 19:11:47 +01:00
|
|
|
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;
|
|
|
|
|
2007-01-09 13:00:47 +01:00
|
|
|
list_for_each_entry(pos, &self->type.members, tag.node)
|
2006-12-07 19:11:47 +01:00
|
|
|
if (pos == trailer)
|
|
|
|
break;
|
|
|
|
else if (pos->hole >= byte_hole_size ||
|
|
|
|
pos->bit_hole >= bit_hole_size)
|
|
|
|
return pos;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-01-04 04:41:11 +01:00
|
|
|
void class__find_holes(struct class *self, const struct cu *cu)
|
2006-10-28 23:22:42 +02:00
|
|
|
{
|
2007-01-09 13:00:47 +01:00
|
|
|
const struct type *ctype = &self->type;
|
2006-10-28 23:22:42 +02:00
|
|
|
struct class_member *pos, *last = NULL;
|
2006-12-25 01:27:22 +01:00
|
|
|
size_t last_size = 0, size;
|
2006-12-28 14:18:43 +01:00
|
|
|
uint32_t bit_sum = 0;
|
2006-10-28 23:22:42 +02:00
|
|
|
|
|
|
|
self->nr_holes = 0;
|
2006-12-07 16:07:22 +01:00
|
|
|
self->nr_bit_holes = 0;
|
2006-10-28 23:22:42 +02:00
|
|
|
|
2007-01-09 13:00:47 +01:00
|
|
|
list_for_each_entry(pos, &ctype->members, tag.node) {
|
2006-12-14 16:18:07 +01:00
|
|
|
if (last != NULL) {
|
2006-12-25 01:27:22 +01:00
|
|
|
const ssize_t cc_last_size = pos->offset - last->offset;
|
2006-12-14 16:18:07 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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) {
|
2006-12-14 19:49:06 +01:00
|
|
|
/*
|
|
|
|
* 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 (cc_last_size < last_size)
|
|
|
|
last_size = cc_last_size;
|
|
|
|
|
2006-12-14 16:18:07 +01:00
|
|
|
last->hole = cc_last_size - last_size;
|
|
|
|
if (last->hole > 0)
|
|
|
|
++self->nr_holes;
|
2006-10-28 23:22:42 +02:00
|
|
|
|
2006-12-14 16:13:14 +01:00
|
|
|
if (bit_sum != 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
|
|
|
|
2006-12-14 16:13:14 +01:00
|
|
|
bit_sum = 0;
|
|
|
|
}
|
2006-12-14 16:18:07 +01:00
|
|
|
}
|
|
|
|
}
|
[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
|
|
|
|
2006-12-14 16:13:14 +01:00
|
|
|
bit_sum += pos->bit_size;
|
2007-01-04 04:41:11 +01:00
|
|
|
size = class_member__size(pos, cu);
|
2006-12-14 16:18:07 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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)
|
2006-10-28 23:22:42 +02:00
|
|
|
last_size = size;
|
|
|
|
|
2006-12-14 16:18:07 +01:00
|
|
|
last = pos;
|
2006-10-28 23:22:42 +02:00
|
|
|
}
|
|
|
|
|
[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) {
|
2007-01-09 13:00:47 +01:00
|
|
|
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;
|
|
|
|
}
|
2006-10-28 23:22:42 +02:00
|
|
|
}
|
|
|
|
|
2007-01-09 13:00:47 +01:00
|
|
|
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
|
|
|
{
|
2007-01-09 13:00:47 +01:00
|
|
|
if (name != NULL) {
|
|
|
|
struct class_member *pos;
|
|
|
|
list_for_each_entry(pos, &self->members, tag.node)
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2007-01-03 01:26:01 +01:00
|
|
|
static void lexblock__account_inline_expansions(struct lexblock *self,
|
|
|
|
const struct cu *cu)
|
[PFUNCT]: Improve --cu_inline_expansions_stats
Now it shows the number that each of the inline functions were expanded in an
object file:
Top 10 inline functions expanded more than once in kernel/sched.o, by total
size of inline expansions:
[acme@newtoy guinea_pig-2.6]$ pfunct --cu_inline_expansions_stats kernel/sched.o | sort -k3 -nr | grep -v ': 1 ' | head -11
kernel/sched.c: 318 10217
get_current: 38 325
finish_task_switch: 2 238
normal_prio: 2 167
__cpus_and: 14 164
find_process_by_pid: 6 152
current_thread_info: 21 149
sched_find_first_bit: 2 148
update_cpu_clock: 2 140
task_rq_unlock: 14 137
variable_test_bit: 14 121
[acme@newtoy guinea_pig-2.6]$
Now we have these options:
[acme@newtoy guinea_pig-2.6]$ pfunct --help
usage: pfunct [options] <file_name> {<function_name>}
where:
-c, --class=<class> functions that have <class> pointer parameters
-g, --goto_labels show number of goto labels
-i, --show_inline_expansions show inline expansions
-C, --cu_inline_expansions_stats show CU inline expansions stats
-s, --sizes show size of functions
-N, --function_name_len show size of functions
-p, --nr_parameters show number or parameters
-S, --variables show number of variables
-V, --verbose be verbose
[acme@newtoy guinea_pig-2.6]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-03 19:22:12 +01:00
|
|
|
{
|
2007-01-04 00:29:24 +01:00
|
|
|
struct tag *pos, *type;
|
[PFUNCT]: Improve --cu_inline_expansions_stats
Now it shows the number that each of the inline functions were expanded in an
object file:
Top 10 inline functions expanded more than once in kernel/sched.o, by total
size of inline expansions:
[acme@newtoy guinea_pig-2.6]$ pfunct --cu_inline_expansions_stats kernel/sched.o | sort -k3 -nr | grep -v ': 1 ' | head -11
kernel/sched.c: 318 10217
get_current: 38 325
finish_task_switch: 2 238
normal_prio: 2 167
__cpus_and: 14 164
find_process_by_pid: 6 152
current_thread_info: 21 149
sched_find_first_bit: 2 148
update_cpu_clock: 2 140
task_rq_unlock: 14 137
variable_test_bit: 14 121
[acme@newtoy guinea_pig-2.6]$
Now we have these options:
[acme@newtoy guinea_pig-2.6]$ pfunct --help
usage: pfunct [options] <file_name> {<function_name>}
where:
-c, --class=<class> functions that have <class> pointer parameters
-g, --goto_labels show number of goto labels
-i, --show_inline_expansions show inline expansions
-C, --cu_inline_expansions_stats show CU inline expansions stats
-s, --sizes show size of functions
-N, --function_name_len show size of functions
-p, --nr_parameters show number or parameters
-S, --variables show number of variables
-V, --verbose be verbose
[acme@newtoy guinea_pig-2.6]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-03 19:22:12 +01:00
|
|
|
|
2007-01-03 01:26:01 +01:00
|
|
|
if (self->nr_inline_expansions == 0)
|
[PFUNCT]: Improve --cu_inline_expansions_stats
Now it shows the number that each of the inline functions were expanded in an
object file:
Top 10 inline functions expanded more than once in kernel/sched.o, by total
size of inline expansions:
[acme@newtoy guinea_pig-2.6]$ pfunct --cu_inline_expansions_stats kernel/sched.o | sort -k3 -nr | grep -v ': 1 ' | head -11
kernel/sched.c: 318 10217
get_current: 38 325
finish_task_switch: 2 238
normal_prio: 2 167
__cpus_and: 14 164
find_process_by_pid: 6 152
current_thread_info: 21 149
sched_find_first_bit: 2 148
update_cpu_clock: 2 140
task_rq_unlock: 14 137
variable_test_bit: 14 121
[acme@newtoy guinea_pig-2.6]$
Now we have these options:
[acme@newtoy guinea_pig-2.6]$ pfunct --help
usage: pfunct [options] <file_name> {<function_name>}
where:
-c, --class=<class> functions that have <class> pointer parameters
-g, --goto_labels show number of goto labels
-i, --show_inline_expansions show inline expansions
-C, --cu_inline_expansions_stats show CU inline expansions stats
-s, --sizes show size of functions
-N, --function_name_len show size of functions
-p, --nr_parameters show number or parameters
-S, --variables show number of variables
-V, --verbose be verbose
[acme@newtoy guinea_pig-2.6]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-03 19:22:12 +01:00
|
|
|
return;
|
|
|
|
|
2007-01-03 01:26:01 +01:00
|
|
|
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;
|
|
|
|
|
2007-01-04 00:29:24 +01:00
|
|
|
type = cu__find_tag_by_id(cu, pos->type);
|
2006-11-18 17:33:48 +01:00
|
|
|
if (type != NULL) {
|
2007-01-04 00:29:24 +01:00
|
|
|
struct function *ftype = tag__function(type);
|
|
|
|
|
|
|
|
ftype->cu_total_nr_inline_expansions++;
|
|
|
|
ftype->cu_total_size_inline_expansions +=
|
2007-01-03 01:26:01 +01:00
|
|
|
tag__inline_expansion(pos)->size;
|
[PFUNCT]: Improve --cu_inline_expansions_stats
Now it shows the number that each of the inline functions were expanded in an
object file:
Top 10 inline functions expanded more than once in kernel/sched.o, by total
size of inline expansions:
[acme@newtoy guinea_pig-2.6]$ pfunct --cu_inline_expansions_stats kernel/sched.o | sort -k3 -nr | grep -v ': 1 ' | head -11
kernel/sched.c: 318 10217
get_current: 38 325
finish_task_switch: 2 238
normal_prio: 2 167
__cpus_and: 14 164
find_process_by_pid: 6 152
current_thread_info: 21 149
sched_find_first_bit: 2 148
update_cpu_clock: 2 140
task_rq_unlock: 14 137
variable_test_bit: 14 121
[acme@newtoy guinea_pig-2.6]$
Now we have these options:
[acme@newtoy guinea_pig-2.6]$ pfunct --help
usage: pfunct [options] <file_name> {<function_name>}
where:
-c, --class=<class> functions that have <class> pointer parameters
-g, --goto_labels show number of goto labels
-i, --show_inline_expansions show inline expansions
-C, --cu_inline_expansions_stats show CU inline expansions stats
-s, --sizes show size of functions
-N, --function_name_len show size of functions
-p, --nr_parameters show number or parameters
-S, --variables show number of variables
-V, --verbose be verbose
[acme@newtoy guinea_pig-2.6]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-03 19:22:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
2006-11-03 18:38:43 +01:00
|
|
|
|
|
|
|
void cu__account_inline_expansions(struct cu *self)
|
|
|
|
{
|
2007-01-04 00:29:24 +01:00
|
|
|
struct tag *pos;
|
|
|
|
struct function *fpos;
|
2006-11-03 18:38:43 +01:00
|
|
|
|
2007-01-04 00:29:24 +01:00
|
|
|
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;
|
2006-11-03 18:38:43 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-11-20 18:43:39 +01:00
|
|
|
static int tags__compare(const void *a, const void *b)
|
2006-11-03 16:41:19 +01:00
|
|
|
{
|
2006-11-20 18:43:39 +01:00
|
|
|
const struct tag *ta = a, *tb = b;
|
2006-11-03 16:41:19 +01:00
|
|
|
|
2006-11-20 18:43:39 +01:00
|
|
|
if (a == b)
|
|
|
|
return 0;
|
|
|
|
if (ta->decl_line < tb->decl_line)
|
2006-12-14 16:18:07 +01:00
|
|
|
return -1;
|
2006-11-20 18:43:39 +01:00
|
|
|
if (ta->decl_line > tb->decl_line)
|
|
|
|
return 1;
|
|
|
|
if (ta->tag == DW_TAG_inlined_subroutine)
|
|
|
|
return -1;
|
|
|
|
return 1;
|
|
|
|
}
|
2006-11-03 16:41:19 +01:00
|
|
|
|
2006-11-20 18:43:39 +01:00
|
|
|
static void tags__free(void *a)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void tags__add(void *tags, const struct tag *tag)
|
|
|
|
{
|
|
|
|
tsearch(tag, tags, tags__compare);
|
|
|
|
}
|
|
|
|
|
2007-01-03 01:26:01 +01:00
|
|
|
static void function__tag_print(const struct tag *tag, const struct cu *cu,
|
|
|
|
int indent)
|
2006-11-20 18:43:39 +01:00
|
|
|
{
|
|
|
|
char bf[512];
|
|
|
|
const void *vtag = tag;
|
2007-01-03 01:26:01 +01:00
|
|
|
int c;
|
|
|
|
|
|
|
|
if (indent >= sizeof(tabs))
|
|
|
|
indent = sizeof(tabs) - 1;
|
|
|
|
c = indent * 8;
|
2006-11-20 18:43:39 +01:00
|
|
|
|
|
|
|
switch (tag->tag) {
|
|
|
|
case DW_TAG_inlined_subroutine: {
|
|
|
|
const struct inline_expansion *exp = vtag;
|
2007-01-04 00:29:24 +01:00
|
|
|
const struct tag *talias =
|
|
|
|
cu__find_tag_by_id(cu, exp->tag.type);
|
2007-01-07 20:13:39 +01:00
|
|
|
struct function *alias = tag__function(talias);
|
2006-11-20 19:17:42 +01:00
|
|
|
|
2007-01-12 02:09:06 +01:00
|
|
|
if (alias == NULL) {
|
|
|
|
tag__type_not_found(&exp->tag, cu);
|
|
|
|
break;
|
|
|
|
}
|
2007-01-03 01:26:01 +01:00
|
|
|
printf("%.*s", indent, tabs);
|
2006-12-26 14:44:05 +01:00
|
|
|
c += printf("%s(); /* low_pc=%#llx */",
|
2007-01-07 20:13:39 +01:00
|
|
|
function__name(alias, cu), exp->low_pc);
|
2006-11-20 18:43:39 +01:00
|
|
|
}
|
|
|
|
break;
|
2006-11-20 19:17:42 +01:00
|
|
|
case DW_TAG_variable:
|
2007-01-03 01:26:01 +01:00
|
|
|
printf("%.*s", indent, tabs);
|
|
|
|
c += printf("%s %s;", variable__type_name(vtag, cu,
|
|
|
|
bf, sizeof(bf)),
|
|
|
|
variable__name(vtag, cu));
|
2006-11-20 19:17:42 +01:00
|
|
|
break;
|
|
|
|
case DW_TAG_label: {
|
|
|
|
const struct label *label = vtag;
|
2007-01-03 01:26:01 +01:00
|
|
|
printf("%.*s", indent, tabs);
|
2006-11-20 19:17:42 +01:00
|
|
|
putchar('\n');
|
|
|
|
c = printf("%s:", label->name);
|
2006-11-03 16:41:19 +01:00
|
|
|
}
|
2006-11-20 18:43:39 +01:00
|
|
|
break;
|
2007-01-02 16:25:56 +01:00
|
|
|
case DW_TAG_lexical_block:
|
2007-01-03 01:26:01 +01:00
|
|
|
lexblock__print(vtag, cu, indent);
|
2007-01-02 16:25:56 +01:00
|
|
|
return;
|
2006-11-20 18:43:39 +01:00
|
|
|
default:
|
2007-01-03 01:26:01 +01:00
|
|
|
printf("%.*s", indent, tabs);
|
2006-11-20 19:17:42 +01:00
|
|
|
c += printf("%s <%llx>", dwarf_tag_name(tag->tag), tag->id);
|
2006-11-20 18:43:39 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2006-11-20 19:17:42 +01:00
|
|
|
printf("%-*.*s// %5u\n", 70 - c, 70 - c, " ", tag->decl_line);
|
2006-11-03 16:41:19 +01:00
|
|
|
}
|
|
|
|
|
2007-01-13 13:57:19 +01:00
|
|
|
void lexblock__print(const struct lexblock *self, const struct cu *cu,
|
|
|
|
int indent)
|
2006-11-20 18:43:39 +01:00
|
|
|
{
|
|
|
|
struct tag *pos;
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
|
2007-01-03 01:26:01 +01:00
|
|
|
if (indent >= sizeof(tabs))
|
|
|
|
indent = sizeof(tabs) - 1;
|
|
|
|
printf("%.*s{\n", indent, tabs);
|
|
|
|
list_for_each_entry(pos, &self->tags, node)
|
|
|
|
function__tag_print(pos, cu, indent + 1);
|
|
|
|
printf("%.*s}\n", indent, tabs);
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
}
|
|
|
|
|
2007-01-02 06:18:33 +01:00
|
|
|
size_t ftype__snprintf(const struct ftype *self, const struct cu *cu,
|
|
|
|
char *bf, const size_t len,
|
|
|
|
const char *name, const int inlined,
|
|
|
|
const int is_pointer, size_t type_spacing)
|
2006-12-30 19:34:20 +01:00
|
|
|
{
|
|
|
|
struct parameter *pos;
|
|
|
|
struct tag *type = cu__find_tag_by_id(cu, self->tag.type);
|
|
|
|
int first_parm = 1;
|
|
|
|
char *s = bf, sbf[128];
|
|
|
|
size_t l = len;
|
|
|
|
const char *stype = tag__name(type, cu, sbf, sizeof(sbf));
|
2007-01-02 06:18:33 +01:00
|
|
|
size_t n = snprintf(s, l, "%s%-*s %s%s%s%s(", inlined ? "inline " : "",
|
|
|
|
type_spacing, stype,
|
[CLASSES]: Introduce DW_TAG_subroutine_type specific parser
So that we handle DW_TAG_formal_parameters in this tag, fixing
these cases:
--- /tmp/ctracer.c.before 2006-12-29 13:27:24.000000000 -0200
+++ /tmp/ctracer.c 2007-01-02 02:34:18.000000000 -0200
<SNIP>
@@ -62,7 +62,7 @@
}; /* size: 68, cachelines: 3 */
/* last cacheline: 4 bytes */
-typedef int (*kretprobe_handler_t)(void /* FIXME: add parm list */);
+typedef int (*kretprobe_handler_t)(struct kretprobe_instance *, struct pt_regs *);
/* /pub/scm/linux/kernel/git/acme/linux-2.6/include/linux/list.h:607 */
struct hlist_head {
struct hlist_node * first; /* 0 4 */
[acme@newtoy ctracer_example]$
--- /tmp/pfunct.before 2006-12-30 16:18:25.000000000 -0200
+++ /tmp/pfunct.after 2007-01-02 02:08:50.000000000 -0200
@@ -249,7 +249,7 @@
/* definitions: 1 */
/* /pub/scm/linux/kernel/git/acme/linux-2.6/lib/klist.c:57 */
-void klist_init(struct klist * k, * get, * put);
+void klist_init(struct klist * k, void (*get)(struct klist_node *), void (*put)(struct klist_node *));
/* size: 12, inline expansions: 1 (5 bytes) */
/* definitions: 1 */
The struct/union case still needs fixing, but we're getting there...
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-02 05:42:33 +01:00
|
|
|
self->tag.tag == DW_TAG_subroutine_type ? "(" : "",
|
|
|
|
is_pointer ? "*" : "", name ?: "",
|
|
|
|
self->tag.tag == DW_TAG_subroutine_type ? ")" : "");
|
2006-12-30 19:34:20 +01:00
|
|
|
s += n; l -= n;
|
|
|
|
|
|
|
|
list_for_each_entry(pos, &self->parms, tag.node) {
|
2007-01-07 20:57:00 +01:00
|
|
|
const char *name;
|
|
|
|
|
2006-12-30 19:34:20 +01:00
|
|
|
if (!first_parm) {
|
|
|
|
n = snprintf(s, l, ", ");
|
|
|
|
s += n; l -= n;
|
|
|
|
} else
|
|
|
|
first_parm = 0;
|
2007-01-07 20:57:00 +01:00
|
|
|
name = parameter__name(pos, cu);
|
2007-01-12 02:09:06 +01:00
|
|
|
type = cu__find_tag_by_id(cu, parameter__type(pos, cu));
|
|
|
|
if (type == NULL) {
|
|
|
|
stype = "<ERROR>";
|
|
|
|
goto print_it;
|
|
|
|
}
|
[CLASSES]: Introduce DW_TAG_subroutine_type specific parser
So that we handle DW_TAG_formal_parameters in this tag, fixing
these cases:
--- /tmp/ctracer.c.before 2006-12-29 13:27:24.000000000 -0200
+++ /tmp/ctracer.c 2007-01-02 02:34:18.000000000 -0200
<SNIP>
@@ -62,7 +62,7 @@
}; /* size: 68, cachelines: 3 */
/* last cacheline: 4 bytes */
-typedef int (*kretprobe_handler_t)(void /* FIXME: add parm list */);
+typedef int (*kretprobe_handler_t)(struct kretprobe_instance *, struct pt_regs *);
/* /pub/scm/linux/kernel/git/acme/linux-2.6/include/linux/list.h:607 */
struct hlist_head {
struct hlist_node * first; /* 0 4 */
[acme@newtoy ctracer_example]$
--- /tmp/pfunct.before 2006-12-30 16:18:25.000000000 -0200
+++ /tmp/pfunct.after 2007-01-02 02:08:50.000000000 -0200
@@ -249,7 +249,7 @@
/* definitions: 1 */
/* /pub/scm/linux/kernel/git/acme/linux-2.6/lib/klist.c:57 */
-void klist_init(struct klist * k, * get, * put);
+void klist_init(struct klist * k, void (*get)(struct klist_node *), void (*put)(struct klist_node *));
/* size: 12, inline expansions: 1 (5 bytes) */
/* definitions: 1 */
The struct/union case still needs fixing, but we're getting there...
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-02 05:42:33 +01:00
|
|
|
if (type->tag == DW_TAG_pointer_type) {
|
|
|
|
if (type->type != 0) {
|
|
|
|
struct tag *ptype =
|
|
|
|
cu__find_tag_by_id(cu, type->type);
|
2007-01-12 19:34:53 +01:00
|
|
|
if (ptype == NULL) {
|
|
|
|
n = snprintf(s, l, ">>>ERROR: "
|
|
|
|
"type for %s not found!",
|
|
|
|
name);
|
|
|
|
goto next;
|
|
|
|
}
|
[CLASSES]: Introduce DW_TAG_subroutine_type specific parser
So that we handle DW_TAG_formal_parameters in this tag, fixing
these cases:
--- /tmp/ctracer.c.before 2006-12-29 13:27:24.000000000 -0200
+++ /tmp/ctracer.c 2007-01-02 02:34:18.000000000 -0200
<SNIP>
@@ -62,7 +62,7 @@
}; /* size: 68, cachelines: 3 */
/* last cacheline: 4 bytes */
-typedef int (*kretprobe_handler_t)(void /* FIXME: add parm list */);
+typedef int (*kretprobe_handler_t)(struct kretprobe_instance *, struct pt_regs *);
/* /pub/scm/linux/kernel/git/acme/linux-2.6/include/linux/list.h:607 */
struct hlist_head {
struct hlist_node * first; /* 0 4 */
[acme@newtoy ctracer_example]$
--- /tmp/pfunct.before 2006-12-30 16:18:25.000000000 -0200
+++ /tmp/pfunct.after 2007-01-02 02:08:50.000000000 -0200
@@ -249,7 +249,7 @@
/* definitions: 1 */
/* /pub/scm/linux/kernel/git/acme/linux-2.6/lib/klist.c:57 */
-void klist_init(struct klist * k, * get, * put);
+void klist_init(struct klist * k, void (*get)(struct klist_node *), void (*put)(struct klist_node *));
/* size: 12, inline expansions: 1 (5 bytes) */
/* definitions: 1 */
The struct/union case still needs fixing, but we're getting there...
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-02 05:42:33 +01:00
|
|
|
if (ptype->tag == DW_TAG_subroutine_type) {
|
|
|
|
n = ftype__snprintf(tag__ftype(ptype),
|
|
|
|
cu, s, l,
|
2007-01-07 20:57:00 +01:00
|
|
|
name, 0, 1, 0);
|
[CLASSES]: Introduce DW_TAG_subroutine_type specific parser
So that we handle DW_TAG_formal_parameters in this tag, fixing
these cases:
--- /tmp/ctracer.c.before 2006-12-29 13:27:24.000000000 -0200
+++ /tmp/ctracer.c 2007-01-02 02:34:18.000000000 -0200
<SNIP>
@@ -62,7 +62,7 @@
}; /* size: 68, cachelines: 3 */
/* last cacheline: 4 bytes */
-typedef int (*kretprobe_handler_t)(void /* FIXME: add parm list */);
+typedef int (*kretprobe_handler_t)(struct kretprobe_instance *, struct pt_regs *);
/* /pub/scm/linux/kernel/git/acme/linux-2.6/include/linux/list.h:607 */
struct hlist_head {
struct hlist_node * first; /* 0 4 */
[acme@newtoy ctracer_example]$
--- /tmp/pfunct.before 2006-12-30 16:18:25.000000000 -0200
+++ /tmp/pfunct.after 2007-01-02 02:08:50.000000000 -0200
@@ -249,7 +249,7 @@
/* definitions: 1 */
/* /pub/scm/linux/kernel/git/acme/linux-2.6/lib/klist.c:57 */
-void klist_init(struct klist * k, * get, * put);
+void klist_init(struct klist * k, void (*get)(struct klist_node *), void (*put)(struct klist_node *));
/* size: 12, inline expansions: 1 (5 bytes) */
/* definitions: 1 */
The struct/union case still needs fixing, but we're getting there...
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-02 05:42:33 +01:00
|
|
|
goto next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (type->tag == DW_TAG_subroutine_type) {
|
|
|
|
n = ftype__snprintf(tag__ftype(type), cu, s, l,
|
2007-01-07 20:57:00 +01:00
|
|
|
name, 0, 0, 0);
|
[CLASSES]: Introduce DW_TAG_subroutine_type specific parser
So that we handle DW_TAG_formal_parameters in this tag, fixing
these cases:
--- /tmp/ctracer.c.before 2006-12-29 13:27:24.000000000 -0200
+++ /tmp/ctracer.c 2007-01-02 02:34:18.000000000 -0200
<SNIP>
@@ -62,7 +62,7 @@
}; /* size: 68, cachelines: 3 */
/* last cacheline: 4 bytes */
-typedef int (*kretprobe_handler_t)(void /* FIXME: add parm list */);
+typedef int (*kretprobe_handler_t)(struct kretprobe_instance *, struct pt_regs *);
/* /pub/scm/linux/kernel/git/acme/linux-2.6/include/linux/list.h:607 */
struct hlist_head {
struct hlist_node * first; /* 0 4 */
[acme@newtoy ctracer_example]$
--- /tmp/pfunct.before 2006-12-30 16:18:25.000000000 -0200
+++ /tmp/pfunct.after 2007-01-02 02:08:50.000000000 -0200
@@ -249,7 +249,7 @@
/* definitions: 1 */
/* /pub/scm/linux/kernel/git/acme/linux-2.6/lib/klist.c:57 */
-void klist_init(struct klist * k, * get, * put);
+void klist_init(struct klist * k, void (*get)(struct klist_node *), void (*put)(struct klist_node *));
/* size: 12, inline expansions: 1 (5 bytes) */
/* definitions: 1 */
The struct/union case still needs fixing, but we're getting there...
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-02 05:42:33 +01:00
|
|
|
goto next;
|
|
|
|
}
|
2007-01-12 02:09:06 +01:00
|
|
|
print_it:
|
2006-12-30 19:34:20 +01:00
|
|
|
stype = tag__name(type, cu, sbf, sizeof(sbf));
|
[CLASSES]: Introduce DW_TAG_subroutine_type specific parser
So that we handle DW_TAG_formal_parameters in this tag, fixing
these cases:
--- /tmp/ctracer.c.before 2006-12-29 13:27:24.000000000 -0200
+++ /tmp/ctracer.c 2007-01-02 02:34:18.000000000 -0200
<SNIP>
@@ -62,7 +62,7 @@
}; /* size: 68, cachelines: 3 */
/* last cacheline: 4 bytes */
-typedef int (*kretprobe_handler_t)(void /* FIXME: add parm list */);
+typedef int (*kretprobe_handler_t)(struct kretprobe_instance *, struct pt_regs *);
/* /pub/scm/linux/kernel/git/acme/linux-2.6/include/linux/list.h:607 */
struct hlist_head {
struct hlist_node * first; /* 0 4 */
[acme@newtoy ctracer_example]$
--- /tmp/pfunct.before 2006-12-30 16:18:25.000000000 -0200
+++ /tmp/pfunct.after 2007-01-02 02:08:50.000000000 -0200
@@ -249,7 +249,7 @@
/* definitions: 1 */
/* /pub/scm/linux/kernel/git/acme/linux-2.6/lib/klist.c:57 */
-void klist_init(struct klist * k, * get, * put);
+void klist_init(struct klist * k, void (*get)(struct klist_node *), void (*put)(struct klist_node *));
/* size: 12, inline expansions: 1 (5 bytes) */
/* definitions: 1 */
The struct/union case still needs fixing, but we're getting there...
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-02 05:42:33 +01:00
|
|
|
n = snprintf(s, l, "%s%s%s", stype,
|
2007-01-07 20:57:00 +01:00
|
|
|
name ? " " : "", name ?: "");
|
[CLASSES]: Introduce DW_TAG_subroutine_type specific parser
So that we handle DW_TAG_formal_parameters in this tag, fixing
these cases:
--- /tmp/ctracer.c.before 2006-12-29 13:27:24.000000000 -0200
+++ /tmp/ctracer.c 2007-01-02 02:34:18.000000000 -0200
<SNIP>
@@ -62,7 +62,7 @@
}; /* size: 68, cachelines: 3 */
/* last cacheline: 4 bytes */
-typedef int (*kretprobe_handler_t)(void /* FIXME: add parm list */);
+typedef int (*kretprobe_handler_t)(struct kretprobe_instance *, struct pt_regs *);
/* /pub/scm/linux/kernel/git/acme/linux-2.6/include/linux/list.h:607 */
struct hlist_head {
struct hlist_node * first; /* 0 4 */
[acme@newtoy ctracer_example]$
--- /tmp/pfunct.before 2006-12-30 16:18:25.000000000 -0200
+++ /tmp/pfunct.after 2007-01-02 02:08:50.000000000 -0200
@@ -249,7 +249,7 @@
/* definitions: 1 */
/* /pub/scm/linux/kernel/git/acme/linux-2.6/lib/klist.c:57 */
-void klist_init(struct klist * k, * get, * put);
+void klist_init(struct klist * k, void (*get)(struct klist_node *), void (*put)(struct klist_node *));
/* size: 12, inline expansions: 1 (5 bytes) */
/* definitions: 1 */
The struct/union case still needs fixing, but we're getting there...
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-02 05:42:33 +01:00
|
|
|
next:
|
2006-12-30 19:34:20 +01:00
|
|
|
s += n; l -= n;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No parameters? */
|
[CLASSES]: Introduce DW_TAG_subroutine_type specific parser
So that we handle DW_TAG_formal_parameters in this tag, fixing
these cases:
--- /tmp/ctracer.c.before 2006-12-29 13:27:24.000000000 -0200
+++ /tmp/ctracer.c 2007-01-02 02:34:18.000000000 -0200
<SNIP>
@@ -62,7 +62,7 @@
}; /* size: 68, cachelines: 3 */
/* last cacheline: 4 bytes */
-typedef int (*kretprobe_handler_t)(void /* FIXME: add parm list */);
+typedef int (*kretprobe_handler_t)(struct kretprobe_instance *, struct pt_regs *);
/* /pub/scm/linux/kernel/git/acme/linux-2.6/include/linux/list.h:607 */
struct hlist_head {
struct hlist_node * first; /* 0 4 */
[acme@newtoy ctracer_example]$
--- /tmp/pfunct.before 2006-12-30 16:18:25.000000000 -0200
+++ /tmp/pfunct.after 2007-01-02 02:08:50.000000000 -0200
@@ -249,7 +249,7 @@
/* definitions: 1 */
/* /pub/scm/linux/kernel/git/acme/linux-2.6/lib/klist.c:57 */
-void klist_init(struct klist * k, * get, * put);
+void klist_init(struct klist * k, void (*get)(struct klist_node *), void (*put)(struct klist_node *));
/* size: 12, inline expansions: 1 (5 bytes) */
/* definitions: 1 */
The struct/union case still needs fixing, but we're getting there...
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-02 05:42:33 +01:00
|
|
|
if (first_parm)
|
|
|
|
n = snprintf(s, l, "void)");
|
|
|
|
else if (self->unspec_parms)
|
|
|
|
n = snprintf(s, l, ", ...)");
|
|
|
|
else
|
|
|
|
n = snprintf(s, l, ")");
|
|
|
|
return len - (l - n);
|
2006-12-30 19:34:20 +01:00
|
|
|
}
|
|
|
|
|
2007-01-12 19:25:20 +01:00
|
|
|
static void function__print(const struct tag *tag_self, const struct cu *cu)
|
2006-10-28 23:49:27 +02:00
|
|
|
{
|
2007-01-12 18:47:26 +01:00
|
|
|
struct function *self = tag__function(tag_self);
|
2006-12-30 19:34:20 +01:00
|
|
|
char bf[2048];
|
2006-10-28 23:49:27 +02:00
|
|
|
|
2007-01-04 00:57:35 +01:00
|
|
|
ftype__snprintf(&self->proto, cu, bf, sizeof(bf),
|
2007-01-07 20:13:39 +01:00
|
|
|
function__name(self, cu),
|
|
|
|
function__declared_inline(self), 0, 0);
|
2006-12-30 19:34:20 +01:00
|
|
|
fputs(bf, stdout);
|
2007-01-12 19:00:07 +01:00
|
|
|
}
|
2006-11-20 18:43:39 +01:00
|
|
|
|
2007-01-12 19:00:07 +01:00
|
|
|
void function__print_stats(const struct tag *tag_self, const struct cu *cu)
|
|
|
|
{
|
|
|
|
struct function *self = tag__function(tag_self);
|
|
|
|
char bf[2048];
|
|
|
|
struct tag *class_type;
|
|
|
|
const char *type = "<ERROR>";
|
|
|
|
|
|
|
|
lexblock__print(&self->lexblock, cu, 0);
|
|
|
|
|
|
|
|
printf("/* size: %u", function__size(self));
|
|
|
|
if (self->lexblock.nr_variables > 0)
|
|
|
|
printf(", variables: %u", self->lexblock.nr_variables);
|
|
|
|
if (self->lexblock.nr_labels > 0)
|
|
|
|
printf(", goto labels: %u", self->lexblock.nr_labels);
|
|
|
|
if (self->lexblock.nr_inline_expansions > 0)
|
|
|
|
printf(", inline expansions: %u (%u bytes)",
|
|
|
|
self->lexblock.nr_inline_expansions,
|
|
|
|
self->lexblock.size_inline_expansions);
|
|
|
|
fputs(" */\n", stdout);
|
2006-10-28 23:49:27 +02:00
|
|
|
}
|
|
|
|
|
2007-01-10 19:39:20 +01:00
|
|
|
static size_t class__snprintf_cacheline_boundary(char *bf, size_t len,
|
|
|
|
uint32_t last_cacheline,
|
|
|
|
size_t sum, size_t sum_holes,
|
|
|
|
uint8_t *newline,
|
[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
|
|
|
uint32_t *cacheline,
|
2007-01-13 13:40:33 +01:00
|
|
|
size_t indent)
|
2006-12-07 22:20:46 +01:00
|
|
|
{
|
2007-01-10 19:39:20 +01:00
|
|
|
size_t l = len;
|
2006-12-25 01:27:22 +01:00
|
|
|
const size_t real_sum = sum + sum_holes;
|
2006-12-07 22:20:46 +01:00
|
|
|
|
2007-01-10 19:39:20 +01:00
|
|
|
*cacheline = real_sum / cacheline_size;
|
|
|
|
|
|
|
|
if (*cacheline > last_cacheline) {
|
2006-12-28 14:18:43 +01:00
|
|
|
const uint32_t cacheline_pos = real_sum % cacheline_size;
|
|
|
|
const uint32_t cacheline_in_bytes = real_sum - cacheline_pos;
|
2007-01-10 19:39:20 +01:00
|
|
|
size_t n;
|
2006-12-14 19:49:06 +01:00
|
|
|
|
|
|
|
if (*newline) {
|
2007-01-10 19:39:20 +01:00
|
|
|
n = snprintf(bf, l, "\n");
|
|
|
|
bf += n; l -= n;
|
2006-12-14 19:49:06 +01:00
|
|
|
*newline = 0;
|
|
|
|
}
|
|
|
|
|
2007-01-13 13:40:33 +01:00
|
|
|
n = snprintf(bf, l, "%.*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
|
|
|
bf += n; l -= n;
|
|
|
|
|
2006-12-07 22:20:46 +01:00
|
|
|
if (cacheline_pos == 0)
|
[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
|
|
|
n = snprintf(bf, len, "/* --- cacheline "
|
2007-01-10 19:39:20 +01:00
|
|
|
"%u boundary (%u bytes) --- */\n",
|
|
|
|
*cacheline, cacheline_in_bytes);
|
2006-12-07 22:20:46 +01:00
|
|
|
else
|
[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
|
|
|
n = snprintf(bf, len, "/* --- cacheline "
|
2007-01-10 19:39:20 +01:00
|
|
|
"%u boundary (%u bytes) was %u "
|
|
|
|
"bytes ago --- */\n",
|
|
|
|
*cacheline, cacheline_in_bytes,
|
|
|
|
cacheline_pos);
|
|
|
|
bf += n; l -= n;
|
2006-12-07 22:20:46 +01:00
|
|
|
}
|
|
|
|
|
2007-01-10 19:39:20 +01:00
|
|
|
return len - l;
|
2006-12-07 22:20:46 +01:00
|
|
|
}
|
|
|
|
|
2007-01-10 19:39:20 +01:00
|
|
|
static size_t class__snprintf(const struct class *self, const struct cu *cu,
|
|
|
|
char *bf, size_t len,
|
|
|
|
const char *prefix, const char *suffix,
|
2007-01-13 13:40:33 +01:00
|
|
|
uint8_t indent, size_t type_spacing,
|
[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
|
|
|
size_t name_spacing, int emit_stats)
|
2006-10-28 23:22:42 +02:00
|
|
|
{
|
[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 char *orig_bf = bf;
|
2007-01-10 19:39:20 +01:00
|
|
|
const struct type *tself = &self->type;
|
2006-12-25 01:27:22 +01:00
|
|
|
size_t last_size = 0, size;
|
|
|
|
size_t last_bit_size = 0;
|
2006-12-14 19:00:28 +01:00
|
|
|
uint8_t newline = 0;
|
2007-01-10 19:39:20 +01:00
|
|
|
uint32_t sum = 0;
|
|
|
|
uint32_t sum_holes = 0;
|
2006-12-28 14:18:43 +01:00
|
|
|
uint32_t sum_bit_holes = 0;
|
2007-01-10 19:39:20 +01:00
|
|
|
uint32_t last_cacheline = 0;
|
|
|
|
int last_offset = -1;
|
|
|
|
struct class_member *pos;
|
|
|
|
size_t l = len;
|
|
|
|
size_t n = snprintf(bf, l, "%s%sstruct%s%s {\n",
|
|
|
|
prefix ?: "", prefix ? " " : "",
|
|
|
|
tself->name ? " " : "", tself->name ?: "");
|
2006-10-28 23:22:42 +02:00
|
|
|
|
2007-01-10 19:39:20 +01:00
|
|
|
bf += n; l -= n;
|
|
|
|
|
2007-01-13 13:40:33 +01:00
|
|
|
if (indent >= 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
|
|
|
|
2007-01-10 19:39:20 +01:00
|
|
|
list_for_each_entry(pos, &tself->members, tag.node) {
|
[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;
|
2006-12-25 01:27:22 +01:00
|
|
|
const ssize_t cc_last_size = pos->offset - last_offset;
|
2006-12-14 19:49:06 +01:00
|
|
|
|
2007-01-10 19:39:20 +01:00
|
|
|
n = class__snprintf_cacheline_boundary(bf, l, last_cacheline,
|
|
|
|
sum, sum_holes,
|
|
|
|
&newline,
|
[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
|
|
|
&last_cacheline,
|
2007-01-13 13:40:33 +01:00
|
|
|
indent + 1);
|
2007-01-10 19:39:20 +01:00
|
|
|
bf += n; l -= n;
|
2006-12-14 19:49:06 +01:00
|
|
|
|
|
|
|
if (last_offset != -1) {
|
|
|
|
if (cc_last_size < last_size && cc_last_size > 0) {
|
[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++) {
|
|
|
|
n = snprintf(bf, l, "\n");
|
|
|
|
bf += n; l -= n;
|
|
|
|
}
|
|
|
|
n = snprintf(bf, l, "%.*s/* Bitfield "
|
2007-01-10 19:39:20 +01:00
|
|
|
"WARNING: DWARF "
|
|
|
|
"size=%u, real size=%u */\n",
|
2007-01-13 13:40:33 +01:00
|
|
|
indent + 1, tabs,
|
2007-01-10 19:39:20 +01:00
|
|
|
last_size, cc_last_size);
|
|
|
|
bf += n; l -= n;
|
2006-12-14 19:49:06 +01:00
|
|
|
sum -= last_size - cc_last_size;
|
|
|
|
/*
|
|
|
|
* Confusing huh? think about this case then,
|
|
|
|
* should clarify:
|
|
|
|
*/
|
|
|
|
#if 0
|
|
|
|
struct foo {
|
|
|
|
int a:1; /* 0 4 */
|
|
|
|
|
|
|
|
/* XXX 7 bits hole, try to pack */
|
|
|
|
/* WARNING: DWARF size: 4, compiler size: 1 */
|
|
|
|
|
|
|
|
char b; /* 1 1 */
|
|
|
|
}; /* size: 4, cachelines: 1 */
|
|
|
|
/* bit holes: 1, sum bit holes: 7 bits */
|
|
|
|
/* padding: 2 */
|
|
|
|
/* last cacheline: 4 bytes */
|
|
|
|
#endif
|
|
|
|
/*
|
|
|
|
* Yeah, this could somehow be simplified,
|
|
|
|
* send me a patch 8-)
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-14 19:00:28 +01:00
|
|
|
if (newline) {
|
2007-01-10 19:39:20 +01:00
|
|
|
n = snprintf(bf, l, "\n");
|
|
|
|
bf += n; l -= n;
|
2006-12-14 19:00:28 +01:00
|
|
|
newline = 0;
|
|
|
|
}
|
|
|
|
|
[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);
|
2007-01-12 02:09:06 +01:00
|
|
|
if (type == NULL) {
|
|
|
|
tag__type_not_found(&pos->tag, cu);
|
|
|
|
n = snprintf(bf, l,
|
|
|
|
"%.*s>>>ERROR: type for %s not found!\n",
|
2007-01-13 13:40:33 +01:00
|
|
|
indent + 1, tabs, pos->name);
|
2007-01-12 02:09:06 +01:00
|
|
|
bf += n; l -= n;
|
|
|
|
continue;
|
|
|
|
}
|
2007-01-10 19:39:20 +01:00
|
|
|
size = tag__size(type, cu);
|
2007-01-13 13:40:33 +01:00
|
|
|
n = snprintf(bf, l, "%.*s", indent + 1, 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
|
|
|
bf += n; l -= n;
|
2007-01-13 13:40:33 +01:00
|
|
|
n = struct_member__snprintf(pos, type, cu, bf, l, indent + 1,
|
2007-01-10 19:39:20 +01:00
|
|
|
type_spacing, name_spacing);
|
|
|
|
bf += n; l -= n;
|
2006-12-07 16:07:22 +01:00
|
|
|
|
|
|
|
if (pos->bit_hole != 0) {
|
2007-01-10 19:39:20 +01:00
|
|
|
if (!newline++) {
|
|
|
|
n = snprintf(bf, l, "\n");
|
|
|
|
bf += n; l -= n;
|
|
|
|
}
|
[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
|
|
|
n = snprintf(bf, l, "\n%.*s/* XXX %d bit%s hole, "
|
2007-01-13 13:40:33 +01:00
|
|
|
"try to pack */", indent + 1, 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
|
|
|
pos->bit_hole,
|
2007-01-10 19:39:20 +01:00
|
|
|
pos->bit_hole != 1 ? "s" : "");
|
|
|
|
bf += n; l -= n;
|
2006-12-07 16:07:22 +01:00
|
|
|
sum_bit_holes += pos->bit_hole;
|
|
|
|
}
|
|
|
|
|
2006-12-06 18:09:36 +01:00
|
|
|
if (pos->hole > 0) {
|
2007-01-10 19:39:20 +01:00
|
|
|
if (!newline++) {
|
|
|
|
n = snprintf(bf, l, "\n");
|
|
|
|
bf += n; l -= n;
|
|
|
|
}
|
[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
|
|
|
|
|
|
|
n = snprintf(bf, l, "\n%.*s/* XXX %d byte%s "
|
2007-01-13 13:40:33 +01:00
|
|
|
"hole, try to pack */", indent + 1, tabs,
|
2007-01-10 19:39:20 +01:00
|
|
|
pos->hole, pos->hole != 1 ? "s" : "");
|
|
|
|
bf += n; l -= n;
|
2006-10-28 23:22:42 +02:00
|
|
|
sum_holes += pos->hole;
|
2006-12-06 18:09:36 +01:00
|
|
|
}
|
2006-12-07 16:07:22 +01:00
|
|
|
|
2007-01-10 19:39:20 +01:00
|
|
|
n = snprintf(bf, l, "\n");
|
|
|
|
bf += n; l -= n;
|
2006-12-06 18:09:36 +01:00
|
|
|
/*
|
|
|
|
* check for bitfields, accounting for only the biggest
|
|
|
|
* of the byte_size in the fields in each bitfield set.
|
|
|
|
*/
|
|
|
|
if (last_offset != pos->offset ||
|
|
|
|
pos->bit_size == 0 || last_bit_size == 0) {
|
|
|
|
last_size = size;
|
|
|
|
sum += last_size;
|
|
|
|
} else if (size > last_size) {
|
2006-10-28 23:22:42 +02:00
|
|
|
sum += size - last_size;
|
|
|
|
last_size = size;
|
2006-12-06 18:09:36 +01:00
|
|
|
}
|
2006-10-28 23:22:42 +02:00
|
|
|
|
2006-12-06 18:09:36 +01:00
|
|
|
last_offset = pos->offset;
|
|
|
|
last_bit_size = pos->bit_size;
|
2006-10-28 23:22:42 +02:00
|
|
|
}
|
|
|
|
|
2007-01-10 19:39:20 +01:00
|
|
|
n = class__snprintf_cacheline_boundary(bf, l, last_cacheline, sum,
|
|
|
|
sum_holes, &newline,
|
2007-01-13 13:40:33 +01:00
|
|
|
&last_cacheline, indent + 1);
|
2007-01-10 19:39:20 +01:00
|
|
|
bf += n; l -= n;
|
[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
|
|
|
n = snprintf(bf, l, "%.*s}%s%s",
|
2007-01-13 13:40:33 +01:00
|
|
|
indent, tabs, suffix ? " ": "", suffix ?: "");
|
[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
|
|
|
bf += n; l -= n;
|
|
|
|
|
|
|
|
if (!emit_stats)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
n = snprintf(bf, l, "; /* size: %u, cachelines: %u */\n", tself->size,
|
2007-01-10 19:39:20 +01:00
|
|
|
(tself->size + cacheline_size - 1) / cacheline_size);
|
|
|
|
bf += n; l -= n;
|
|
|
|
if (sum_holes > 0) {
|
[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
|
|
|
n = snprintf(bf, l, "%.*s /* sum members: %lu, "
|
2007-01-13 13:40:33 +01:00
|
|
|
"holes: %d, sum holes: %lu */\n", indent, tabs,
|
2007-01-10 19:39:20 +01:00
|
|
|
sum, self->nr_holes, sum_holes);
|
|
|
|
bf += n; l -= n;
|
|
|
|
}
|
|
|
|
if (sum_bit_holes > 0) {
|
[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
|
|
|
n = snprintf(bf, l, "%.*s /* bit holes: %d, sum "
|
2007-01-13 13:40:33 +01:00
|
|
|
"bit holes: %u bits */\n", indent, tabs,
|
[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
|
|
|
self->nr_bit_holes, sum_bit_holes);
|
2007-01-10 19:39:20 +01:00
|
|
|
bf += n; l -= n;
|
|
|
|
}
|
|
|
|
if (self->padding > 0) {
|
2007-01-13 13:40:33 +01:00
|
|
|
n = snprintf(bf, l, "%.*s /* padding: %u */\n", 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
|
|
|
self->padding);
|
2007-01-10 19:39:20 +01:00
|
|
|
bf += n; l -= n;
|
|
|
|
}
|
|
|
|
if (self->bit_padding > 0) {
|
[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
|
|
|
n = snprintf(bf, l, "%.*s /* bit_padding: %u bits */\n",
|
2007-01-13 13:40:33 +01:00
|
|
|
indent, tabs, self->bit_padding);
|
2007-01-10 19:39:20 +01:00
|
|
|
bf += n; l -= n;
|
|
|
|
}
|
2007-01-09 13:00:47 +01:00
|
|
|
last_cacheline = tself->size % cacheline_size;
|
2007-01-10 19:39:20 +01:00
|
|
|
if (last_cacheline != 0) {
|
[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
|
|
|
n = snprintf(bf, l, "%.*s /* last cacheline: %u bytes */\n",
|
2007-01-13 13:40:33 +01:00
|
|
|
indent, tabs, last_cacheline);
|
2007-01-10 19:39:20 +01:00
|
|
|
bf += n; l -= n;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sum + sum_holes != tself->size - self->padding) {
|
[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
|
|
|
n = snprintf(bf, l, "\n%.*s/* BRAIN FART ALERT! %u != "
|
2007-01-13 13:40:33 +01:00
|
|
|
"%u + %u(holes), diff = %u */\n\n", indent, tabs,
|
2007-01-10 19:39:20 +01:00
|
|
|
tself->size, sum, sum_holes,
|
|
|
|
tself->size - (sum + sum_holes));
|
|
|
|
bf += n; l -= n;
|
|
|
|
}
|
[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:
|
2007-01-10 19:39:20 +01:00
|
|
|
return len - l;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void class__print(const struct tag *tag, const struct cu *cu,
|
|
|
|
const char *prefix, const char *suffix)
|
|
|
|
{
|
|
|
|
char bf[32768];
|
|
|
|
|
|
|
|
class__snprintf(tag__class(tag), cu, bf, sizeof(bf),
|
[LIB]: Pass prefix and suffix to class__snprintf in class__print
Fixing a regression introduced when doing the class__snprintf introduction out
of class__print, namely this one:
--- ctracer_sock.c.old 2007-01-12 14:57:56.000000000 -0200
+++ ctracer.c 2007-01-12 15:00:21.000000000 -0200
@@ -1668,7 +1668,7 @@
};
/* /pub/scm/linux/kernel/git/acme/linux-2.6/include/linux/fs.h:1050 */
-struct {
+typedef struct {
size_t written; /* 0 4 */
size_t count; /* 4 4 */
union {
@@ -1676,7 +1676,7 @@
void * data; /* 4 */
} arg; /* 8 4 */
int error; /* 12 4 */
-}; /* size: 16, cachelines: 1 */
+} read_descriptor_t; /* size: 16, cachelines: 1 */
/* last cacheline: 16 bytes */
typedef int (*sk_read_actor_t)(read_descriptor_t *, struct sk_buff *, unsigned int, size_t);
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-12 18:03:59 +01:00
|
|
|
prefix, suffix, 0, 26, 23, 1);
|
2007-01-10 19:39:20 +01:00
|
|
|
fputs(bf, stdout);
|
2006-10-28 23:22:42 +02:00
|
|
|
}
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
void tag__print(const struct tag *self, const struct cu *cu,
|
|
|
|
const char *prefix, const char *suffix)
|
2006-10-28 23:22:42 +02:00
|
|
|
{
|
2007-01-12 19:11:37 +01:00
|
|
|
tag__print_decl_info(self);
|
2006-10-29 00:13:27 +02:00
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
switch (self->tag) {
|
2007-01-12 18:24:41 +01:00
|
|
|
case DW_TAG_enumeration_type:
|
|
|
|
enumeration__print(self, NULL, 0);
|
|
|
|
break;
|
2007-01-12 18:13:38 +01:00
|
|
|
case DW_TAG_typedef:
|
|
|
|
typedef__print(self, cu);
|
|
|
|
break;
|
2006-10-28 23:22:42 +02:00
|
|
|
case DW_TAG_structure_type:
|
2007-01-10 17:27:03 +01:00
|
|
|
class__print(self, cu, prefix, suffix);
|
2006-10-28 23:22:42 +02:00
|
|
|
break;
|
2007-01-12 19:19:13 +01:00
|
|
|
case DW_TAG_subprogram:
|
|
|
|
function__print(self, cu);
|
|
|
|
break;
|
2007-01-12 21:00:32 +01:00
|
|
|
case DW_TAG_union_type:
|
|
|
|
union__print(self, cu, suffix);
|
|
|
|
break;
|
2006-10-28 23:22:42 +02:00
|
|
|
default:
|
2006-12-29 18:28:58 +01:00
|
|
|
printf("%s: %s tag not supported!\n", __FUNCTION__,
|
|
|
|
dwarf_tag_name(self->tag));
|
2006-10-28 23:22:42 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
int cu__for_each_tag(struct cu *self,
|
|
|
|
int (*iterator)(struct tag *tag, struct cu *cu,
|
|
|
|
void *cookie),
|
|
|
|
void *cookie,
|
2007-01-04 00:29:24 +01:00
|
|
|
struct tag *(*filter)(struct tag *tag, struct cu *cu,
|
|
|
|
void *cookie))
|
2006-10-29 03:55:56 +01:00
|
|
|
{
|
2006-12-29 18:28:58 +01:00
|
|
|
struct tag *pos;
|
2006-10-31 20:12:42 +01:00
|
|
|
|
2007-01-04 00:29:24 +01:00
|
|
|
list_for_each_entry(pos, &self->tags, node) {
|
2006-12-29 18:28:58 +01:00
|
|
|
struct tag *tag = pos;
|
2006-12-01 03:00:24 +01:00
|
|
|
if (filter != NULL) {
|
2007-01-04 00:29:24 +01:00
|
|
|
tag = filter(pos, self, cookie);
|
2006-12-29 18:28:58 +01:00
|
|
|
if (tag == NULL)
|
2006-12-01 03:00:24 +01:00
|
|
|
continue;
|
|
|
|
}
|
2006-12-29 18:28:58 +01:00
|
|
|
if (iterator(tag, self, cookie))
|
2006-10-31 21:23:16 +01:00
|
|
|
return 1;
|
2006-12-01 03:00:24 +01:00
|
|
|
}
|
2006-10-31 21:23:16 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-11-11 19:31:04 +01:00
|
|
|
void cus__for_each_cu(struct cus *self,
|
|
|
|
int (*iterator)(struct cu *cu, void *cookie),
|
2006-12-01 02:48:34 +01:00
|
|
|
void *cookie,
|
|
|
|
struct cu *(*filter)(struct cu *cu))
|
2006-10-31 21:23:16 +01:00
|
|
|
{
|
|
|
|
struct cu *pos;
|
|
|
|
|
2006-12-01 02:48:34 +01:00
|
|
|
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))
|
2006-10-31 21:23:16 +01:00
|
|
|
break;
|
2006-12-01 02:48:34 +01:00
|
|
|
}
|
2006-10-29 03:55:56 +01:00
|
|
|
}
|
|
|
|
|
2006-10-28 23:22:42 +02:00
|
|
|
static void oom(const char *msg)
|
|
|
|
{
|
2007-01-02 21:02:08 +01:00
|
|
|
fprintf(stderr, "libclasses: out of memory(%s)\n", msg);
|
2006-10-28 23:22:42 +02:00
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
2006-11-11 17:15:50 +01:00
|
|
|
static uint64_t attr_upper_bound(Dwarf_Die *die)
|
2006-10-28 23:22:42 +02:00
|
|
|
{
|
|
|
|
Dwarf_Attribute attr;
|
|
|
|
|
|
|
|
if (dwarf_attr(die, DW_AT_upper_bound, &attr) != NULL) {
|
2006-12-14 16:18:07 +01:00
|
|
|
Dwarf_Word num;
|
2006-10-28 23:22:42 +02:00
|
|
|
|
|
|
|
if (dwarf_formudata(&attr, &num) == 0) {
|
|
|
|
return (uintmax_t)num + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-01-09 15:55:45 +01:00
|
|
|
static void __cu__tag_not_handled(Dwarf_Die *die, const char *fn)
|
2007-01-08 02:57:32 +01:00
|
|
|
{
|
|
|
|
fprintf(stderr, "%s: DW_TAG_%s @ <%#llx> not handled!\n",
|
|
|
|
fn, dwarf_tag_name(dwarf_tag(die)), dwarf_cuoffset(die));
|
|
|
|
}
|
|
|
|
|
2007-01-09 15:55:45 +01:00
|
|
|
#define cu__tag_not_handled(die) __cu__tag_not_handled(die, __FUNCTION__)
|
|
|
|
|
|
|
|
static void __die__process_tag(Dwarf_Die *die, struct cu *cu, const char *fn);
|
|
|
|
|
|
|
|
#define die__process_tag(die, cu) __die__process_tag(die, cu, __FUNCTION__)
|
2007-01-08 02:57:32 +01:00
|
|
|
|
2007-01-09 15:17:48 +01:00
|
|
|
static struct tag *die__create_new_tag(Dwarf_Die *die)
|
2006-12-29 19:34:11 +01:00
|
|
|
{
|
2007-01-03 23:22:51 +01:00
|
|
|
struct tag *self = tag__new(die);
|
2006-12-29 19:34:11 +01:00
|
|
|
|
|
|
|
if (self == NULL)
|
|
|
|
oom("tag__new");
|
|
|
|
|
|
|
|
if (dwarf_haschildren(die))
|
|
|
|
fprintf(stderr, "%s: %s WITH children!\n", __FUNCTION__,
|
2007-01-03 23:22:51 +01:00
|
|
|
dwarf_tag_name(self->tag));
|
2006-12-29 19:34:11 +01:00
|
|
|
|
2007-01-09 15:04:12 +01:00
|
|
|
return self;
|
2006-12-29 19:34:11 +01:00
|
|
|
}
|
|
|
|
|
2007-01-09 15:17:48 +01:00
|
|
|
static void die__process_class(Dwarf_Die *die,
|
|
|
|
struct type *class, struct cu *cu);
|
2006-12-06 14:35:21 +01:00
|
|
|
|
2007-01-09 15:17:48 +01:00
|
|
|
static struct tag *die__create_new_class(Dwarf_Die *die, struct cu *cu)
|
2006-12-06 14:35:21 +01:00
|
|
|
{
|
|
|
|
Dwarf_Die child;
|
2007-01-03 23:22:51 +01:00
|
|
|
struct class *class = class__new(die);
|
2007-01-03 14:09:52 +01:00
|
|
|
|
2006-12-06 14:35:21 +01:00
|
|
|
if (class == NULL)
|
|
|
|
oom("class__new");
|
2007-01-03 23:22:51 +01:00
|
|
|
|
2006-12-06 14:35:21 +01:00
|
|
|
if (dwarf_haschildren(die) != 0 && dwarf_child(die, &child) == 0)
|
2007-01-09 15:17:48 +01:00
|
|
|
die__process_class(&child, &class->type, cu);
|
2007-01-09 15:04:12 +01:00
|
|
|
|
|
|
|
return &class->type.tag;
|
2006-12-06 14:35:21 +01:00
|
|
|
}
|
|
|
|
|
2007-01-09 15:17:48 +01:00
|
|
|
static struct tag *die__create_new_union(Dwarf_Die *die, struct cu *cu)
|
2007-01-09 13:17:39 +01:00
|
|
|
{
|
|
|
|
Dwarf_Die child;
|
|
|
|
struct type *utype = type__new(die);
|
|
|
|
|
|
|
|
if (utype == NULL)
|
|
|
|
oom("type__new");
|
|
|
|
|
|
|
|
if (dwarf_haschildren(die) != 0 && dwarf_child(die, &child) == 0)
|
2007-01-09 15:17:48 +01:00
|
|
|
die__process_class(&child, utype, cu);
|
2007-01-09 15:04:12 +01:00
|
|
|
|
|
|
|
return &utype->tag;
|
2007-01-09 13:17:39 +01:00
|
|
|
}
|
|
|
|
|
2007-01-09 15:17:48 +01:00
|
|
|
static struct tag *die__create_new_base_type(Dwarf_Die *die)
|
2006-12-29 23:58:03 +01:00
|
|
|
{
|
2007-01-03 23:22:51 +01:00
|
|
|
struct base_type *base = base_type__new(die);
|
2007-01-03 14:59:31 +01:00
|
|
|
|
2006-12-29 23:58:03 +01:00
|
|
|
if (base == NULL)
|
|
|
|
oom("base_type__new");
|
|
|
|
|
|
|
|
if (dwarf_haschildren(die))
|
|
|
|
fprintf(stderr, "%s: DW_TAG_base_type WITH children!\n",
|
|
|
|
__FUNCTION__);
|
|
|
|
|
2007-01-09 15:04:12 +01:00
|
|
|
return &base->tag;
|
2006-12-29 23:58:03 +01:00
|
|
|
}
|
|
|
|
|
2007-01-09 15:17:48 +01:00
|
|
|
static struct tag *die__create_new_typedef(Dwarf_Die *die)
|
2007-01-06 18:17:58 +01:00
|
|
|
{
|
2007-01-07 15:30:58 +01:00
|
|
|
struct type *tdef = type__new(die);
|
2007-01-06 18:17:58 +01:00
|
|
|
|
|
|
|
if (tdef == NULL)
|
2007-01-07 15:30:58 +01:00
|
|
|
oom("type__new");
|
2007-01-06 18:17:58 +01:00
|
|
|
|
|
|
|
if (dwarf_haschildren(die))
|
|
|
|
fprintf(stderr, "%s: DW_TAG_typedef WITH children!\n",
|
|
|
|
__FUNCTION__);
|
|
|
|
|
2007-01-09 15:04:12 +01:00
|
|
|
return &tdef->tag;
|
2007-01-06 18:17:58 +01:00
|
|
|
}
|
|
|
|
|
2007-01-09 15:17:48 +01:00
|
|
|
static struct tag *die__create_new_array(Dwarf_Die *die)
|
2006-12-08 15:58:46 +01:00
|
|
|
{
|
|
|
|
Dwarf_Die child;
|
|
|
|
/* "64 dimensions will be enough for everybody." acme, 2006 */
|
|
|
|
const uint8_t max_dimensions = 64;
|
|
|
|
uint32_t nr_entries[max_dimensions];
|
2007-01-03 23:22:51 +01:00
|
|
|
struct array_type *array = array_type__new(die);
|
2007-01-03 14:59:31 +01:00
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
if (array == NULL)
|
|
|
|
oom("array_type__new");
|
2006-12-08 15:58:46 +01:00
|
|
|
|
|
|
|
if (!dwarf_haschildren(die) || dwarf_child(die, &child) != 0) {
|
|
|
|
fprintf(stderr, "%s: DW_TAG_array_type with no children!\n",
|
|
|
|
__FUNCTION__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
die = &child;
|
2006-12-29 18:28:58 +01:00
|
|
|
array->dimensions = 0;
|
2006-12-08 15:58:46 +01:00
|
|
|
do {
|
2007-01-08 02:57:32 +01:00
|
|
|
if (dwarf_tag(die) == DW_TAG_subrange_type) {
|
2006-12-29 18:28:58 +01:00
|
|
|
nr_entries[array->dimensions++] = attr_upper_bound(die);
|
|
|
|
if (array->dimensions == max_dimensions) {
|
2006-12-08 15:58:46 +01:00
|
|
|
fprintf(stderr, "%s: only %u dimensions are "
|
|
|
|
"supported!\n",
|
|
|
|
__FUNCTION__, max_dimensions);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else
|
2007-01-08 02:57:32 +01:00
|
|
|
cu__tag_not_handled(die);
|
2006-12-08 15:58:46 +01:00
|
|
|
} while (dwarf_siblingof(die, die) == 0);
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
array->nr_entries = memdup(nr_entries,
|
|
|
|
array->dimensions * sizeof(uint32_t));
|
|
|
|
if (array->nr_entries == NULL)
|
2006-12-08 15:58:46 +01:00
|
|
|
oom("memdup(array.nr_entries)");
|
|
|
|
|
2007-01-09 15:04:12 +01:00
|
|
|
return &array->tag;
|
2006-12-08 15:58:46 +01:00
|
|
|
}
|
|
|
|
|
2007-01-09 15:17:48 +01:00
|
|
|
static void die__create_new_parameter(Dwarf_Die *die, struct ftype *ftype,
|
|
|
|
struct cu *cu)
|
2007-01-02 21:21:59 +01:00
|
|
|
{
|
2007-01-03 23:22:51 +01:00
|
|
|
struct parameter *parm = parameter__new(die);
|
2007-01-02 21:21:59 +01:00
|
|
|
|
|
|
|
if (parm == NULL)
|
|
|
|
oom("parameter__new");
|
|
|
|
|
2007-01-07 20:57:00 +01:00
|
|
|
if (ftype != NULL)
|
|
|
|
ftype__add_parameter(ftype, parm);
|
|
|
|
else
|
|
|
|
cu__add_tag(cu, &parm->tag);
|
2007-01-02 21:21:59 +01:00
|
|
|
}
|
|
|
|
|
2007-01-09 15:17:48 +01:00
|
|
|
static void die__create_new_label(Dwarf_Die *die, struct lexblock *lexblock)
|
2007-01-03 12:54:06 +01:00
|
|
|
{
|
2007-01-03 23:22:51 +01:00
|
|
|
struct label *label = label__new(die);
|
2007-01-03 12:54:06 +01:00
|
|
|
|
|
|
|
if (label == NULL)
|
|
|
|
oom("label__new");
|
|
|
|
|
|
|
|
lexblock__add_label(lexblock, label);
|
|
|
|
}
|
|
|
|
|
2007-01-09 15:17:48 +01:00
|
|
|
static void die__create_new_variable(Dwarf_Die *die,
|
|
|
|
struct lexblock *lexblock)
|
2007-01-03 12:49:20 +01:00
|
|
|
{
|
2007-01-03 23:22:51 +01:00
|
|
|
struct variable *var = variable__new(die);
|
2007-01-03 12:49:20 +01:00
|
|
|
if (var == NULL)
|
|
|
|
oom("variable__new");
|
|
|
|
|
|
|
|
lexblock__add_variable(lexblock, var);
|
|
|
|
}
|
|
|
|
|
2007-01-09 15:17:48 +01:00
|
|
|
static struct tag *die__create_new_subroutine_type(Dwarf_Die *die)
|
[CLASSES]: Introduce DW_TAG_subroutine_type specific parser
So that we handle DW_TAG_formal_parameters in this tag, fixing
these cases:
--- /tmp/ctracer.c.before 2006-12-29 13:27:24.000000000 -0200
+++ /tmp/ctracer.c 2007-01-02 02:34:18.000000000 -0200
<SNIP>
@@ -62,7 +62,7 @@
}; /* size: 68, cachelines: 3 */
/* last cacheline: 4 bytes */
-typedef int (*kretprobe_handler_t)(void /* FIXME: add parm list */);
+typedef int (*kretprobe_handler_t)(struct kretprobe_instance *, struct pt_regs *);
/* /pub/scm/linux/kernel/git/acme/linux-2.6/include/linux/list.h:607 */
struct hlist_head {
struct hlist_node * first; /* 0 4 */
[acme@newtoy ctracer_example]$
--- /tmp/pfunct.before 2006-12-30 16:18:25.000000000 -0200
+++ /tmp/pfunct.after 2007-01-02 02:08:50.000000000 -0200
@@ -249,7 +249,7 @@
/* definitions: 1 */
/* /pub/scm/linux/kernel/git/acme/linux-2.6/lib/klist.c:57 */
-void klist_init(struct klist * k, * get, * put);
+void klist_init(struct klist * k, void (*get)(struct klist_node *), void (*put)(struct klist_node *));
/* size: 12, inline expansions: 1 (5 bytes) */
/* definitions: 1 */
The struct/union case still needs fixing, but we're getting there...
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-02 05:42:33 +01:00
|
|
|
{
|
|
|
|
Dwarf_Die child;
|
2007-01-03 23:22:51 +01:00
|
|
|
struct ftype *ftype = ftype__new(die);
|
2007-01-03 14:59:31 +01:00
|
|
|
|
[CLASSES]: Introduce DW_TAG_subroutine_type specific parser
So that we handle DW_TAG_formal_parameters in this tag, fixing
these cases:
--- /tmp/ctracer.c.before 2006-12-29 13:27:24.000000000 -0200
+++ /tmp/ctracer.c 2007-01-02 02:34:18.000000000 -0200
<SNIP>
@@ -62,7 +62,7 @@
}; /* size: 68, cachelines: 3 */
/* last cacheline: 4 bytes */
-typedef int (*kretprobe_handler_t)(void /* FIXME: add parm list */);
+typedef int (*kretprobe_handler_t)(struct kretprobe_instance *, struct pt_regs *);
/* /pub/scm/linux/kernel/git/acme/linux-2.6/include/linux/list.h:607 */
struct hlist_head {
struct hlist_node * first; /* 0 4 */
[acme@newtoy ctracer_example]$
--- /tmp/pfunct.before 2006-12-30 16:18:25.000000000 -0200
+++ /tmp/pfunct.after 2007-01-02 02:08:50.000000000 -0200
@@ -249,7 +249,7 @@
/* definitions: 1 */
/* /pub/scm/linux/kernel/git/acme/linux-2.6/lib/klist.c:57 */
-void klist_init(struct klist * k, * get, * put);
+void klist_init(struct klist * k, void (*get)(struct klist_node *), void (*put)(struct klist_node *));
/* size: 12, inline expansions: 1 (5 bytes) */
/* definitions: 1 */
The struct/union case still needs fixing, but we're getting there...
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-02 05:42:33 +01:00
|
|
|
if (ftype == NULL)
|
|
|
|
oom("ftype__new");
|
|
|
|
|
|
|
|
if (!dwarf_haschildren(die) || dwarf_child(die, &child) != 0)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
die = &child;
|
|
|
|
do {
|
2007-01-08 02:57:32 +01:00
|
|
|
switch (dwarf_tag(die)) {
|
2007-01-04 16:28:45 +01:00
|
|
|
case DW_TAG_formal_parameter:
|
2007-01-09 15:17:48 +01:00
|
|
|
die__create_new_parameter(die, ftype, NULL);
|
2007-01-04 16:28:45 +01:00
|
|
|
break;
|
|
|
|
case DW_TAG_unspecified_parameters:
|
|
|
|
ftype->unspec_parms = 1;
|
|
|
|
break;
|
|
|
|
default:
|
2007-01-08 02:57:32 +01:00
|
|
|
cu__tag_not_handled(die);
|
2007-01-04 16:28:45 +01:00
|
|
|
break;
|
[CLASSES]: Introduce DW_TAG_subroutine_type specific parser
So that we handle DW_TAG_formal_parameters in this tag, fixing
these cases:
--- /tmp/ctracer.c.before 2006-12-29 13:27:24.000000000 -0200
+++ /tmp/ctracer.c 2007-01-02 02:34:18.000000000 -0200
<SNIP>
@@ -62,7 +62,7 @@
}; /* size: 68, cachelines: 3 */
/* last cacheline: 4 bytes */
-typedef int (*kretprobe_handler_t)(void /* FIXME: add parm list */);
+typedef int (*kretprobe_handler_t)(struct kretprobe_instance *, struct pt_regs *);
/* /pub/scm/linux/kernel/git/acme/linux-2.6/include/linux/list.h:607 */
struct hlist_head {
struct hlist_node * first; /* 0 4 */
[acme@newtoy ctracer_example]$
--- /tmp/pfunct.before 2006-12-30 16:18:25.000000000 -0200
+++ /tmp/pfunct.after 2007-01-02 02:08:50.000000000 -0200
@@ -249,7 +249,7 @@
/* definitions: 1 */
/* /pub/scm/linux/kernel/git/acme/linux-2.6/lib/klist.c:57 */
-void klist_init(struct klist * k, * get, * put);
+void klist_init(struct klist * k, void (*get)(struct klist_node *), void (*put)(struct klist_node *));
/* size: 12, inline expansions: 1 (5 bytes) */
/* definitions: 1 */
The struct/union case still needs fixing, but we're getting there...
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-02 05:42:33 +01:00
|
|
|
}
|
|
|
|
} while (dwarf_siblingof(die, die) == 0);
|
|
|
|
out:
|
2007-01-09 15:04:12 +01:00
|
|
|
return &ftype->tag;
|
[CLASSES]: Introduce DW_TAG_subroutine_type specific parser
So that we handle DW_TAG_formal_parameters in this tag, fixing
these cases:
--- /tmp/ctracer.c.before 2006-12-29 13:27:24.000000000 -0200
+++ /tmp/ctracer.c 2007-01-02 02:34:18.000000000 -0200
<SNIP>
@@ -62,7 +62,7 @@
}; /* size: 68, cachelines: 3 */
/* last cacheline: 4 bytes */
-typedef int (*kretprobe_handler_t)(void /* FIXME: add parm list */);
+typedef int (*kretprobe_handler_t)(struct kretprobe_instance *, struct pt_regs *);
/* /pub/scm/linux/kernel/git/acme/linux-2.6/include/linux/list.h:607 */
struct hlist_head {
struct hlist_node * first; /* 0 4 */
[acme@newtoy ctracer_example]$
--- /tmp/pfunct.before 2006-12-30 16:18:25.000000000 -0200
+++ /tmp/pfunct.after 2007-01-02 02:08:50.000000000 -0200
@@ -249,7 +249,7 @@
/* definitions: 1 */
/* /pub/scm/linux/kernel/git/acme/linux-2.6/lib/klist.c:57 */
-void klist_init(struct klist * k, * get, * put);
+void klist_init(struct klist * k, void (*get)(struct klist_node *), void (*put)(struct klist_node *));
/* size: 12, inline expansions: 1 (5 bytes) */
/* definitions: 1 */
The struct/union case still needs fixing, but we're getting there...
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-02 05:42:33 +01:00
|
|
|
}
|
|
|
|
|
2007-01-09 15:17:48 +01:00
|
|
|
static struct tag *die__create_new_enumeration(Dwarf_Die *die)
|
2007-01-09 01:06:11 +01:00
|
|
|
{
|
|
|
|
Dwarf_Die child;
|
2007-01-09 13:00:47 +01:00
|
|
|
struct type *enumeration = type__new(die);
|
2007-01-09 01:06:11 +01:00
|
|
|
|
|
|
|
if (enumeration == NULL)
|
|
|
|
oom("class__new");
|
|
|
|
|
|
|
|
if (!dwarf_haschildren(die) || dwarf_child(die, &child) != 0) {
|
|
|
|
fprintf(stderr, "%s: DW_TAG_enumeration_type with no "
|
|
|
|
"children!\n", __FUNCTION__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
die = &child;
|
|
|
|
do {
|
|
|
|
struct enumerator *enumerator;
|
|
|
|
|
|
|
|
if (dwarf_tag(die) != DW_TAG_enumerator) {
|
|
|
|
cu__tag_not_handled(die);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
enumerator = enumerator__new(die);
|
|
|
|
if (enumerator == NULL)
|
|
|
|
oom("enumerator__new");
|
|
|
|
|
|
|
|
enumeration__add(enumeration, enumerator);
|
|
|
|
} while (dwarf_siblingof(die, die) == 0);
|
|
|
|
|
2007-01-09 15:04:12 +01:00
|
|
|
return &enumeration->tag;
|
2007-01-09 01:06:11 +01:00
|
|
|
}
|
|
|
|
|
2007-01-09 15:17:48 +01:00
|
|
|
static void die__process_class(Dwarf_Die *die, struct type *class,
|
|
|
|
struct cu *cu)
|
2006-10-28 23:22:42 +02:00
|
|
|
{
|
2007-01-06 17:07:28 +01:00
|
|
|
do {
|
2007-01-08 02:57:32 +01:00
|
|
|
switch (dwarf_tag(die)) {
|
2007-01-06 17:07:28 +01:00
|
|
|
case DW_TAG_inheritance:
|
|
|
|
case DW_TAG_member: {
|
|
|
|
struct class_member *member = class_member__new(die);
|
2006-10-28 23:22:42 +02:00
|
|
|
|
2007-01-06 17:07:28 +01:00
|
|
|
if (member == NULL)
|
|
|
|
oom("class_member__new");
|
2006-11-19 00:06:03 +01:00
|
|
|
|
2007-01-09 13:17:39 +01:00
|
|
|
type__add_member(class, member);
|
2007-01-06 17:07:28 +01:00
|
|
|
}
|
2007-01-09 15:04:12 +01:00
|
|
|
continue;
|
2007-01-06 17:07:28 +01:00
|
|
|
default:
|
2007-01-09 15:55:45 +01:00
|
|
|
die__process_tag(die, cu);
|
2007-01-09 15:04:12 +01:00
|
|
|
continue;
|
2007-01-06 17:07:28 +01:00
|
|
|
}
|
|
|
|
} while (dwarf_siblingof(die, die) == 0);
|
2006-11-19 00:06:03 +01:00
|
|
|
}
|
|
|
|
|
2007-01-09 15:17:48 +01:00
|
|
|
static void die__process_function(Dwarf_Die *die, struct ftype *ftype,
|
|
|
|
struct lexblock *lexblock, struct cu *cu);
|
2007-01-02 16:25:56 +01:00
|
|
|
|
2007-01-09 15:17:48 +01:00
|
|
|
static void die__create_new_lexblock(Dwarf_Die *die,
|
|
|
|
struct cu *cu, struct lexblock *father)
|
2007-01-02 16:25:56 +01:00
|
|
|
{
|
2007-01-03 23:22:51 +01:00
|
|
|
struct lexblock *lexblock = lexblock__new(die);
|
2007-01-02 16:25:56 +01:00
|
|
|
|
|
|
|
if (lexblock == NULL)
|
|
|
|
oom("lexblock__new");
|
2007-01-09 15:17:48 +01:00
|
|
|
die__process_function(die, NULL, lexblock, cu);
|
2007-01-02 16:25:56 +01:00
|
|
|
lexblock__add_lexblock(father, lexblock);
|
|
|
|
}
|
|
|
|
|
2007-01-09 15:17:48 +01:00
|
|
|
static void die__create_new_inline_expansion(Dwarf_Die *die,
|
|
|
|
struct lexblock *lexblock)
|
2007-01-02 19:26:11 +01:00
|
|
|
{
|
2007-01-03 23:22:51 +01:00
|
|
|
struct inline_expansion *exp = inline_expansion__new(die);
|
2007-01-02 19:26:11 +01:00
|
|
|
|
|
|
|
if (exp == NULL)
|
|
|
|
oom("inline_expansion__new");
|
|
|
|
|
|
|
|
lexblock__add_inline_expansion(lexblock, exp);
|
|
|
|
}
|
|
|
|
|
2007-01-09 15:17:48 +01:00
|
|
|
static void die__process_function(Dwarf_Die *die, struct ftype *ftype,
|
|
|
|
struct lexblock *lexblock, struct cu *cu)
|
2006-11-19 00:06:03 +01:00
|
|
|
{
|
|
|
|
Dwarf_Die child;
|
|
|
|
|
2007-01-02 15:20:32 +01:00
|
|
|
if (!dwarf_haschildren(die) || dwarf_child(die, &child) != 0)
|
2006-11-19 00:06:03 +01:00
|
|
|
return;
|
|
|
|
|
2007-01-02 15:20:32 +01:00
|
|
|
die = &child;
|
|
|
|
do {
|
2007-01-08 02:57:32 +01:00
|
|
|
switch (dwarf_tag(die)) {
|
2007-01-02 15:20:32 +01:00
|
|
|
case DW_TAG_formal_parameter:
|
2007-01-09 15:17:48 +01:00
|
|
|
die__create_new_parameter(die, ftype, cu);
|
2007-01-09 15:04:12 +01:00
|
|
|
continue;
|
2007-01-03 12:49:20 +01:00
|
|
|
case DW_TAG_variable:
|
2007-01-09 15:17:48 +01:00
|
|
|
die__create_new_variable(die, lexblock);
|
2007-01-09 15:04:12 +01:00
|
|
|
continue;
|
2007-01-02 15:20:32 +01:00
|
|
|
case DW_TAG_unspecified_parameters:
|
|
|
|
if (ftype != NULL)
|
|
|
|
ftype->unspec_parms = 1;
|
2007-01-09 15:04:12 +01:00
|
|
|
continue;
|
2007-01-03 12:54:06 +01:00
|
|
|
case DW_TAG_label:
|
2007-01-09 15:17:48 +01:00
|
|
|
die__create_new_label(die, lexblock);
|
2007-01-09 15:04:12 +01:00
|
|
|
continue;
|
2007-01-02 19:26:11 +01:00
|
|
|
case DW_TAG_inlined_subroutine:
|
2007-01-09 15:17:48 +01:00
|
|
|
die__create_new_inline_expansion(die, lexblock);
|
2007-01-09 15:04:12 +01:00
|
|
|
continue;
|
2007-01-02 15:20:32 +01:00
|
|
|
case DW_TAG_lexical_block:
|
2007-01-09 15:17:48 +01:00
|
|
|
die__create_new_lexblock(die, cu, lexblock);
|
2007-01-09 15:04:12 +01:00
|
|
|
continue;
|
2007-01-06 17:07:28 +01:00
|
|
|
default:
|
2007-01-09 15:55:45 +01:00
|
|
|
die__process_tag(die, cu);
|
2007-01-02 15:20:32 +01:00
|
|
|
}
|
|
|
|
} while (dwarf_siblingof(die, die) == 0);
|
|
|
|
}
|
2006-11-19 00:06:03 +01:00
|
|
|
|
2007-01-09 15:17:48 +01:00
|
|
|
static struct tag *die__create_new_function(Dwarf_Die *die, struct cu *cu)
|
2007-01-02 15:20:32 +01:00
|
|
|
{
|
2007-01-07 18:54:41 +01:00
|
|
|
struct function *function = function__new(die);
|
2007-01-02 15:20:32 +01:00
|
|
|
|
|
|
|
if (function == NULL)
|
|
|
|
oom("function__new");
|
2007-01-09 15:17:48 +01:00
|
|
|
die__process_function(die, &function->proto, &function->lexblock, cu);
|
2007-01-09 15:04:12 +01:00
|
|
|
return &function->proto.tag;
|
2006-11-19 00:06:03 +01:00
|
|
|
}
|
|
|
|
|
2007-01-09 15:55:45 +01:00
|
|
|
static void __die__process_tag(Dwarf_Die *die, struct cu *cu, const char *fn)
|
|
|
|
{
|
|
|
|
struct tag *new_tag = NULL;
|
|
|
|
|
|
|
|
switch (dwarf_tag(die)) {
|
|
|
|
case DW_TAG_array_type:
|
|
|
|
new_tag = die__create_new_array(die); break;
|
|
|
|
case DW_TAG_base_type:
|
|
|
|
new_tag = die__create_new_base_type(die); break;
|
|
|
|
case DW_TAG_const_type:
|
|
|
|
case DW_TAG_pointer_type:
|
2007-01-12 14:06:59 +01:00
|
|
|
case DW_TAG_reference_type:
|
2007-01-09 15:55:45 +01:00
|
|
|
case DW_TAG_volatile_type:
|
|
|
|
new_tag = die__create_new_tag(die); break;
|
|
|
|
case DW_TAG_enumeration_type:
|
|
|
|
new_tag = die__create_new_enumeration(die); break;
|
|
|
|
case DW_TAG_structure_type:
|
|
|
|
new_tag = die__create_new_class(die, cu); break;
|
|
|
|
case DW_TAG_subprogram:
|
|
|
|
new_tag = die__create_new_function(die, cu); break;
|
|
|
|
case DW_TAG_subroutine_type:
|
|
|
|
new_tag = die__create_new_subroutine_type(die); break;
|
|
|
|
case DW_TAG_typedef:
|
|
|
|
new_tag = die__create_new_typedef(die); break;
|
|
|
|
case DW_TAG_union_type:
|
|
|
|
new_tag = die__create_new_union(die, cu); break;
|
|
|
|
default:
|
|
|
|
__cu__tag_not_handled(die, fn); return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (new_tag != NULL)
|
|
|
|
cu__add_tag(cu, new_tag);
|
|
|
|
}
|
|
|
|
|
2007-01-09 15:17:48 +01:00
|
|
|
static void die__process_unit(Dwarf_Die *die, struct cu *cu)
|
2007-01-06 17:07:28 +01:00
|
|
|
{
|
|
|
|
do {
|
2007-01-08 02:57:32 +01:00
|
|
|
switch (dwarf_tag(die)) {
|
2007-01-06 17:07:28 +01:00
|
|
|
case DW_TAG_variable:
|
|
|
|
/* Handle global variables later */
|
2007-01-09 15:04:12 +01:00
|
|
|
continue;
|
2007-01-06 17:07:28 +01:00
|
|
|
default:
|
2007-01-09 15:55:45 +01:00
|
|
|
die__process_tag(die, cu);
|
2007-01-09 15:04:12 +01:00
|
|
|
continue;
|
2007-01-06 17:07:28 +01:00
|
|
|
}
|
|
|
|
} while (dwarf_siblingof(die, die) == 0);
|
|
|
|
}
|
|
|
|
|
2007-01-09 15:17:48 +01:00
|
|
|
static void die__process(Dwarf_Die *die, struct cu *cu)
|
2006-11-19 00:06:03 +01:00
|
|
|
{
|
|
|
|
Dwarf_Die child;
|
2007-01-06 17:07:28 +01:00
|
|
|
const uint16_t tag = dwarf_tag(die);
|
2006-11-19 00:06:03 +01:00
|
|
|
|
2007-01-06 17:07:28 +01:00
|
|
|
if (tag != DW_TAG_compile_unit) {
|
|
|
|
fprintf(stderr, "%s: DW_TAG_compile_unit expected got %s!\n",
|
|
|
|
__FUNCTION__, dwarf_tag_name(tag));
|
2006-11-19 00:06:03 +01:00
|
|
|
return;
|
|
|
|
}
|
2006-10-28 23:22:42 +02:00
|
|
|
|
2007-01-06 17:07:28 +01:00
|
|
|
cu->language = attr_numeric(die, DW_AT_language);
|
|
|
|
|
|
|
|
if (dwarf_child(die, &child) == 0)
|
2007-01-09 15:17:48 +01:00
|
|
|
die__process_unit(&child, cu);
|
2007-01-06 17:07:28 +01:00
|
|
|
|
2006-11-18 19:32:05 +01:00
|
|
|
if (dwarf_siblingof(die, die) == 0)
|
2007-01-06 17:07:28 +01:00
|
|
|
fprintf(stderr, "%s: got %s unexpected tag after "
|
|
|
|
"DW_TAG_compile_unit!\n",
|
|
|
|
__FUNCTION__, dwarf_tag_name(tag));
|
2006-10-28 23:22:42 +02:00
|
|
|
}
|
|
|
|
|
2006-12-27 17:57:19 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2006-12-20 15:35:45 +01:00
|
|
|
int cus__load(struct cus *self, const char *filename)
|
2006-10-28 23:22:42 +02:00
|
|
|
{
|
|
|
|
Dwarf_Off offset, last_offset, abbrev_offset;
|
|
|
|
uint8_t addr_size, offset_size;
|
2006-12-24 15:00:07 +01:00
|
|
|
uint32_t cu_id;
|
2006-10-28 23:22:42 +02:00
|
|
|
size_t hdr_size;
|
|
|
|
Dwarf *dwarf;
|
|
|
|
int err = -1;
|
2006-12-20 15:35:45 +01:00
|
|
|
int fd = open(filename, O_RDONLY);
|
2006-10-28 23:22:42 +02:00
|
|
|
|
|
|
|
if (fd < 0)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
dwarf = dwarf_begin(fd, DWARF_C_READ);
|
|
|
|
if (dwarf == NULL)
|
|
|
|
goto out_close;
|
|
|
|
|
|
|
|
offset = last_offset = 0;
|
2006-11-19 00:06:03 +01:00
|
|
|
cu_id = 0;
|
2006-10-28 23:22:42 +02:00
|
|
|
while (dwarf_nextcu(dwarf, offset, &offset, &hdr_size,
|
|
|
|
&abbrev_offset, &addr_size, &offset_size) == 0) {
|
|
|
|
Dwarf_Die die;
|
|
|
|
|
|
|
|
if (dwarf_offdie(dwarf, last_offset + hdr_size, &die) != NULL) {
|
2006-11-19 00:06:03 +01:00
|
|
|
struct cu *cu = cu__new(cu_id,
|
2007-01-04 20:27:24 +01:00
|
|
|
attr_string(&die, DW_AT_name),
|
2006-12-29 19:34:11 +01:00
|
|
|
addr_size);
|
2006-11-19 00:06:03 +01:00
|
|
|
if (cu == NULL)
|
2006-10-31 20:12:42 +01:00
|
|
|
oom("cu__new");
|
2006-11-19 00:06:03 +01:00
|
|
|
++cu_id;
|
2007-01-09 15:17:48 +01:00
|
|
|
die__process(&die, cu);
|
2006-11-19 00:06:03 +01:00
|
|
|
cus__add(self, cu);
|
2006-10-28 23:22:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
last_offset = offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
dwarf_end(dwarf);
|
|
|
|
err = 0;
|
|
|
|
out_close:
|
|
|
|
close(fd);
|
|
|
|
out:
|
|
|
|
return err;
|
|
|
|
}
|
2006-11-11 19:31:04 +01:00
|
|
|
|
2006-12-27 17:39:37 +01:00
|
|
|
struct cus *cus__new(struct list_head *definitions,
|
|
|
|
struct list_head *fwd_decls)
|
2006-11-11 19:31:04 +01:00
|
|
|
{
|
|
|
|
struct cus *self = malloc(sizeof(*self));
|
|
|
|
|
2006-12-23 21:30:48 +01:00
|
|
|
if (self != NULL) {
|
2006-11-11 19:31:04 +01:00
|
|
|
INIT_LIST_HEAD(&self->cus);
|
2006-12-27 17:39:37 +01:00
|
|
|
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;
|
2006-12-23 21:30:48 +01:00
|
|
|
}
|
2006-11-11 19:31:04 +01:00
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
2006-12-23 22:29:27 +01:00
|
|
|
|
2007-01-04 04:41:11 +01:00
|
|
|
static int cus__emit_typedef_definitions(struct cus *self, struct cu *cu,
|
|
|
|
struct tag *tdef)
|
2006-12-23 22:29:27 +01:00
|
|
|
{
|
2007-01-07 15:30:58 +01:00
|
|
|
struct type *def = tag__type(tdef);
|
2006-12-29 18:28:58 +01:00
|
|
|
struct tag *type, *ptr_type;
|
2006-12-24 17:00:16 +01:00
|
|
|
int is_pointer = 0;
|
2006-12-23 22:29:27 +01:00
|
|
|
|
|
|
|
/* Have we already emitted this in this CU? */
|
2007-01-07 15:30:58 +01:00
|
|
|
if (def->definition_emitted)
|
2006-12-23 22:29:27 +01:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Ok, lets look at the previous CUs: */
|
2007-01-07 15:30:58 +01:00
|
|
|
if (cus__find_definition(self, def->name) != NULL) {
|
2006-12-23 22:29:27 +01:00
|
|
|
/*
|
|
|
|
* Yes, so lets mark it visited on this CU too,
|
|
|
|
* to speed up the lookup.
|
|
|
|
*/
|
2007-01-07 15:30:58 +01:00
|
|
|
def->definition_emitted = 1;
|
2006-12-23 22:29:27 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2007-01-06 18:17:58 +01:00
|
|
|
type = cu__find_tag_by_id(cu, tdef->type);
|
2006-12-23 22:29:27 +01:00
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
switch (type->tag) {
|
[LIB]: Fix stupid if + switch case
Where the 'if' should be just one of of the cases in the 'switch', and guess
what:
This:
diff --git a/dwarves.c b/dwarves.c
index c0ae7c8..34f29a1 100644
--- a/dwarves.c
+++ b/dwarves.c
@@ -2580,10 +2580,10 @@ static int cus__emit_typedef_definitions
}
type = cu__find_tag_by_id(cu, tdef->type);
- if (type->tag == DW_TAG_typedef)
- cus__emit_typedef_definitions(self, cu, type);
-
switch (type->tag) {
+ case DW_TAG_typedef:
+ cus__emit_typedef_definitions(self, cu, type);
+ break;
case DW_TAG_pointer_type:
ptr_type = cu__find_tag_by_id(cu, type->type);
if (ptr_type->tag != DW_TAG_subroutine_type)
Results in this:
[acme@newtoy pahole]$ codiff -V build/libdwarves.so.orig build/libdwarves.so
/home/acme/pahole/dwarves.c:
cus__emit_typedef_definitions | -18 # 466 -> 448
1 function changed, 18 bytes removed
[acme@newtoy pahole]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-13 19:22:53 +01:00
|
|
|
case DW_TAG_typedef:
|
|
|
|
cus__emit_typedef_definitions(self, cu, type);
|
|
|
|
break;
|
2006-12-24 17:00:16 +01:00
|
|
|
case DW_TAG_pointer_type:
|
2007-01-04 04:41:11 +01:00
|
|
|
ptr_type = cu__find_tag_by_id(cu, type->type);
|
2006-12-29 18:28:58 +01:00
|
|
|
if (ptr_type->tag != DW_TAG_subroutine_type)
|
2006-12-24 17:00:16 +01:00
|
|
|
break;
|
|
|
|
type = ptr_type;
|
|
|
|
is_pointer = 1;
|
|
|
|
/* Fall thru */
|
|
|
|
case DW_TAG_subroutine_type:
|
2007-01-04 04:41:11 +01:00
|
|
|
cus__emit_ftype_definitions(self, cu, tag__ftype(type));
|
2007-01-12 16:04:05 +01:00
|
|
|
break;
|
2007-01-13 17:19:34 +01:00
|
|
|
case DW_TAG_structure_type:
|
|
|
|
case DW_TAG_union_type: {
|
2007-01-07 15:30:58 +01:00
|
|
|
const struct type *ctype = tag__type(type);
|
2006-12-29 18:28:58 +01:00
|
|
|
|
2007-01-12 16:04:05 +01:00
|
|
|
if (ctype->name == NULL) {
|
2007-01-13 17:19:34 +01:00
|
|
|
cus__emit_type_definitions(self, cu, type,
|
|
|
|
"typedef", def->name);
|
2007-01-12 16:04:05 +01:00
|
|
|
goto out;
|
|
|
|
}
|
2006-12-29 18:28:58 +01:00
|
|
|
}
|
2006-12-23 22:29:27 +01:00
|
|
|
}
|
2007-01-12 16:04:05 +01:00
|
|
|
|
|
|
|
typedef__print(tdef, cu);
|
2007-01-12 20:23:14 +01:00
|
|
|
puts(";");
|
2006-12-23 22:29:27 +01:00
|
|
|
out:
|
2007-01-07 15:30:58 +01:00
|
|
|
cus__add_definition(self, def);
|
2006-12-23 22:29:27 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2007-01-07 16:27:12 +01:00
|
|
|
static int cus__emit_enumeration_definitions(struct cus *self, struct tag *tag)
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
{
|
2007-01-07 16:27:12 +01:00
|
|
|
struct type *etype = tag__type(tag);
|
2007-01-07 15:30:58 +01:00
|
|
|
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
/* Have we already emitted this in this CU? */
|
2007-01-07 15:30:58 +01:00
|
|
|
if (etype->definition_emitted)
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Ok, lets look at the previous CUs: */
|
2007-01-07 15:30:58 +01:00
|
|
|
if (cus__find_definition(self, etype->name) != NULL) {
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
/*
|
|
|
|
* Yes, so lets mark it visited on this CU too,
|
|
|
|
* to speed up the lookup.
|
|
|
|
*/
|
2007-01-07 15:30:58 +01:00
|
|
|
etype->definition_emitted = 1;
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2007-01-07 15:30:58 +01:00
|
|
|
|
2007-01-12 19:11:37 +01:00
|
|
|
tag__print_decl_info(tag);
|
2007-01-07 16:27:12 +01:00
|
|
|
enumeration__print(tag, NULL, 0);
|
2007-01-12 20:40:12 +01:00
|
|
|
puts(";");
|
2007-01-07 15:30:58 +01:00
|
|
|
cus__add_definition(self, etype);
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2007-01-07 15:30:58 +01:00
|
|
|
int cus__emit_fwd_decl(struct cus *self, struct type *ctype)
|
2006-12-23 22:29:27 +01:00
|
|
|
{
|
|
|
|
/* Have we already emitted this in this CU? */
|
2007-01-07 15:30:58 +01:00
|
|
|
if (ctype->fwd_decl_emitted)
|
2006-12-23 22:29:27 +01:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Ok, lets look at the previous CUs: */
|
2007-01-07 15:30:58 +01:00
|
|
|
if (cus__find_fwd_decl(self, ctype->name) != NULL) {
|
2006-12-23 22:29:27 +01:00
|
|
|
/*
|
|
|
|
* Yes, so lets mark it visited on this CU too,
|
|
|
|
* to speed up the lookup.
|
|
|
|
*/
|
2007-01-07 15:30:58 +01:00
|
|
|
ctype->fwd_decl_emitted = 1;
|
2006-12-23 22:29:27 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-01-13 17:27:08 +01:00
|
|
|
printf("%s %s;\n",
|
|
|
|
ctype->tag.tag == DW_TAG_union_type ? "union" : "struct",
|
|
|
|
ctype->name);
|
2007-01-07 15:30:58 +01:00
|
|
|
cus__add_fwd_decl(self, ctype);
|
2006-12-23 22:29:27 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cus__emit_tag_definitions(struct cus *self, struct cu *cu,
|
|
|
|
struct tag *tag)
|
|
|
|
{
|
2006-12-29 18:28:58 +01:00
|
|
|
struct tag *type = cu__find_tag_by_id(cu, tag->type);
|
2006-12-23 22:29:27 +01:00
|
|
|
int pointer = 0;
|
|
|
|
|
|
|
|
if (type == NULL)
|
|
|
|
return 0;
|
|
|
|
next_indirection:
|
2006-12-29 18:28:58 +01:00
|
|
|
if (type->tag == DW_TAG_pointer_type ||
|
2007-01-12 14:06:59 +01:00
|
|
|
type->tag == DW_TAG_reference_type ||
|
2006-12-29 18:28:58 +01:00
|
|
|
type->tag == DW_TAG_array_type ||
|
|
|
|
type->tag == DW_TAG_const_type ||
|
|
|
|
type->tag == DW_TAG_volatile_type) {
|
2006-12-23 22:29:27 +01:00
|
|
|
pointer = 1;
|
2006-12-29 18:28:58 +01:00
|
|
|
type = cu__find_tag_by_id(cu, type->type);
|
2006-12-23 22:29:27 +01:00
|
|
|
if (type == NULL)
|
|
|
|
return 0;
|
|
|
|
goto next_indirection;
|
|
|
|
}
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
switch (type->tag) {
|
2006-12-23 22:29:27 +01:00
|
|
|
case DW_TAG_typedef:
|
2007-01-04 04:41:11 +01:00
|
|
|
return cus__emit_typedef_definitions(self, cu, type);
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
case DW_TAG_enumeration_type:
|
2007-01-07 15:30:58 +01:00
|
|
|
if (tag__type(type)->name != NULL)
|
2007-01-07 16:27:12 +01:00
|
|
|
return cus__emit_enumeration_definitions(self, type);
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
break;
|
2006-12-23 22:29:27 +01:00
|
|
|
case DW_TAG_structure_type:
|
2007-01-13 17:19:34 +01:00
|
|
|
case DW_TAG_union_type:
|
2006-12-23 22:29:27 +01:00
|
|
|
if (pointer)
|
2007-01-07 15:30:58 +01:00
|
|
|
return cus__emit_fwd_decl(self, tag__type(type));
|
2007-01-13 17:19:34 +01:00
|
|
|
return cus__emit_type_definitions(self, cu, type, NULL, NULL);
|
2006-12-27 13:21:40 +01:00
|
|
|
case DW_TAG_subroutine_type:
|
2007-01-12 17:39:26 +01:00
|
|
|
return cus__emit_ftype_definitions(self, cu, tag__ftype(type));
|
2006-12-23 22:29:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-12-30 19:34:20 +01:00
|
|
|
int cus__emit_ftype_definitions(struct cus *self, struct cu *cu,
|
|
|
|
struct ftype *ftype)
|
2006-12-23 22:29:27 +01:00
|
|
|
{
|
|
|
|
struct parameter *pos;
|
|
|
|
/* First check the function return type */
|
2006-12-30 19:34:20 +01:00
|
|
|
int printed = cus__emit_tag_definitions(self, cu, &ftype->tag);
|
2006-12-23 22:29:27 +01:00
|
|
|
|
|
|
|
/* Then its parameters */
|
2006-12-30 19:34:20 +01:00
|
|
|
list_for_each_entry(pos, &ftype->parms, tag.node)
|
|
|
|
if (cus__emit_tag_definitions(self, cu, &pos->tag))
|
2006-12-23 22:29:27 +01:00
|
|
|
printed = 1;
|
|
|
|
|
|
|
|
if (printed)
|
|
|
|
putchar('\n');
|
|
|
|
return printed;
|
|
|
|
}
|
|
|
|
|
2007-01-13 17:19:34 +01:00
|
|
|
int cus__emit_type_definitions(struct cus *self, struct cu *cu,
|
|
|
|
struct tag *tag,
|
|
|
|
const char *prefix, const char *suffix)
|
2006-12-23 22:29:27 +01:00
|
|
|
{
|
2007-01-07 16:11:20 +01:00
|
|
|
struct type *ctype = tag__type(tag);
|
2006-12-23 22:29:27 +01:00
|
|
|
struct class_member *pos;
|
|
|
|
int printed = 0;
|
|
|
|
|
2007-01-07 15:30:58 +01:00
|
|
|
if (ctype->definition_emitted)
|
2006-12-24 02:34:42 +01:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Ok, lets look at the previous CUs: */
|
2007-01-07 15:30:58 +01:00
|
|
|
if (cus__find_definition(self, ctype->name) != NULL) {
|
|
|
|
ctype->definition_emitted = 1;
|
2006-12-24 02:34:42 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-01-07 15:30:58 +01:00
|
|
|
cus__add_definition(self, ctype);
|
2006-12-24 02:34:42 +01:00
|
|
|
|
2007-01-13 17:19:34 +01:00
|
|
|
list_for_each_entry(pos, &ctype->members, tag.node)
|
2007-01-04 04:41:11 +01:00
|
|
|
if (cus__emit_tag_definitions(self, cu, &pos->tag))
|
2006-12-23 22:29:27 +01:00
|
|
|
printed = 1;
|
|
|
|
|
|
|
|
if (printed)
|
|
|
|
putchar('\n');
|
|
|
|
|
2007-01-13 17:19:34 +01:00
|
|
|
if (tag->tag == DW_TAG_structure_type)
|
|
|
|
class__find_holes(tag__class(tag), cu);
|
2007-01-13 18:56:27 +01:00
|
|
|
|
2007-01-07 16:11:20 +01:00
|
|
|
tag__print(tag, cu, prefix, suffix);
|
2007-01-13 18:56:27 +01:00
|
|
|
|
|
|
|
if (tag->tag != DW_TAG_structure_type)
|
|
|
|
putchar(';');
|
|
|
|
|
2006-12-23 22:29:27 +01:00
|
|
|
putchar('\n');
|
|
|
|
return 1;
|
|
|
|
}
|