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>
|
2007-02-15 14:36:49 +01:00
|
|
|
Copyright (C) 2007 Red Hat Inc.
|
|
|
|
Copyright (C) 2007 Arnaldo Carvalho de Melo <acme@redhat.com>
|
2006-10-28 23:22:42 +02:00
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
|
[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>
|
2007-03-30 18:22:28 +02:00
|
|
|
#include <argp.h>
|
|
|
|
#include <elfutils/libdwfl.h>
|
2007-03-28 17:54:46 +02:00
|
|
|
#include <errno.h>
|
2006-10-28 23:22:42 +02:00
|
|
|
#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";
|
|
|
|
}
|
|
|
|
|
2007-04-28 21:13:35 +02:00
|
|
|
static const struct conf_fprintf conf_fprintf__defaults = {
|
|
|
|
.name_spacing = 23,
|
|
|
|
.type_spacing = 26,
|
|
|
|
.emit_stats = 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
|
|
|
static const char tabs[] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
|
|
|
|
|
2007-01-19 00:41:25 +01:00
|
|
|
static size_t 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_flag:
|
|
|
|
return 1;
|
|
|
|
default:
|
2007-01-25 19:24:09 +01:00
|
|
|
fprintf(stderr, "DW_AT_<0x%x>=0x%x\n", name, form);
|
2007-01-03 23:22:51 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-05-29 23:11:45 +02:00
|
|
|
static uint64_t dwarf_expr(const uint8_t *expr, uint32_t len __unused)
|
|
|
|
{
|
|
|
|
/* Common case: offset from start of the class */
|
2007-07-09 01:32:34 +02:00
|
|
|
if (expr[0] == DW_OP_plus_uconst ||
|
|
|
|
expr[0] == DW_OP_constu) {
|
2007-05-29 23:11:45 +02:00
|
|
|
uint64_t result;
|
|
|
|
++expr;
|
|
|
|
get_uleb128(result, expr);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(stderr, "%s: unhandled %#x DW_OP_ operation\n",
|
|
|
|
__func__, *expr);
|
|
|
|
return UINT64_MAX;
|
|
|
|
}
|
|
|
|
|
2007-07-09 01:33:56 +02:00
|
|
|
static Dwarf_Off attr_offset(Dwarf_Die *die, const uint32_t name)
|
2007-01-03 23:22:51 +01:00
|
|
|
{
|
|
|
|
Dwarf_Attribute attr;
|
2007-05-29 23:11:45 +02:00
|
|
|
Dwarf_Block block;
|
2007-01-03 23:22:51 +01:00
|
|
|
|
2007-07-09 01:33:56 +02:00
|
|
|
if (dwarf_attr(die, name, &attr) != NULL &&
|
2007-05-29 23:11:45 +02:00
|
|
|
dwarf_formblock(&attr, &block) == 0)
|
|
|
|
return dwarf_expr(block.data, block.length);
|
2007-01-03 23:22:51 +01:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2007-01-25 19:24:09 +01:00
|
|
|
static Dwarf_Off attr_type(Dwarf_Die *die, uint32_t attr_name)
|
|
|
|
{
|
|
|
|
Dwarf_Attribute attr;
|
|
|
|
if (dwarf_attr(die, attr_name, &attr) != NULL) {
|
|
|
|
Dwarf_Die type_die;
|
|
|
|
if (dwarf_formref_die(&attr, &type_die) != NULL)
|
|
|
|
return dwarf_dieoffset(&type_die);
|
|
|
|
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-02-02 14:56:53 +01:00
|
|
|
static int attr_location(Dwarf_Die *die, Dwarf_Op **expr, size_t *exprlen)
|
|
|
|
{
|
|
|
|
Dwarf_Attribute attr;
|
|
|
|
if (dwarf_attr(die, DW_AT_location, &attr) != NULL) {
|
|
|
|
if (dwarf_getlocation(&attr, expr, exprlen) == 0)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2007-01-03 23:22:51 +01:00
|
|
|
static void tag__init(struct tag *self, Dwarf_Die *die)
|
|
|
|
{
|
2007-01-29 13:42:03 +01:00
|
|
|
int32_t decl_line;
|
2007-01-03 23:22:51 +01:00
|
|
|
|
2007-05-26 15:54:27 +02:00
|
|
|
self->tag = dwarf_tag(die);
|
|
|
|
self->id = dwarf_dieoffset(die);
|
|
|
|
|
2007-05-26 17:39:16 +02:00
|
|
|
if (self->tag == DW_TAG_imported_module ||
|
|
|
|
self->tag == DW_TAG_imported_declaration)
|
2007-05-26 15:54:27 +02:00
|
|
|
self->type = attr_type(die, DW_AT_import);
|
|
|
|
else
|
|
|
|
self->type = attr_type(die, DW_AT_type);
|
|
|
|
|
2007-01-03 23:22:51 +01:00
|
|
|
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-07-05 01:36:28 +02:00
|
|
|
self->recursivity_level = 0;
|
2006-11-18 14:54:02 +01:00
|
|
|
}
|
|
|
|
|
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-05-25 22:02:05 +02:00
|
|
|
static const char *tag__accessibility(const struct tag *self)
|
|
|
|
{
|
|
|
|
int a;
|
|
|
|
|
|
|
|
switch (self->tag) {
|
|
|
|
case DW_TAG_inheritance:
|
|
|
|
case DW_TAG_member:
|
|
|
|
a = tag__class_member(self)->accessibility;
|
|
|
|
break;
|
|
|
|
case DW_TAG_subprogram:
|
|
|
|
a = tag__function(self)->accessibility;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (a) {
|
|
|
|
case DW_ACCESS_public: return "public";
|
|
|
|
case DW_ACCESS_private: return "private";
|
|
|
|
case DW_ACCESS_protected: return "protected";
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-01-30 16:32:55 +01:00
|
|
|
size_t tag__nr_cachelines(const struct tag *self, const struct cu *cu)
|
|
|
|
{
|
|
|
|
return (tag__size(self, cu) + cacheline_size - 1) / cacheline_size;
|
|
|
|
}
|
|
|
|
|
2007-05-26 20:40:52 +02:00
|
|
|
static void __tag__id_not_found(const struct tag *self,
|
|
|
|
unsigned long long id, const char *fn)
|
2007-01-12 19:29:53 +01:00
|
|
|
{
|
2007-05-26 20:40:52 +02:00
|
|
|
fprintf(stderr, "%s: %#llx id not found for %s (id=%#llx)\n",
|
2007-11-10 18:56:30 +01:00
|
|
|
fn, (unsigned long long)id, dwarf_tag_name(self->tag),
|
|
|
|
(unsigned long long)self->id);
|
2007-02-15 14:46:49 +01:00
|
|
|
fflush(stderr);
|
2007-01-12 19:29:53 +01:00
|
|
|
}
|
|
|
|
|
2007-05-26 20:40:52 +02:00
|
|
|
#define tag__id_not_found(self, id) __tag__id_not_found(self, id, __func__)
|
|
|
|
|
|
|
|
#define tag__type_not_found(self) __tag__id_not_found(self, (self)->type, __func__)
|
2007-01-12 19:29:53 +01:00
|
|
|
|
2007-05-06 19:50:28 +02:00
|
|
|
size_t tag__fprintf_decl_info(const struct tag *self, FILE *fp)
|
2007-01-12 19:11:37 +01:00
|
|
|
{
|
2007-02-15 14:42:33 +01:00
|
|
|
return fprintf(fp, "/* <%llx> %s:%u */\n",
|
2007-03-28 16:38:32 +02:00
|
|
|
(unsigned long long)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-24 12:41:46 +01:00
|
|
|
static struct array_type *array_type__new(Dwarf_Die *die)
|
|
|
|
{
|
|
|
|
struct array_type *self = zalloc(sizeof(*self));
|
|
|
|
|
|
|
|
if (self != NULL)
|
|
|
|
tag__init(&self->tag, die);
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2007-07-02 01:04:19 +02:00
|
|
|
static size_t type__fprintf(struct tag *type, const struct cu *cu,
|
|
|
|
const char *name, const struct conf_fprintf *conf,
|
|
|
|
FILE *fp);
|
|
|
|
|
2007-02-15 14:36:49 +01:00
|
|
|
static size_t array_type__fprintf(const struct tag *tag_self,
|
|
|
|
const struct cu *cu, const char *name,
|
2007-07-02 01:04:19 +02:00
|
|
|
const struct conf_fprintf *conf,
|
|
|
|
FILE *fp)
|
2007-01-24 12:41:46 +01:00
|
|
|
{
|
|
|
|
struct array_type *self = tag__array_type(tag_self);
|
2007-07-02 01:04:19 +02:00
|
|
|
struct tag *type = cu__find_tag_by_id(cu, tag_self->type);
|
|
|
|
size_t printed = type__fprintf(type, cu, name, conf, fp);
|
2007-01-24 12:41:46 +01:00
|
|
|
int i;
|
2007-07-02 01:04:19 +02:00
|
|
|
|
2007-02-15 14:36:49 +01:00
|
|
|
for (i = 0; i < self->dimensions; ++i)
|
2007-02-15 15:28:02 +01:00
|
|
|
printed += fprintf(fp, "[%u]", self->nr_entries[i]);
|
|
|
|
return printed;
|
2007-01-24 12:41:46 +01:00
|
|
|
}
|
|
|
|
|
2007-05-24 17:16:59 +02:00
|
|
|
static void namespace__init(struct namespace *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);
|
2007-05-24 03:38:29 +02:00
|
|
|
INIT_LIST_HEAD(&self->tags);
|
2007-05-24 17:16:59 +02:00
|
|
|
self->name = strings__add(attr_string(die, DW_AT_name));
|
|
|
|
self->nr_tags = 0;
|
|
|
|
}
|
|
|
|
|
2007-05-24 17:30:33 +02:00
|
|
|
static struct namespace *namespace__new(Dwarf_Die *die)
|
|
|
|
{
|
|
|
|
struct namespace *self = malloc(sizeof(*self));
|
|
|
|
|
|
|
|
if (self != NULL)
|
|
|
|
namespace__init(self, die);
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2007-05-24 17:16:59 +02:00
|
|
|
static void type__init(struct type *self, Dwarf_Die *die)
|
|
|
|
{
|
|
|
|
namespace__init(&self->namespace, die);
|
|
|
|
INIT_LIST_HEAD(&self->node);
|
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-05-24 23:45:34 +02:00
|
|
|
self->specification = attr_type(die, DW_AT_specification);
|
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-05-24 23:45:34 +02:00
|
|
|
const char *type__name(struct type *self, const struct cu *cu)
|
|
|
|
{
|
|
|
|
/* Check if the tag doesn't comes with a DW_AT_name attribute... */
|
2007-05-26 20:47:39 +02:00
|
|
|
if (self->namespace.name == NULL &&
|
|
|
|
/* No? So it can have a DW_TAG_specification... */
|
|
|
|
self->specification != 0 &&
|
|
|
|
cu != NULL) {
|
2007-05-24 23:45:34 +02:00
|
|
|
struct tag *tag = cu__find_tag_by_id(cu, self->specification);
|
|
|
|
if (tag == NULL) {
|
2007-05-26 20:40:52 +02:00
|
|
|
tag__id_not_found(&self->namespace.tag, self->specification);
|
2007-05-24 23:45:34 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/* ... and now we cache the result in this tag ->name field */
|
|
|
|
self->namespace.name = tag__type(tag)->namespace.name;
|
|
|
|
}
|
|
|
|
|
|
|
|
return self->namespace.name;
|
|
|
|
}
|
|
|
|
|
2007-05-06 19:50:28 +02:00
|
|
|
size_t typedef__fprintf(const struct tag *tag_self, const struct cu *cu,
|
2007-07-02 01:04:19 +02:00
|
|
|
const struct conf_fprintf *conf, FILE *fp)
|
2007-01-12 16:04:05 +01:00
|
|
|
{
|
2007-05-24 23:45:34 +02:00
|
|
|
struct type *self = tag__type(tag_self);
|
2007-07-02 01:04:19 +02:00
|
|
|
const struct conf_fprintf *pconf = conf ?: &conf_fprintf__defaults;
|
2007-05-26 19:50:51 +02:00
|
|
|
const struct tag *type;
|
2007-01-12 16:04:05 +01:00
|
|
|
const struct tag *ptr_type;
|
|
|
|
char bf[512];
|
2007-02-15 14:36:49 +01:00
|
|
|
int is_pointer = 0;
|
2007-02-15 15:28:02 +01:00
|
|
|
size_t printed;
|
2007-01-12 16:04:05 +01:00
|
|
|
|
2007-05-26 19:50:51 +02:00
|
|
|
/*
|
|
|
|
* Check for void (humm, perhaps we should have a fake void tag instance
|
|
|
|
* to avoid all these checks?
|
|
|
|
*/
|
|
|
|
if (tag_self->type == 0)
|
|
|
|
return fprintf(fp, "typedef void %s", type__name(self, cu));
|
|
|
|
|
|
|
|
type = cu__find_tag_by_id(cu, tag_self->type);
|
2007-01-12 19:29:53 +01:00
|
|
|
if (type == NULL) {
|
2007-01-29 13:42:03 +01:00
|
|
|
tag__type_not_found(tag_self);
|
2007-02-15 14:46:49 +01:00
|
|
|
return 0;
|
2007-01-12 19:29:53 +01:00
|
|
|
}
|
|
|
|
|
2007-01-12 16:04:05 +01:00
|
|
|
switch (type->tag) {
|
2007-01-24 12:41:46 +01:00
|
|
|
case DW_TAG_array_type:
|
2007-02-15 15:28:02 +01:00
|
|
|
printed = fprintf(fp, "typedef ");
|
|
|
|
return printed + array_type__fprintf(type, cu,
|
2007-05-24 23:45:34 +02:00
|
|
|
type__name(self, cu),
|
2007-07-02 01:04:19 +02:00
|
|
|
pconf, fp);
|
2007-01-12 16:04:05 +01:00
|
|
|
case DW_TAG_pointer_type:
|
2007-01-16 15:19:06 +01:00
|
|
|
if (type->type == 0) /* void pointer */
|
|
|
|
break;
|
2007-01-12 16:04:05 +01:00
|
|
|
ptr_type = cu__find_tag_by_id(cu, type->type);
|
2007-01-16 15:19:06 +01:00
|
|
|
if (ptr_type == NULL) {
|
2007-01-29 13:42:03 +01:00
|
|
|
tag__type_not_found(type);
|
2007-02-15 14:46:49 +01:00
|
|
|
return 0;
|
2007-01-16 15:19:06 +01:00
|
|
|
}
|
2007-01-12 16:04:05 +01:00
|
|
|
if (ptr_type->tag != DW_TAG_subroutine_type)
|
|
|
|
break;
|
|
|
|
type = ptr_type;
|
|
|
|
is_pointer = 1;
|
|
|
|
/* Fall thru */
|
|
|
|
case DW_TAG_subroutine_type:
|
2007-02-15 15:28:02 +01:00
|
|
|
printed = fprintf(fp, "typedef ");
|
|
|
|
return printed + ftype__fprintf(tag__ftype(type), cu,
|
2007-05-24 23:45:34 +02:00
|
|
|
type__name(self, cu),
|
|
|
|
0, is_pointer, 0,
|
2007-02-15 15:28:02 +01:00
|
|
|
fp);
|
2007-01-12 16:04:05 +01:00
|
|
|
case DW_TAG_structure_type: {
|
2007-05-24 23:45:34 +02:00
|
|
|
struct type *ctype = tag__type(type);
|
2007-01-12 16:04:05 +01:00
|
|
|
|
2007-05-24 23:45:34 +02:00
|
|
|
if (type__name(ctype, cu) != NULL)
|
2007-02-15 14:46:49 +01:00
|
|
|
return fprintf(fp, "typedef struct %s %s",
|
2007-05-24 23:45:34 +02:00
|
|
|
type__name(ctype, cu),
|
|
|
|
type__name(self, cu));
|
2007-01-12 16:04:05 +01:00
|
|
|
}
|
2007-01-25 13:31:36 +01:00
|
|
|
}
|
2007-01-12 16:04:05 +01:00
|
|
|
|
2007-02-15 14:46:49 +01:00
|
|
|
return fprintf(fp, "typedef %s %s",
|
2007-05-24 23:45:34 +02:00
|
|
|
tag__name(type, cu, bf, sizeof(bf)),
|
|
|
|
type__name(self, cu));
|
2007-01-12 16:04:05 +01:00
|
|
|
}
|
|
|
|
|
2007-05-26 17:39:16 +02:00
|
|
|
static size_t imported_declaration__fprintf(const struct tag *self,
|
|
|
|
const struct cu *cu, FILE *fp)
|
|
|
|
{
|
|
|
|
char bf[512];
|
|
|
|
const struct tag *decl = cu__find_tag_by_id(cu, self->type);
|
|
|
|
|
|
|
|
return fprintf(fp, "using ::%s", tag__name(decl, cu, bf, sizeof(bf)));
|
|
|
|
}
|
|
|
|
|
2007-05-26 15:54:27 +02:00
|
|
|
static size_t imported_module__fprintf(const struct tag *self,
|
|
|
|
const struct cu *cu, FILE *fp)
|
|
|
|
{
|
|
|
|
const struct tag *module = cu__find_tag_by_id(cu, self->type);
|
|
|
|
const char *name = "<IMPORTED MODULE ERROR!>";
|
|
|
|
|
2007-05-31 07:21:36 +02:00
|
|
|
if (tag__is_namespace(module))
|
2007-05-26 15:54:27 +02:00
|
|
|
name = tag__namespace(module)->name;
|
|
|
|
|
|
|
|
return fprintf(fp, "using namespace %s", name);
|
|
|
|
}
|
|
|
|
|
2007-05-24 23:45:34 +02:00
|
|
|
size_t enumeration__fprintf(const struct tag *tag_self, const struct cu *cu,
|
2007-05-06 19:50:28 +02:00
|
|
|
const struct conf_fprintf *conf, FILE *fp)
|
[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-05-24 23:45:34 +02:00
|
|
|
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;
|
2007-05-24 23:45:34 +02:00
|
|
|
size_t printed = fprintf(fp, "enum%s%s {\n",
|
|
|
|
type__name(self, cu) ? " " : "",
|
|
|
|
type__name(self, cu) ?: "");
|
2007-04-28 21:13:35 +02:00
|
|
|
size_t indent = conf->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-13 13:40:33 +01:00
|
|
|
if (indent >= sizeof(tabs))
|
|
|
|
indent = sizeof(tabs) - 1;
|
2007-04-28 21:13:35 +02:00
|
|
|
|
2007-05-24 03:38:29 +02:00
|
|
|
type__for_each_enumerator(self, pos)
|
2007-02-15 15:28:02 +01:00
|
|
|
printed += fprintf(fp, "%.*s\t%s = %u,\n", indent, tabs,
|
|
|
|
pos->name, pos->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
|
|
|
|
2007-02-15 15:28:02 +01:00
|
|
|
return printed + fprintf(fp, "%.*s}%s%s", indent, tabs,
|
2007-04-28 21:13:35 +02:00
|
|
|
conf->suffix ? " " : "", conf->suffix ?: "");
|
[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-02-02 14:56:53 +01:00
|
|
|
static enum vlocation dwarf__location(Dwarf_Die *die)
|
|
|
|
{
|
|
|
|
Dwarf_Op *expr;
|
|
|
|
size_t exprlen;
|
|
|
|
enum vlocation location = LOCATION_UNKNOWN;
|
|
|
|
|
|
|
|
if (attr_location(die, &expr, &exprlen) != 0)
|
|
|
|
location = LOCATION_OPTIMIZED;
|
|
|
|
else if (exprlen != 0)
|
|
|
|
switch (expr->atom) {
|
|
|
|
case DW_OP_addr:
|
|
|
|
location = LOCATION_GLOBAL; break;
|
|
|
|
case DW_OP_reg1 ... DW_OP_reg31:
|
|
|
|
case DW_OP_breg0 ... DW_OP_breg31:
|
|
|
|
location = LOCATION_REGISTER; break;
|
|
|
|
case DW_OP_fbreg:
|
|
|
|
location = LOCATION_LOCAL; break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return location;
|
|
|
|
}
|
|
|
|
|
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-25 19:24:09 +01:00
|
|
|
self->abstract_origin = attr_type(die, DW_AT_abstract_origin);
|
2007-02-02 14:56:53 +01:00
|
|
|
/* variable is visible outside of its enclosing cu */
|
|
|
|
self->external = dwarf_hasattr(die, DW_AT_external);
|
|
|
|
/* non-defining declaration of an object */
|
|
|
|
self->declaration = dwarf_hasattr(die, DW_AT_declaration);
|
|
|
|
self->location = LOCATION_UNKNOWN;
|
|
|
|
if (!self->declaration)
|
|
|
|
self->location = dwarf__location(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
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2007-01-29 13:42:03 +01:00
|
|
|
static struct cu *cu__new(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-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 "";
|
|
|
|
}
|
|
|
|
|
2007-05-24 17:40:43 +02:00
|
|
|
static struct tag *namespace__find_tag_by_id(const struct namespace *self,
|
|
|
|
const Dwarf_Off id)
|
2007-05-24 04:19:35 +02:00
|
|
|
{
|
|
|
|
struct tag *pos;
|
|
|
|
|
|
|
|
if (id == 0)
|
|
|
|
return NULL;
|
|
|
|
|
2007-05-24 17:40:43 +02:00
|
|
|
namespace__for_each_tag(self, pos) {
|
2007-05-24 04:19:35 +02:00
|
|
|
if (pos->id == id)
|
|
|
|
return pos;
|
|
|
|
|
2007-05-24 17:40:43 +02:00
|
|
|
/* Look for nested namespaces */
|
2007-05-31 07:21:36 +02:00
|
|
|
if (tag__is_struct(pos) || tag__is_union(pos) ||
|
|
|
|
tag__is_namespace(pos)) {
|
2007-05-24 04:19:35 +02:00
|
|
|
struct tag *tag =
|
2007-05-24 17:40:43 +02:00
|
|
|
namespace__find_tag_by_id(tag__namespace(pos), id);
|
2007-05-24 04:19:35 +02:00
|
|
|
if (tag != NULL)
|
|
|
|
return tag;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
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-05-24 04:19:35 +02: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
|
|
|
|
2007-05-24 17:40:43 +02:00
|
|
|
/* Look for nested namespaces */
|
2007-05-31 07:21:36 +02:00
|
|
|
if (tag__is_struct(pos) || tag__is_union(pos) ||
|
|
|
|
tag__is_namespace(pos)) {
|
2007-05-24 04:19:35 +02:00
|
|
|
struct tag *tag =
|
2007-05-24 17:40:43 +02:00
|
|
|
namespace__find_tag_by_id(tag__namespace(pos), id);
|
2007-05-24 04:19:35 +02:00
|
|
|
if (tag != NULL)
|
|
|
|
return tag;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
return NULL;
|
2006-12-20 17:10:07 +01:00
|
|
|
}
|
|
|
|
|
2007-01-28 05:18:34 +01:00
|
|
|
struct tag *cu__find_first_typedef_of_type(const struct cu *self,
|
|
|
|
const Dwarf_Off type)
|
|
|
|
{
|
|
|
|
struct tag *pos;
|
|
|
|
|
|
|
|
if (type == 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
list_for_each_entry(pos, &self->tags, node)
|
|
|
|
if (pos->tag == DW_TAG_typedef && pos->type == type)
|
|
|
|
return pos;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-01-30 19:53:01 +01:00
|
|
|
struct tag *cu__find_base_type_by_name(const struct cu *self, const char *name)
|
|
|
|
{
|
|
|
|
struct tag *pos;
|
|
|
|
|
|
|
|
if (name == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
list_for_each_entry(pos, &self->tags, node) {
|
|
|
|
if (pos->tag == DW_TAG_base_type &&
|
|
|
|
strcmp(tag__base_type(pos)->name, name) == 0)
|
|
|
|
return pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-11-16 21:16:56 +01:00
|
|
|
struct tag *cu__find_struct_by_name(const struct cu *self, const char *name,
|
|
|
|
const int include_decls)
|
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
|
|
|
|
2007-05-31 06:53:01 +02:00
|
|
|
if (!tag__is_struct(pos))
|
2006-12-29 23:58:03 +01:00
|
|
|
continue;
|
|
|
|
|
2007-01-07 16:11:20 +01:00
|
|
|
type = tag__type(pos);
|
2007-11-16 21:16:56 +01:00
|
|
|
if (type__name(type, self) != NULL &&
|
|
|
|
strcmp(type__name(type, self), name) == 0) {
|
|
|
|
if (type->declaration) {
|
|
|
|
if (include_decls)
|
|
|
|
return pos;
|
|
|
|
} else
|
|
|
|
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,
|
2007-11-16 21:16:56 +01:00
|
|
|
struct cu **cu, const char *name,
|
|
|
|
const int include_decls)
|
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-11-16 21:16:56 +01:00
|
|
|
struct tag *tag = cu__find_struct_by_name(pos, name,
|
|
|
|
include_decls);
|
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;
|
|
|
|
}
|
|
|
|
|
2007-05-24 22:41:16 +02:00
|
|
|
struct tag *cus__find_tag_by_id(const struct cus *self,
|
|
|
|
struct cu **cu, const Dwarf_Off id)
|
|
|
|
{
|
|
|
|
struct cu *pos;
|
|
|
|
|
|
|
|
list_for_each_entry(pos, &self->cus, node) {
|
|
|
|
struct tag *tag = cu__find_tag_by_id(pos, id);
|
|
|
|
|
|
|
|
if (tag != NULL) {
|
|
|
|
if (cu != NULL)
|
|
|
|
*cu = pos;
|
|
|
|
return tag;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
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-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-05-26 22:53:40 +02:00
|
|
|
static struct tag *list__find_tag_by_id(const struct list_head *self,
|
|
|
|
const Dwarf_Off id)
|
2007-01-13 14:37:41 +01:00
|
|
|
{
|
2007-05-26 22:53:40 +02:00
|
|
|
struct tag *pos, *tag;
|
2007-01-13 14:37:41 +01:00
|
|
|
|
2007-05-26 22:53:40 +02:00
|
|
|
list_for_each_entry(pos, self, node) {
|
2007-01-13 14:37:41 +01:00
|
|
|
if (pos->id == id)
|
|
|
|
return pos;
|
2007-01-07 20:57:00 +01:00
|
|
|
|
2007-05-26 22:53:40 +02:00
|
|
|
switch (pos->tag) {
|
|
|
|
case DW_TAG_namespace:
|
2007-05-29 17:41:25 +02:00
|
|
|
case DW_TAG_structure_type:
|
|
|
|
case DW_TAG_union_type:
|
2007-05-26 22:53:40 +02:00
|
|
|
tag = list__find_tag_by_id(&tag__namespace(pos)->tags, id);
|
|
|
|
break;
|
|
|
|
case DW_TAG_subprogram:
|
|
|
|
tag = list__find_tag_by_id(&tag__ftype(pos)->parms, id);
|
|
|
|
if (tag == NULL)
|
|
|
|
tag = list__find_tag_by_id(&tag__function(pos)->lexblock.tags, id);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
continue;
|
2007-01-07 20:57:00 +01:00
|
|
|
}
|
2007-05-26 22:53:40 +02:00
|
|
|
|
|
|
|
if (tag != NULL)
|
|
|
|
return tag;
|
2007-01-26 03:29:53 +01:00
|
|
|
}
|
2007-01-07 20:57:00 +01:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-05-26 22:53:40 +02:00
|
|
|
static struct tag *cu__find_parameter_by_id(const struct cu *self,
|
|
|
|
const Dwarf_Off id)
|
|
|
|
{
|
|
|
|
return list__find_tag_by_id(&self->tags, id);
|
|
|
|
}
|
|
|
|
|
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) {
|
2007-01-29 13:42:03 +01:00
|
|
|
tag__type_not_found(self);
|
2007-01-12 02:09:06 +01:00
|
|
|
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) {
|
2007-01-29 13:42:03 +01:00
|
|
|
tag__type_not_found(self);
|
2007-01-12 14:06:59 +01:00
|
|
|
snprintf(bf, len,
|
|
|
|
"<ERROR: type not found!> %c", ptr_char);
|
|
|
|
} else {
|
2007-02-02 14:56:53 +01:00
|
|
|
char tmpbf[512];
|
2007-01-12 14:06:59 +01:00
|
|
|
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
|
|
|
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
|
|
|
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) {
|
2007-01-29 13:42:03 +01:00
|
|
|
tag__type_not_found(self);
|
2007-01-12 02:09:06 +01:00
|
|
|
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) {
|
2007-01-29 13:42:03 +01:00
|
|
|
tag__type_not_found(self);
|
2007-01-12 02:09:06 +01:00
|
|
|
strncpy(bf, "<ERROR>", len);
|
|
|
|
} else
|
|
|
|
return tag__name(type, cu, bf, len);
|
2007-01-13 19:04:21 +01:00
|
|
|
break;
|
2007-02-15 14:36:49 +01:00
|
|
|
case DW_TAG_subroutine_type: {
|
|
|
|
FILE *bfp = fmemopen(bf, len, "w");
|
|
|
|
if (bfp != NULL) {
|
|
|
|
ftype__fprintf(tag__ftype(self), cu, NULL, 0, 0, 0, bfp);
|
|
|
|
fclose(bfp);
|
|
|
|
} else
|
|
|
|
strncpy(bf, "<ERROR>", len);
|
|
|
|
}
|
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-05-24 23:45:34 +02:00
|
|
|
type__name(tag__type(self), cu) ?: "");
|
2007-01-13 19:04:21 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2006-10-28 23:22:42 +02:00
|
|
|
return bf;
|
|
|
|
}
|
|
|
|
|
2007-02-02 14:56:53 +01:00
|
|
|
static struct tag *variable__type(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-02-02 14:56:53 +01:00
|
|
|
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
|
|
|
|
2007-02-02 14:56:53 +01:00
|
|
|
if (self->tag.type != 0)
|
|
|
|
return cu__find_tag_by_id(cu, self->tag.type);
|
|
|
|
else if (self->abstract_origin != 0) {
|
|
|
|
var = cu__find_variable_by_id(cu, self->abstract_origin);
|
|
|
|
if (var)
|
|
|
|
return variable__type(var, cu);
|
[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-02-02 14:56:53 +01:00
|
|
|
|
[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-02-02 14:56:53 +01:00
|
|
|
const char *variable__type_name(const struct variable *self,
|
|
|
|
const struct cu *cu,
|
|
|
|
char *bf, size_t len)
|
|
|
|
{
|
|
|
|
const struct tag *tag = variable__type(self, cu);
|
|
|
|
return tag != NULL ? tag__name(tag, cu, bf, len) : NULL;
|
|
|
|
}
|
|
|
|
|
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-02-02 14:56:53 +01:00
|
|
|
static const char *variable__prefix(const struct variable *var)
|
|
|
|
{
|
|
|
|
switch (var->location) {
|
|
|
|
case LOCATION_REGISTER:
|
|
|
|
return "register ";
|
|
|
|
case LOCATION_UNKNOWN:
|
|
|
|
if (var->external && var->declaration)
|
|
|
|
return "extern ";
|
|
|
|
break;
|
|
|
|
case LOCATION_GLOBAL:
|
|
|
|
if (!var->external)
|
|
|
|
return "static ";
|
|
|
|
break;
|
|
|
|
case LOCATION_LOCAL:
|
|
|
|
case LOCATION_OPTIMIZED:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
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);
|
2007-07-09 01:33:56 +02:00
|
|
|
self->offset = attr_offset(die, DW_AT_data_member_location);
|
2007-01-03 23:22:51 +01:00
|
|
|
self->bit_size = attr_numeric(die, DW_AT_bit_size);
|
|
|
|
self->bit_offset = attr_numeric(die, DW_AT_bit_offset);
|
2007-05-24 18:57:08 +02:00
|
|
|
self->accessibility = attr_numeric(die, DW_AT_accessibility);
|
|
|
|
self->virtuality = attr_numeric(die, DW_AT_virtuality);
|
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-02-01 16:17:41 +01:00
|
|
|
void class_member__delete(struct class_member *self)
|
2007-01-30 16:32:55 +01:00
|
|
|
{
|
|
|
|
free(self);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct class_member *class_member__clone(const struct class_member *from)
|
|
|
|
{
|
|
|
|
struct class_member *self = malloc(sizeof(*self));
|
|
|
|
|
|
|
|
if (self != NULL)
|
|
|
|
memcpy(self, from, sizeof(*self));
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t class_member__size(const struct class_member *self,
|
|
|
|
const struct cu *cu)
|
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) {
|
2007-01-29 13:42:03 +01:00
|
|
|
tag__type_not_found(&self->tag);
|
2007-01-12 02:09:06 +01:00
|
|
|
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));
|
2007-01-25 19:24:09 +01:00
|
|
|
self->abstract_origin = attr_type(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? */
|
2007-05-26 21:15:27 +02:00
|
|
|
struct tag *alias =
|
2007-01-07 20:57:00 +01:00
|
|
|
cu__find_parameter_by_id(cu, self->abstract_origin);
|
2007-01-12 02:09:06 +01:00
|
|
|
if (alias == NULL) {
|
2007-05-26 20:40:52 +02:00
|
|
|
tag__id_not_found(&self->tag, self->abstract_origin);
|
2007-01-12 02:09:06 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
2007-01-07 20:57:00 +01:00
|
|
|
/* Now cache the result in this tag ->name field */
|
2007-05-26 21:15:27 +02:00
|
|
|
self->name = tag__parameter(alias)->name;
|
2007-01-07 20:57:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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? */
|
2007-05-26 21:15:27 +02:00
|
|
|
struct tag *alias =
|
2007-01-07 20:57:00 +01:00
|
|
|
cu__find_parameter_by_id(cu, self->abstract_origin);
|
2007-01-12 02:09:06 +01:00
|
|
|
if (alias == NULL) {
|
2007-05-26 20:40:52 +02:00
|
|
|
tag__id_not_found(&self->tag, self->abstract_origin);
|
2007-01-12 02:09:06 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2007-01-07 20:57:00 +01:00
|
|
|
/* Now cache the result in this tag ->name and type fields */
|
2007-05-26 21:15:27 +02:00
|
|
|
self->name = tag__parameter(alias)->name;
|
|
|
|
self->tag.type = tag__parameter(alias)->tag.type;
|
2007-01-07 20:57:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2007-01-25 19:24:09 +01:00
|
|
|
self->tag.type = attr_type(die, DW_AT_abstract_origin);
|
2007-01-03 23:22:51 +01:00
|
|
|
|
|
|
|
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-05-24 23:45:34 +02:00
|
|
|
static size_t union__fprintf(struct type *self, const struct cu *cu,
|
2007-04-28 21:13:35 +02:00
|
|
|
const struct conf_fprintf *conf, FILE *fp);
|
[CLASSES]: Ditch class_member__names
Was a awful function, to replace it added some new __snprintf methods for more
classes (array_type, class_member, etc), the end result is a much nicer
rendering, for instance:
@@ -6549,11 +6549,11 @@
/* XXX 2 bytes hole, try to pack */
union {
- struct ff_constant_effect constant; /* 10 */
- struct ff_ramp_effect ramp; /* 12 */
- struct ff_periodic_effect periodic; /* 28 */
- struct ff_condition_effect condition[2]; /* 24 */
- struct ff_rumble_effect rumble; /* 4 */
+ struct ff_constant_effect constant; /* 10 */
+ struct ff_ramp_effect ramp; /* 12 */
+ struct ff_periodic_effect periodic; /* 28 */
+ struct ff_condition_effect condition[2]; /* 24 */
+ struct ff_rumble_effect rumble; /* 4 */
} u; /* 16 28 */
/* --- cacheline 1 boundary (32 bytes) was 12 bytes ago --- */
}; /* size: 44, cachelines: 2 */
Previously when such big class members appeared the comments with the size and
offset were unaligned, now its only in extreme cases, such as the array above
that things get unaligned.
End result is a smaller library:
[acme@newtoy pahole]$ codiff -V build/libclasses.so.orig build/libclasses.so
/home/acme/pahole/classes.c:
struct array_type | -4
nr_members: -1
-const char *name /* 36 4 */
1 struct changed
enumeration__print | +10 # 175 -> 185
union__snprintf | +32 # 576 -> 608
union__print | +16 # 182 -> 198
class_member__names | -851 (removed)
class_member__print | -721 # 1218 -> 497
class__print_struct | +54 # 1403 -> 1457
6 functions changed, 112 bytes added, 1572 bytes removed, diff: -1460
/home/acme/pahole/classes.c:
array_type__snprintf | +249 (added)
class_member__snprintf | +892 (added)
2 functions changed, 1141 bytes added
build/libclasses.so:
8 functions changed, 1253 bytes added, 1572 bytes removed, diff: -319
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 17:19:55 +01:00
|
|
|
|
2007-04-28 21:13:35 +02:00
|
|
|
static size_t type__fprintf(struct tag *type, const struct cu *cu,
|
|
|
|
const char *name, const struct conf_fprintf *conf,
|
|
|
|
FILE *fp)
|
[CLASSES]: Ditch class_member__names
Was a awful function, to replace it added some new __snprintf methods for more
classes (array_type, class_member, etc), the end result is a much nicer
rendering, for instance:
@@ -6549,11 +6549,11 @@
/* XXX 2 bytes hole, try to pack */
union {
- struct ff_constant_effect constant; /* 10 */
- struct ff_ramp_effect ramp; /* 12 */
- struct ff_periodic_effect periodic; /* 28 */
- struct ff_condition_effect condition[2]; /* 24 */
- struct ff_rumble_effect rumble; /* 4 */
+ struct ff_constant_effect constant; /* 10 */
+ struct ff_ramp_effect ramp; /* 12 */
+ struct ff_periodic_effect periodic; /* 28 */
+ struct ff_condition_effect condition[2]; /* 24 */
+ struct ff_rumble_effect rumble; /* 4 */
} u; /* 16 28 */
/* --- cacheline 1 boundary (32 bytes) was 12 bytes ago --- */
}; /* size: 44, cachelines: 2 */
Previously when such big class members appeared the comments with the size and
offset were unaligned, now its only in extreme cases, such as the array above
that things get unaligned.
End result is a smaller library:
[acme@newtoy pahole]$ codiff -V build/libclasses.so.orig build/libclasses.so
/home/acme/pahole/classes.c:
struct array_type | -4
nr_members: -1
-const char *name /* 36 4 */
1 struct changed
enumeration__print | +10 # 175 -> 185
union__snprintf | +32 # 576 -> 608
union__print | +16 # 182 -> 198
class_member__names | -851 (removed)
class_member__print | -721 # 1218 -> 497
class__print_struct | +54 # 1403 -> 1457
6 functions changed, 112 bytes added, 1572 bytes removed, diff: -1460
/home/acme/pahole/classes.c:
array_type__snprintf | +249 (added)
class_member__snprintf | +892 (added)
2 functions changed, 1141 bytes added
build/libclasses.so:
8 functions changed, 1253 bytes added, 1572 bytes removed, diff: -319
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 17:19:55 +01:00
|
|
|
{
|
|
|
|
char tbf[128];
|
2007-07-05 01:36:28 +02:00
|
|
|
char namebf[256];
|
2007-01-13 19:14:45 +01:00
|
|
|
struct type *ctype;
|
2007-04-28 21:13:35 +02:00
|
|
|
struct conf_fprintf tconf;
|
[LIB]: Expand typedefs in the expand_types mode
[acme@filo pahole]$ cat examples/expand_typedefs.c
<SNIP>
typedef struct {
int a, b, c;
} inner;
static struct outer {
int q, b;
inner m;
} foo;
<SNIP>
[acme@filo pahole]$ pahole --expand_types examples/expand_typedefs
/* <158> /home/acme/git/pahole/examples/expand_typedefs.c:7 */
struct outer {
int q; /* 0 4 */
int b; /* 4 4 */
/* typedef inner */ struct {
int a; /* 0 4 */
int b; /* 4 4 */
int c; /* 8 4 */
} m; /* 8 12 */
}; /* size: 20, cachelines: 1 */
/* last cacheline: 20 bytes */
/* definitions: 1 */
[acme@filo pahole]$
For now it does all typedef expansions, which in at least the base types may be
a bit too much, e.g. u32 -> unsigned long int, lets see if somebody complains,
perhaps even myself 8) If that is the case we can add yet another command line
option to specify that such base type expansions should be filtered out, making
the expand_types parameter be flag mask, not just a boolean as it is today.
To see a more complete output look at:
http://oops.ghostprotocols.net:81/acme/dwarves/vmlinux-pahole-expand_types-typedef_unfolding.txt
Suggested by Jeff Muizelaar.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2007-02-27 02:57:38 +01:00
|
|
|
size_t printed = 0;
|
2007-07-05 01:36:28 +02:00
|
|
|
int expand_types = conf->expand_types;
|
2007-07-07 19:41:41 +02:00
|
|
|
int suppress_offset_comment = conf->suppress_offset_comment;
|
[CLASSES]: Ditch class_member__names
Was a awful function, to replace it added some new __snprintf methods for more
classes (array_type, class_member, etc), the end result is a much nicer
rendering, for instance:
@@ -6549,11 +6549,11 @@
/* XXX 2 bytes hole, try to pack */
union {
- struct ff_constant_effect constant; /* 10 */
- struct ff_ramp_effect ramp; /* 12 */
- struct ff_periodic_effect periodic; /* 28 */
- struct ff_condition_effect condition[2]; /* 24 */
- struct ff_rumble_effect rumble; /* 4 */
+ struct ff_constant_effect constant; /* 10 */
+ struct ff_ramp_effect ramp; /* 12 */
+ struct ff_periodic_effect periodic; /* 28 */
+ struct ff_condition_effect condition[2]; /* 24 */
+ struct ff_rumble_effect rumble; /* 4 */
} u; /* 16 28 */
/* --- cacheline 1 boundary (32 bytes) was 12 bytes ago --- */
}; /* size: 44, cachelines: 2 */
Previously when such big class members appeared the comments with the size and
offset were unaligned, now its only in extreme cases, such as the array above
that things get unaligned.
End result is a smaller library:
[acme@newtoy pahole]$ codiff -V build/libclasses.so.orig build/libclasses.so
/home/acme/pahole/classes.c:
struct array_type | -4
nr_members: -1
-const char *name /* 36 4 */
1 struct changed
enumeration__print | +10 # 175 -> 185
union__snprintf | +32 # 576 -> 608
union__print | +16 # 182 -> 198
class_member__names | -851 (removed)
class_member__print | -721 # 1218 -> 497
class__print_struct | +54 # 1403 -> 1457
6 functions changed, 112 bytes added, 1572 bytes removed, diff: -1460
/home/acme/pahole/classes.c:
array_type__snprintf | +249 (added)
class_member__snprintf | +892 (added)
2 functions changed, 1141 bytes added
build/libclasses.so:
8 functions changed, 1253 bytes added, 1572 bytes removed, diff: -319
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 17:19:55 +01:00
|
|
|
|
|
|
|
if (type == NULL)
|
2007-02-27 03:00:56 +01:00
|
|
|
goto out_type_not_found;
|
[CLASSES]: Ditch class_member__names
Was a awful function, to replace it added some new __snprintf methods for more
classes (array_type, class_member, etc), the end result is a much nicer
rendering, for instance:
@@ -6549,11 +6549,11 @@
/* XXX 2 bytes hole, try to pack */
union {
- struct ff_constant_effect constant; /* 10 */
- struct ff_ramp_effect ramp; /* 12 */
- struct ff_periodic_effect periodic; /* 28 */
- struct ff_condition_effect condition[2]; /* 24 */
- struct ff_rumble_effect rumble; /* 4 */
+ struct ff_constant_effect constant; /* 10 */
+ struct ff_ramp_effect ramp; /* 12 */
+ struct ff_periodic_effect periodic; /* 28 */
+ struct ff_condition_effect condition[2]; /* 24 */
+ struct ff_rumble_effect rumble; /* 4 */
} u; /* 16 28 */
/* --- cacheline 1 boundary (32 bytes) was 12 bytes ago --- */
}; /* size: 44, cachelines: 2 */
Previously when such big class members appeared the comments with the size and
offset were unaligned, now its only in extreme cases, such as the array above
that things get unaligned.
End result is a smaller library:
[acme@newtoy pahole]$ codiff -V build/libclasses.so.orig build/libclasses.so
/home/acme/pahole/classes.c:
struct array_type | -4
nr_members: -1
-const char *name /* 36 4 */
1 struct changed
enumeration__print | +10 # 175 -> 185
union__snprintf | +32 # 576 -> 608
union__print | +16 # 182 -> 198
class_member__names | -851 (removed)
class_member__print | -721 # 1218 -> 497
class__print_struct | +54 # 1403 -> 1457
6 functions changed, 112 bytes added, 1572 bytes removed, diff: -1460
/home/acme/pahole/classes.c:
array_type__snprintf | +249 (added)
class_member__snprintf | +892 (added)
2 functions changed, 1141 bytes added
build/libclasses.so:
8 functions changed, 1253 bytes added, 1572 bytes removed, diff: -319
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 17:19:55 +01:00
|
|
|
|
2007-07-05 01:36:28 +02:00
|
|
|
if (conf->expand_pointers) {
|
|
|
|
int nr_indirections = 0;
|
|
|
|
|
|
|
|
while (type->tag == DW_TAG_pointer_type && type->type != 0) {
|
|
|
|
type = cu__find_tag_by_id(cu, type->type);
|
|
|
|
if (type == NULL)
|
|
|
|
goto out_type_not_found;
|
|
|
|
++nr_indirections;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nr_indirections > 0) {
|
|
|
|
const size_t len = strlen(name);
|
|
|
|
if (len + nr_indirections >= sizeof(namebf))
|
|
|
|
goto out_type_not_found;
|
|
|
|
memset(namebf, '*', nr_indirections);
|
|
|
|
memcpy(namebf + nr_indirections, name, len);
|
|
|
|
namebf[len + nr_indirections] = '\0';
|
|
|
|
name = namebf;
|
|
|
|
}
|
|
|
|
|
|
|
|
expand_types = nr_indirections;
|
2007-07-07 19:41:41 +02:00
|
|
|
if (!suppress_offset_comment)
|
|
|
|
suppress_offset_comment = !!nr_indirections;
|
2007-07-05 01:36:28 +02:00
|
|
|
|
|
|
|
/* Avoid loops */
|
|
|
|
if (type->recursivity_level != 0)
|
|
|
|
expand_types = 0;
|
|
|
|
++type->recursivity_level;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (expand_types) {
|
2007-04-28 14:07:35 +02:00
|
|
|
int typedef_expanded = 0;
|
|
|
|
|
[LIB]: Expand typedefs in the expand_types mode
[acme@filo pahole]$ cat examples/expand_typedefs.c
<SNIP>
typedef struct {
int a, b, c;
} inner;
static struct outer {
int q, b;
inner m;
} foo;
<SNIP>
[acme@filo pahole]$ pahole --expand_types examples/expand_typedefs
/* <158> /home/acme/git/pahole/examples/expand_typedefs.c:7 */
struct outer {
int q; /* 0 4 */
int b; /* 4 4 */
/* typedef inner */ struct {
int a; /* 0 4 */
int b; /* 4 4 */
int c; /* 8 4 */
} m; /* 8 12 */
}; /* size: 20, cachelines: 1 */
/* last cacheline: 20 bytes */
/* definitions: 1 */
[acme@filo pahole]$
For now it does all typedef expansions, which in at least the base types may be
a bit too much, e.g. u32 -> unsigned long int, lets see if somebody complains,
perhaps even myself 8) If that is the case we can add yet another command line
option to specify that such base type expansions should be filtered out, making
the expand_types parameter be flag mask, not just a boolean as it is today.
To see a more complete output look at:
http://oops.ghostprotocols.net:81/acme/dwarves/vmlinux-pahole-expand_types-typedef_unfolding.txt
Suggested by Jeff Muizelaar.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2007-02-27 02:57:38 +01:00
|
|
|
while (type->tag == DW_TAG_typedef) {
|
|
|
|
ctype = tag__type(type);
|
|
|
|
if (typedef_expanded)
|
2007-05-24 23:45:34 +02:00
|
|
|
printed += fprintf(fp, " -> %s",
|
|
|
|
type__name(ctype, cu));
|
[LIB]: Expand typedefs in the expand_types mode
[acme@filo pahole]$ cat examples/expand_typedefs.c
<SNIP>
typedef struct {
int a, b, c;
} inner;
static struct outer {
int q, b;
inner m;
} foo;
<SNIP>
[acme@filo pahole]$ pahole --expand_types examples/expand_typedefs
/* <158> /home/acme/git/pahole/examples/expand_typedefs.c:7 */
struct outer {
int q; /* 0 4 */
int b; /* 4 4 */
/* typedef inner */ struct {
int a; /* 0 4 */
int b; /* 4 4 */
int c; /* 8 4 */
} m; /* 8 12 */
}; /* size: 20, cachelines: 1 */
/* last cacheline: 20 bytes */
/* definitions: 1 */
[acme@filo pahole]$
For now it does all typedef expansions, which in at least the base types may be
a bit too much, e.g. u32 -> unsigned long int, lets see if somebody complains,
perhaps even myself 8) If that is the case we can add yet another command line
option to specify that such base type expansions should be filtered out, making
the expand_types parameter be flag mask, not just a boolean as it is today.
To see a more complete output look at:
http://oops.ghostprotocols.net:81/acme/dwarves/vmlinux-pahole-expand_types-typedef_unfolding.txt
Suggested by Jeff Muizelaar.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2007-02-27 02:57:38 +01:00
|
|
|
else {
|
2007-05-24 23:45:34 +02:00
|
|
|
printed += fprintf(fp, "/* typedef %s",
|
|
|
|
type__name(ctype, cu));
|
[LIB]: Expand typedefs in the expand_types mode
[acme@filo pahole]$ cat examples/expand_typedefs.c
<SNIP>
typedef struct {
int a, b, c;
} inner;
static struct outer {
int q, b;
inner m;
} foo;
<SNIP>
[acme@filo pahole]$ pahole --expand_types examples/expand_typedefs
/* <158> /home/acme/git/pahole/examples/expand_typedefs.c:7 */
struct outer {
int q; /* 0 4 */
int b; /* 4 4 */
/* typedef inner */ struct {
int a; /* 0 4 */
int b; /* 4 4 */
int c; /* 8 4 */
} m; /* 8 12 */
}; /* size: 20, cachelines: 1 */
/* last cacheline: 20 bytes */
/* definitions: 1 */
[acme@filo pahole]$
For now it does all typedef expansions, which in at least the base types may be
a bit too much, e.g. u32 -> unsigned long int, lets see if somebody complains,
perhaps even myself 8) If that is the case we can add yet another command line
option to specify that such base type expansions should be filtered out, making
the expand_types parameter be flag mask, not just a boolean as it is today.
To see a more complete output look at:
http://oops.ghostprotocols.net:81/acme/dwarves/vmlinux-pahole-expand_types-typedef_unfolding.txt
Suggested by Jeff Muizelaar.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2007-02-27 02:57:38 +01:00
|
|
|
typedef_expanded = 1;
|
|
|
|
}
|
|
|
|
type = cu__find_tag_by_id(cu, type->type);
|
2007-02-27 03:00:56 +01:00
|
|
|
if (type == NULL)
|
|
|
|
goto out_type_not_found;
|
[LIB]: Expand typedefs in the expand_types mode
[acme@filo pahole]$ cat examples/expand_typedefs.c
<SNIP>
typedef struct {
int a, b, c;
} inner;
static struct outer {
int q, b;
inner m;
} foo;
<SNIP>
[acme@filo pahole]$ pahole --expand_types examples/expand_typedefs
/* <158> /home/acme/git/pahole/examples/expand_typedefs.c:7 */
struct outer {
int q; /* 0 4 */
int b; /* 4 4 */
/* typedef inner */ struct {
int a; /* 0 4 */
int b; /* 4 4 */
int c; /* 8 4 */
} m; /* 8 12 */
}; /* size: 20, cachelines: 1 */
/* last cacheline: 20 bytes */
/* definitions: 1 */
[acme@filo pahole]$
For now it does all typedef expansions, which in at least the base types may be
a bit too much, e.g. u32 -> unsigned long int, lets see if somebody complains,
perhaps even myself 8) If that is the case we can add yet another command line
option to specify that such base type expansions should be filtered out, making
the expand_types parameter be flag mask, not just a boolean as it is today.
To see a more complete output look at:
http://oops.ghostprotocols.net:81/acme/dwarves/vmlinux-pahole-expand_types-typedef_unfolding.txt
Suggested by Jeff Muizelaar.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2007-02-27 02:57:38 +01:00
|
|
|
}
|
|
|
|
if (typedef_expanded)
|
2007-03-28 16:38:32 +02:00
|
|
|
printed += fprintf(fp, " */ ");
|
[LIB]: Expand typedefs in the expand_types mode
[acme@filo pahole]$ cat examples/expand_typedefs.c
<SNIP>
typedef struct {
int a, b, c;
} inner;
static struct outer {
int q, b;
inner m;
} foo;
<SNIP>
[acme@filo pahole]$ pahole --expand_types examples/expand_typedefs
/* <158> /home/acme/git/pahole/examples/expand_typedefs.c:7 */
struct outer {
int q; /* 0 4 */
int b; /* 4 4 */
/* typedef inner */ struct {
int a; /* 0 4 */
int b; /* 4 4 */
int c; /* 8 4 */
} m; /* 8 12 */
}; /* size: 20, cachelines: 1 */
/* last cacheline: 20 bytes */
/* definitions: 1 */
[acme@filo pahole]$
For now it does all typedef expansions, which in at least the base types may be
a bit too much, e.g. u32 -> unsigned long int, lets see if somebody complains,
perhaps even myself 8) If that is the case we can add yet another command line
option to specify that such base type expansions should be filtered out, making
the expand_types parameter be flag mask, not just a boolean as it is today.
To see a more complete output look at:
http://oops.ghostprotocols.net:81/acme/dwarves/vmlinux-pahole-expand_types-typedef_unfolding.txt
Suggested by Jeff Muizelaar.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2007-02-27 02:57:38 +01:00
|
|
|
}
|
|
|
|
|
2007-05-31 07:21:36 +02:00
|
|
|
if (tag__is_struct(type) || tag__is_union(type) ||
|
|
|
|
tag__is_enumeration(type)) {
|
2007-04-28 21:13:35 +02:00
|
|
|
tconf = *conf;
|
|
|
|
tconf.type_spacing -= 8;
|
|
|
|
tconf.prefix = NULL;
|
|
|
|
tconf.suffix = name;
|
|
|
|
tconf.emit_stats = 0;
|
2007-07-07 19:41:41 +02:00
|
|
|
tconf.suppress_offset_comment = suppress_offset_comment;
|
2007-04-28 21:13:35 +02:00
|
|
|
}
|
|
|
|
|
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);
|
2007-02-27 03:00:56 +01:00
|
|
|
if (ptype == NULL)
|
|
|
|
goto out_type_not_found;
|
2007-07-02 01:46:59 +02:00
|
|
|
if (ptype->tag == DW_TAG_subroutine_type) {
|
|
|
|
printed += ftype__fprintf(tag__ftype(ptype),
|
|
|
|
cu, name, 0, 1,
|
|
|
|
conf->type_spacing,
|
|
|
|
fp);
|
|
|
|
break;
|
|
|
|
}
|
[CLASSES]: Ditch class_member__names
Was a awful function, to replace it added some new __snprintf methods for more
classes (array_type, class_member, etc), the end result is a much nicer
rendering, for instance:
@@ -6549,11 +6549,11 @@
/* XXX 2 bytes hole, try to pack */
union {
- struct ff_constant_effect constant; /* 10 */
- struct ff_ramp_effect ramp; /* 12 */
- struct ff_periodic_effect periodic; /* 28 */
- struct ff_condition_effect condition[2]; /* 24 */
- struct ff_rumble_effect rumble; /* 4 */
+ struct ff_constant_effect constant; /* 10 */
+ struct ff_ramp_effect ramp; /* 12 */
+ struct ff_periodic_effect periodic; /* 28 */
+ struct ff_condition_effect condition[2]; /* 24 */
+ struct ff_rumble_effect rumble; /* 4 */
} u; /* 16 28 */
/* --- cacheline 1 boundary (32 bytes) was 12 bytes ago --- */
}; /* size: 44, cachelines: 2 */
Previously when such big class members appeared the comments with the size and
offset were unaligned, now its only in extreme cases, such as the array above
that things get unaligned.
End result is a smaller library:
[acme@newtoy pahole]$ codiff -V build/libclasses.so.orig build/libclasses.so
/home/acme/pahole/classes.c:
struct array_type | -4
nr_members: -1
-const char *name /* 36 4 */
1 struct changed
enumeration__print | +10 # 175 -> 185
union__snprintf | +32 # 576 -> 608
union__print | +16 # 182 -> 198
class_member__names | -851 (removed)
class_member__print | -721 # 1218 -> 497
class__print_struct | +54 # 1403 -> 1457
6 functions changed, 112 bytes added, 1572 bytes removed, diff: -1460
/home/acme/pahole/classes.c:
array_type__snprintf | +249 (added)
class_member__snprintf | +892 (added)
2 functions changed, 1141 bytes added
build/libclasses.so:
8 functions changed, 1253 bytes added, 1572 bytes removed, diff: -319
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 17:19:55 +01:00
|
|
|
}
|
2007-07-02 01:46:59 +02:00
|
|
|
/* Fall Thru */
|
|
|
|
default:
|
|
|
|
printed += fprintf(fp, "%-*s %s", conf->type_spacing,
|
|
|
|
tag__name(type, cu, tbf, sizeof(tbf)), name);
|
2007-01-13 19:12:41 +01:00
|
|
|
break;
|
|
|
|
case DW_TAG_subroutine_type:
|
2007-07-02 01:46:59 +02:00
|
|
|
printed += ftype__fprintf(tag__ftype(type), cu, name, 0, 0,
|
|
|
|
conf->type_spacing, fp);
|
|
|
|
break;
|
2007-01-13 19:12:41 +01:00
|
|
|
case DW_TAG_array_type:
|
2007-07-02 01:46:59 +02:00
|
|
|
printed += array_type__fprintf(type, cu, name, conf, fp);
|
|
|
|
break;
|
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
|
|
|
|
2007-07-05 01:36:28 +02:00
|
|
|
if (type__name(ctype, cu) != NULL && !expand_types)
|
2007-07-02 01:46:59 +02:00
|
|
|
printed += fprintf(fp, "struct %-*s %s",
|
|
|
|
conf->type_spacing - 7,
|
|
|
|
type__name(ctype, cu), name);
|
|
|
|
else
|
|
|
|
printed += class__fprintf(tag__class(type), cu,
|
|
|
|
&tconf, fp);
|
|
|
|
break;
|
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
|
|
|
|
2007-07-05 01:36:28 +02:00
|
|
|
if (type__name(ctype, cu) != NULL && !expand_types)
|
2007-07-02 01:46:59 +02:00
|
|
|
printed += fprintf(fp, "union %-*s %s",
|
|
|
|
conf->type_spacing - 6,
|
|
|
|
type__name(ctype, cu), name);
|
|
|
|
else
|
|
|
|
printed += union__fprintf(ctype, cu, &tconf, fp);
|
|
|
|
break;
|
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
|
|
|
|
2007-05-24 23:45:34 +02:00
|
|
|
if (type__name(ctype, cu) != NULL)
|
2007-07-02 01:46:59 +02:00
|
|
|
printed += fprintf(fp, "enum %-*s %s",
|
|
|
|
conf->type_spacing - 5,
|
|
|
|
type__name(ctype, cu), name);
|
|
|
|
else
|
|
|
|
printed += enumeration__fprintf(type, cu, &tconf, fp);
|
|
|
|
break;
|
[CLASSES]: Ditch class_member__names
Was a awful function, to replace it added some new __snprintf methods for more
classes (array_type, class_member, etc), the end result is a much nicer
rendering, for instance:
@@ -6549,11 +6549,11 @@
/* XXX 2 bytes hole, try to pack */
union {
- struct ff_constant_effect constant; /* 10 */
- struct ff_ramp_effect ramp; /* 12 */
- struct ff_periodic_effect periodic; /* 28 */
- struct ff_condition_effect condition[2]; /* 24 */
- struct ff_rumble_effect rumble; /* 4 */
+ struct ff_constant_effect constant; /* 10 */
+ struct ff_ramp_effect ramp; /* 12 */
+ struct ff_periodic_effect periodic; /* 28 */
+ struct ff_condition_effect condition[2]; /* 24 */
+ struct ff_rumble_effect rumble; /* 4 */
} u; /* 16 28 */
/* --- cacheline 1 boundary (32 bytes) was 12 bytes ago --- */
}; /* size: 44, cachelines: 2 */
Previously when such big class members appeared the comments with the size and
offset were unaligned, now its only in extreme cases, such as the array above
that things get unaligned.
End result is a smaller library:
[acme@newtoy pahole]$ codiff -V build/libclasses.so.orig build/libclasses.so
/home/acme/pahole/classes.c:
struct array_type | -4
nr_members: -1
-const char *name /* 36 4 */
1 struct changed
enumeration__print | +10 # 175 -> 185
union__snprintf | +32 # 576 -> 608
union__print | +16 # 182 -> 198
class_member__names | -851 (removed)
class_member__print | -721 # 1218 -> 497
class__print_struct | +54 # 1403 -> 1457
6 functions changed, 112 bytes added, 1572 bytes removed, diff: -1460
/home/acme/pahole/classes.c:
array_type__snprintf | +249 (added)
class_member__snprintf | +892 (added)
2 functions changed, 1141 bytes added
build/libclasses.so:
8 functions changed, 1253 bytes added, 1572 bytes removed, diff: -319
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 17:19:55 +01:00
|
|
|
}
|
2007-07-02 01:46:59 +02:00
|
|
|
out:
|
2007-07-05 01:36:28 +02:00
|
|
|
if (conf->expand_types)
|
|
|
|
--type->recursivity_level;
|
|
|
|
|
2007-07-02 01:46:59 +02:00
|
|
|
return printed;
|
2007-02-27 03:00:56 +01:00
|
|
|
out_type_not_found:
|
2007-07-02 01:46:59 +02:00
|
|
|
printed = fprintf(fp, "%-*s %s", conf->type_spacing, "<ERROR>", name);
|
|
|
|
goto out;
|
[CLASSES]: Ditch class_member__names
Was a awful function, to replace it added some new __snprintf methods for more
classes (array_type, class_member, etc), the end result is a much nicer
rendering, for instance:
@@ -6549,11 +6549,11 @@
/* XXX 2 bytes hole, try to pack */
union {
- struct ff_constant_effect constant; /* 10 */
- struct ff_ramp_effect ramp; /* 12 */
- struct ff_periodic_effect periodic; /* 28 */
- struct ff_condition_effect condition[2]; /* 24 */
- struct ff_rumble_effect rumble; /* 4 */
+ struct ff_constant_effect constant; /* 10 */
+ struct ff_ramp_effect ramp; /* 12 */
+ struct ff_periodic_effect periodic; /* 28 */
+ struct ff_condition_effect condition[2]; /* 24 */
+ struct ff_rumble_effect rumble; /* 4 */
} u; /* 16 28 */
/* --- cacheline 1 boundary (32 bytes) was 12 bytes ago --- */
}; /* size: 44, cachelines: 2 */
Previously when such big class members appeared the comments with the size and
offset were unaligned, now its only in extreme cases, such as the array above
that things get unaligned.
End result is a smaller library:
[acme@newtoy pahole]$ codiff -V build/libclasses.so.orig build/libclasses.so
/home/acme/pahole/classes.c:
struct array_type | -4
nr_members: -1
-const char *name /* 36 4 */
1 struct changed
enumeration__print | +10 # 175 -> 185
union__snprintf | +32 # 576 -> 608
union__print | +16 # 182 -> 198
class_member__names | -851 (removed)
class_member__print | -721 # 1218 -> 497
class__print_struct | +54 # 1403 -> 1457
6 functions changed, 112 bytes added, 1572 bytes removed, diff: -1460
/home/acme/pahole/classes.c:
array_type__snprintf | +249 (added)
class_member__snprintf | +892 (added)
2 functions changed, 1141 bytes added
build/libclasses.so:
8 functions changed, 1253 bytes added, 1572 bytes removed, diff: -319
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 17:19:55 +01:00
|
|
|
}
|
|
|
|
|
2007-02-15 14:36:49 +01:00
|
|
|
static size_t struct_member__fprintf(struct class_member *self,
|
|
|
|
struct tag *type, const struct cu *cu,
|
2007-04-28 21:13:35 +02:00
|
|
|
const struct conf_fprintf *conf, FILE *fp)
|
[CLASSES]: Ditch class_member__names
Was a awful function, to replace it added some new __snprintf methods for more
classes (array_type, class_member, etc), the end result is a much nicer
rendering, for instance:
@@ -6549,11 +6549,11 @@
/* XXX 2 bytes hole, try to pack */
union {
- struct ff_constant_effect constant; /* 10 */
- struct ff_ramp_effect ramp; /* 12 */
- struct ff_periodic_effect periodic; /* 28 */
- struct ff_condition_effect condition[2]; /* 24 */
- struct ff_rumble_effect rumble; /* 4 */
+ struct ff_constant_effect constant; /* 10 */
+ struct ff_ramp_effect ramp; /* 12 */
+ struct ff_periodic_effect periodic; /* 28 */
+ struct ff_condition_effect condition[2]; /* 24 */
+ struct ff_rumble_effect rumble; /* 4 */
} u; /* 16 28 */
/* --- cacheline 1 boundary (32 bytes) was 12 bytes ago --- */
}; /* size: 44, cachelines: 2 */
Previously when such big class members appeared the comments with the size and
offset were unaligned, now its only in extreme cases, such as the array above
that things get unaligned.
End result is a smaller library:
[acme@newtoy pahole]$ codiff -V build/libclasses.so.orig build/libclasses.so
/home/acme/pahole/classes.c:
struct array_type | -4
nr_members: -1
-const char *name /* 36 4 */
1 struct changed
enumeration__print | +10 # 175 -> 185
union__snprintf | +32 # 576 -> 608
union__print | +16 # 182 -> 198
class_member__names | -851 (removed)
class_member__print | -721 # 1218 -> 497
class__print_struct | +54 # 1403 -> 1457
6 functions changed, 112 bytes added, 1572 bytes removed, diff: -1460
/home/acme/pahole/classes.c:
array_type__snprintf | +249 (added)
class_member__snprintf | +892 (added)
2 functions changed, 1141 bytes added
build/libclasses.so:
8 functions changed, 1253 bytes added, 1572 bytes removed, diff: -319
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 17:19:55 +01:00
|
|
|
{
|
2007-03-28 16:38:32 +02:00
|
|
|
const int size = tag__size(type, cu);
|
2007-04-28 21:13:35 +02:00
|
|
|
struct conf_fprintf sconf = *conf;
|
2007-05-02 21:14:20 +02:00
|
|
|
uint32_t offset = self->offset;
|
2007-05-26 02:45:30 +02:00
|
|
|
size_t printed = 0;
|
|
|
|
const char *name = self->name;
|
2007-05-02 21:14:20 +02:00
|
|
|
|
|
|
|
if (!sconf.rel_offset) {
|
|
|
|
sconf.base_offset += self->offset;
|
|
|
|
offset = sconf.base_offset;
|
|
|
|
}
|
2007-05-26 02:45:30 +02:00
|
|
|
|
|
|
|
if (self->tag.tag == DW_TAG_inheritance) {
|
|
|
|
name = "<ancestor>";
|
|
|
|
printed += fprintf(fp, "/* ");
|
|
|
|
}
|
|
|
|
|
|
|
|
printed += type__fprintf(type, cu, name, &sconf, fp);
|
2007-04-28 21:13:35 +02: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
|
|
|
if (self->bit_size != 0)
|
2007-02-15 15:28:02 +01:00
|
|
|
printed += fprintf(fp, ":%u;", self->bit_size);
|
2007-02-15 14:36:49 +01:00
|
|
|
else {
|
|
|
|
fputc(';', fp);
|
2007-02-15 15:28:02 +01:00
|
|
|
++printed;
|
2007-02-15 14:36:49 +01:00
|
|
|
}
|
2007-01-10 19:39:20 +01:00
|
|
|
|
2007-05-31 07:21:36 +02:00
|
|
|
if ((tag__is_union(type) || tag__is_struct(type) ||
|
|
|
|
tag__is_enumeration(type)) &&
|
[CLASSES]: Fully support nested classes
Example:
[acme@newtoy pahole]$ pahole net/ipv4/tcp.o flowi
/* include/net/flow.h:13 */
struct flowi {
int oif; /* 0 4 */
int iif; /* 4 4 */
__u32 mark; /* 8 4 */
union {
struct {
__be32 daddr; /* 0 4 */
__be32 saddr; /* 4 4 */
__u8 tos; /* 8 1 */
__u8 scope; /* 9 1 */
} ip4_u; /* 12 */
struct {
struct in6_addr daddr; /* 0 16 */
struct in6_addr saddr; /* 16 16 */
/* --- cacheline 1 boundary (32 bytes) --- */
__be32 flowlabel; /* 32 4 */
} ip6_u; /* 36 */
struct {
__le16 daddr; /* 0 2 */
__le16 saddr; /* 2 2 */
__u8 scope; /* 4 1 */
} dn_u; /* 6 */
} nl_u; /* 12 36 */
/* --- cacheline 1 boundary (32 bytes) was 16 bytes ago --- */
__u8 proto; /* 48 1 */
__u8 flags; /* 49 1 */
/* XXX 2 bytes hole, try to pack */
union {
struct {
__be16 sport; /* 0 2 */
__be16 dport; /* 2 2 */
} ports; /* 4 */
struct {
__u8 type; /* 0 1 */
__u8 code; /* 1 1 */
} icmpt; /* 2 */
struct {
__le16 sport; /* 0 2 */
__le16 dport; /* 2 2 */
} dnports; /* 4 */
__be32 spi; /* 4 */
} uli_u; /* 52 4 */
__u32 secid; /* 56 4 */
}; /* size: 60, cachelines: 2 */
/* sum members: 58, holes: 1, sum holes: 2 */
/* last cacheline: 28 bytes */
Supporting anonymous structs and unions just fine, even combinations of both,
like in struct page, in the Linux kernel:
[acme@newtoy pahole]$ pahole mm/mmap.o page
/* include/linux/mmzone.h:391 */
struct page {
long unsigned int flags; /* 0 4 */
atomic_t _count; /* 4 4 */
atomic_t _mapcount; /* 8 4 */
union {
struct {
long unsigned int private; /* 0 4 */
struct address_space * mapping; /* 4 4 */
}; /* 8 */
}; /* 12 8 */
long unsigned int index; /* 20 4 */
struct list_head lru; /* 24 8 */
/* --- cacheline 1 boundary (32 bytes) --- */
}; /* size: 32, cachelines: 1 */
Or struct freebsd_sys_getdents_args in the OpenBSD kernel:
/* /usr/home/leonardo/openbsd/src/sys/compat/freebsd/freebsd_syscallargs.h:231 */
struct freebsd_sys_getdents_args {
union {
register_t pad; /* 4 */
struct {
int datum; /* 0 4 */
} le; /* 4 */
struct {
int8_t pad[0]; /* 0 0 */
int datum; /* 0 4 */
} be; /* 4 */
} fd; /* 0 4 */
union {
register_t pad; /* 4 */
struct {
void * datum; /* 0 4 */
} le; /* 4 */
struct {
int8_t pad[0]; /* 0 0 */
void * datum; /* 0 4 */
} be; /* 4 */
} dirent; /* 4 4 */
union {
register_t pad; /* 4 */
struct {
unsigned int datum; /* 0 4 */
} le; /* 4 */
struct {
int8_t pad[0]; /* 0 0 */
unsigned int datum; /* 0 4 */
} be; /* 4 */
} count; /* 8 4 */
}; /* size: 12, cachelines: 1 */
/* last cacheline: 12 bytes */
/* definitions: 7 */
One more from the OpenBSD kernel:
/* /usr/home/leonardo/openbsd/src/sys/nfs/nfs.h:344 */
struct nfssvc_sock {
struct {
struct nfssvc_sock * tqe_next; /* 0 4 */
struct nfssvc_sock * * tqe_prev; /* 4 4 */
} ns_chain; /* 0 8 */
struct {
struct nfsuid * tqh_first; /* 0 4 */
struct nfsuid * * tqh_last; /* 4 4 */
} ns_uidlruhead; /* 8 8 */
struct file * ns_fp; /* 16 4 */
struct socket * ns_so; /* 20 4 */
struct mbuf * ns_nam; /* 24 4 */
struct mbuf * ns_raw; /* 28 4 */
/* --- cacheline 1 boundary (32 bytes) --- */
struct mbuf * ns_rawend; /* 32 4 */
struct mbuf * ns_rec; /* 36 4 */
struct mbuf * ns_recend; /* 40 4 */
struct mbuf * ns_frag; /* 44 4 */
int ns_flag; /* 48 4 */
int ns_solock; /* 52 4 */
int ns_cc; /* 56 4 */
int ns_reclen; /* 60 4 */
/* --- cacheline 2 boundary (64 bytes) --- */
int ns_numuids; /* 64 4 */
u_int32_t ns_sref; /* 68 4 */
struct {
struct nfsrv_descript * lh_first; /* 0 4 */
} ns_tq; /* 72 4 */
struct ns_uidhashtbl[29]; /* 76 116 */
/* --- cacheline 6 boundary (192 bytes) --- */
struct nfsrvw_delayhash ns_wdelayhashtbl[16]; /* 192 64 */
/* --- cacheline 8 boundary (256 bytes) --- */
}; /* size: 256, cachelines: 8 */
/* definitions: 12 */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 22:46:47 +01:00
|
|
|
/* Look if is a type defined inline */
|
2007-05-24 23:45:34 +02:00
|
|
|
type__name(tag__type(type), cu) == NULL) {
|
2007-07-07 19:41:41 +02:00
|
|
|
if (!sconf.suppress_offset_comment) {
|
|
|
|
/* Check if this is a anonymous union */
|
|
|
|
const int slen = self->name != NULL ?
|
|
|
|
(int)strlen(self->name) : -1;
|
|
|
|
printed += fprintf(fp, "%*s/* %5u %5u */",
|
|
|
|
(sconf.type_spacing +
|
|
|
|
sconf.name_spacing - slen - 3),
|
|
|
|
" ", offset, size);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
int spacing = sconf.type_spacing + sconf.name_spacing - printed;
|
|
|
|
|
|
|
|
if (self->tag.tag == DW_TAG_inheritance) {
|
|
|
|
const size_t p = fprintf(fp, " */");
|
|
|
|
printed += p;
|
|
|
|
spacing -= p;
|
|
|
|
}
|
|
|
|
if (!sconf.suppress_offset_comment)
|
|
|
|
printed += fprintf(fp, "%*s/* %5u %5u */",
|
|
|
|
spacing > 0 ? spacing : 0, " ",
|
|
|
|
offset, size);
|
2007-05-26 02:45:30 +02:00
|
|
|
}
|
2007-07-07 19:41:41 +02:00
|
|
|
return printed;
|
[CLASSES]: Fully support nested classes
Example:
[acme@newtoy pahole]$ pahole net/ipv4/tcp.o flowi
/* include/net/flow.h:13 */
struct flowi {
int oif; /* 0 4 */
int iif; /* 4 4 */
__u32 mark; /* 8 4 */
union {
struct {
__be32 daddr; /* 0 4 */
__be32 saddr; /* 4 4 */
__u8 tos; /* 8 1 */
__u8 scope; /* 9 1 */
} ip4_u; /* 12 */
struct {
struct in6_addr daddr; /* 0 16 */
struct in6_addr saddr; /* 16 16 */
/* --- cacheline 1 boundary (32 bytes) --- */
__be32 flowlabel; /* 32 4 */
} ip6_u; /* 36 */
struct {
__le16 daddr; /* 0 2 */
__le16 saddr; /* 2 2 */
__u8 scope; /* 4 1 */
} dn_u; /* 6 */
} nl_u; /* 12 36 */
/* --- cacheline 1 boundary (32 bytes) was 16 bytes ago --- */
__u8 proto; /* 48 1 */
__u8 flags; /* 49 1 */
/* XXX 2 bytes hole, try to pack */
union {
struct {
__be16 sport; /* 0 2 */
__be16 dport; /* 2 2 */
} ports; /* 4 */
struct {
__u8 type; /* 0 1 */
__u8 code; /* 1 1 */
} icmpt; /* 2 */
struct {
__le16 sport; /* 0 2 */
__le16 dport; /* 2 2 */
} dnports; /* 4 */
__be32 spi; /* 4 */
} uli_u; /* 52 4 */
__u32 secid; /* 56 4 */
}; /* size: 60, cachelines: 2 */
/* sum members: 58, holes: 1, sum holes: 2 */
/* last cacheline: 28 bytes */
Supporting anonymous structs and unions just fine, even combinations of both,
like in struct page, in the Linux kernel:
[acme@newtoy pahole]$ pahole mm/mmap.o page
/* include/linux/mmzone.h:391 */
struct page {
long unsigned int flags; /* 0 4 */
atomic_t _count; /* 4 4 */
atomic_t _mapcount; /* 8 4 */
union {
struct {
long unsigned int private; /* 0 4 */
struct address_space * mapping; /* 4 4 */
}; /* 8 */
}; /* 12 8 */
long unsigned int index; /* 20 4 */
struct list_head lru; /* 24 8 */
/* --- cacheline 1 boundary (32 bytes) --- */
}; /* size: 32, cachelines: 1 */
Or struct freebsd_sys_getdents_args in the OpenBSD kernel:
/* /usr/home/leonardo/openbsd/src/sys/compat/freebsd/freebsd_syscallargs.h:231 */
struct freebsd_sys_getdents_args {
union {
register_t pad; /* 4 */
struct {
int datum; /* 0 4 */
} le; /* 4 */
struct {
int8_t pad[0]; /* 0 0 */
int datum; /* 0 4 */
} be; /* 4 */
} fd; /* 0 4 */
union {
register_t pad; /* 4 */
struct {
void * datum; /* 0 4 */
} le; /* 4 */
struct {
int8_t pad[0]; /* 0 0 */
void * datum; /* 0 4 */
} be; /* 4 */
} dirent; /* 4 4 */
union {
register_t pad; /* 4 */
struct {
unsigned int datum; /* 0 4 */
} le; /* 4 */
struct {
int8_t pad[0]; /* 0 0 */
unsigned int datum; /* 0 4 */
} be; /* 4 */
} count; /* 8 4 */
}; /* size: 12, cachelines: 1 */
/* last cacheline: 12 bytes */
/* definitions: 7 */
One more from the OpenBSD kernel:
/* /usr/home/leonardo/openbsd/src/sys/nfs/nfs.h:344 */
struct nfssvc_sock {
struct {
struct nfssvc_sock * tqe_next; /* 0 4 */
struct nfssvc_sock * * tqe_prev; /* 4 4 */
} ns_chain; /* 0 8 */
struct {
struct nfsuid * tqh_first; /* 0 4 */
struct nfsuid * * tqh_last; /* 4 4 */
} ns_uidlruhead; /* 8 8 */
struct file * ns_fp; /* 16 4 */
struct socket * ns_so; /* 20 4 */
struct mbuf * ns_nam; /* 24 4 */
struct mbuf * ns_raw; /* 28 4 */
/* --- cacheline 1 boundary (32 bytes) --- */
struct mbuf * ns_rawend; /* 32 4 */
struct mbuf * ns_rec; /* 36 4 */
struct mbuf * ns_recend; /* 40 4 */
struct mbuf * ns_frag; /* 44 4 */
int ns_flag; /* 48 4 */
int ns_solock; /* 52 4 */
int ns_cc; /* 56 4 */
int ns_reclen; /* 60 4 */
/* --- cacheline 2 boundary (64 bytes) --- */
int ns_numuids; /* 64 4 */
u_int32_t ns_sref; /* 68 4 */
struct {
struct nfsrv_descript * lh_first; /* 0 4 */
} ns_tq; /* 72 4 */
struct ns_uidhashtbl[29]; /* 76 116 */
/* --- cacheline 6 boundary (192 bytes) --- */
struct nfsrvw_delayhash ns_wdelayhashtbl[16]; /* 192 64 */
/* --- cacheline 8 boundary (256 bytes) --- */
}; /* size: 256, cachelines: 8 */
/* definitions: 12 */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 22:46:47 +01:00
|
|
|
}
|
|
|
|
|
2007-02-15 14:36:49 +01:00
|
|
|
static size_t union_member__fprintf(struct class_member *self,
|
|
|
|
struct tag *type, const struct cu *cu,
|
2007-04-28 21:13:35 +02:00
|
|
|
const struct conf_fprintf *conf, FILE *fp)
|
[CLASSES]: Fully support nested classes
Example:
[acme@newtoy pahole]$ pahole net/ipv4/tcp.o flowi
/* include/net/flow.h:13 */
struct flowi {
int oif; /* 0 4 */
int iif; /* 4 4 */
__u32 mark; /* 8 4 */
union {
struct {
__be32 daddr; /* 0 4 */
__be32 saddr; /* 4 4 */
__u8 tos; /* 8 1 */
__u8 scope; /* 9 1 */
} ip4_u; /* 12 */
struct {
struct in6_addr daddr; /* 0 16 */
struct in6_addr saddr; /* 16 16 */
/* --- cacheline 1 boundary (32 bytes) --- */
__be32 flowlabel; /* 32 4 */
} ip6_u; /* 36 */
struct {
__le16 daddr; /* 0 2 */
__le16 saddr; /* 2 2 */
__u8 scope; /* 4 1 */
} dn_u; /* 6 */
} nl_u; /* 12 36 */
/* --- cacheline 1 boundary (32 bytes) was 16 bytes ago --- */
__u8 proto; /* 48 1 */
__u8 flags; /* 49 1 */
/* XXX 2 bytes hole, try to pack */
union {
struct {
__be16 sport; /* 0 2 */
__be16 dport; /* 2 2 */
} ports; /* 4 */
struct {
__u8 type; /* 0 1 */
__u8 code; /* 1 1 */
} icmpt; /* 2 */
struct {
__le16 sport; /* 0 2 */
__le16 dport; /* 2 2 */
} dnports; /* 4 */
__be32 spi; /* 4 */
} uli_u; /* 52 4 */
__u32 secid; /* 56 4 */
}; /* size: 60, cachelines: 2 */
/* sum members: 58, holes: 1, sum holes: 2 */
/* last cacheline: 28 bytes */
Supporting anonymous structs and unions just fine, even combinations of both,
like in struct page, in the Linux kernel:
[acme@newtoy pahole]$ pahole mm/mmap.o page
/* include/linux/mmzone.h:391 */
struct page {
long unsigned int flags; /* 0 4 */
atomic_t _count; /* 4 4 */
atomic_t _mapcount; /* 8 4 */
union {
struct {
long unsigned int private; /* 0 4 */
struct address_space * mapping; /* 4 4 */
}; /* 8 */
}; /* 12 8 */
long unsigned int index; /* 20 4 */
struct list_head lru; /* 24 8 */
/* --- cacheline 1 boundary (32 bytes) --- */
}; /* size: 32, cachelines: 1 */
Or struct freebsd_sys_getdents_args in the OpenBSD kernel:
/* /usr/home/leonardo/openbsd/src/sys/compat/freebsd/freebsd_syscallargs.h:231 */
struct freebsd_sys_getdents_args {
union {
register_t pad; /* 4 */
struct {
int datum; /* 0 4 */
} le; /* 4 */
struct {
int8_t pad[0]; /* 0 0 */
int datum; /* 0 4 */
} be; /* 4 */
} fd; /* 0 4 */
union {
register_t pad; /* 4 */
struct {
void * datum; /* 0 4 */
} le; /* 4 */
struct {
int8_t pad[0]; /* 0 0 */
void * datum; /* 0 4 */
} be; /* 4 */
} dirent; /* 4 4 */
union {
register_t pad; /* 4 */
struct {
unsigned int datum; /* 0 4 */
} le; /* 4 */
struct {
int8_t pad[0]; /* 0 0 */
unsigned int datum; /* 0 4 */
} be; /* 4 */
} count; /* 8 4 */
}; /* size: 12, cachelines: 1 */
/* last cacheline: 12 bytes */
/* definitions: 7 */
One more from the OpenBSD kernel:
/* /usr/home/leonardo/openbsd/src/sys/nfs/nfs.h:344 */
struct nfssvc_sock {
struct {
struct nfssvc_sock * tqe_next; /* 0 4 */
struct nfssvc_sock * * tqe_prev; /* 4 4 */
} ns_chain; /* 0 8 */
struct {
struct nfsuid * tqh_first; /* 0 4 */
struct nfsuid * * tqh_last; /* 4 4 */
} ns_uidlruhead; /* 8 8 */
struct file * ns_fp; /* 16 4 */
struct socket * ns_so; /* 20 4 */
struct mbuf * ns_nam; /* 24 4 */
struct mbuf * ns_raw; /* 28 4 */
/* --- cacheline 1 boundary (32 bytes) --- */
struct mbuf * ns_rawend; /* 32 4 */
struct mbuf * ns_rec; /* 36 4 */
struct mbuf * ns_recend; /* 40 4 */
struct mbuf * ns_frag; /* 44 4 */
int ns_flag; /* 48 4 */
int ns_solock; /* 52 4 */
int ns_cc; /* 56 4 */
int ns_reclen; /* 60 4 */
/* --- cacheline 2 boundary (64 bytes) --- */
int ns_numuids; /* 64 4 */
u_int32_t ns_sref; /* 68 4 */
struct {
struct nfsrv_descript * lh_first; /* 0 4 */
} ns_tq; /* 72 4 */
struct ns_uidhashtbl[29]; /* 76 116 */
/* --- cacheline 6 boundary (192 bytes) --- */
struct nfsrvw_delayhash ns_wdelayhashtbl[16]; /* 192 64 */
/* --- cacheline 8 boundary (256 bytes) --- */
}; /* size: 256, cachelines: 8 */
/* definitions: 12 */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 22:46:47 +01:00
|
|
|
{
|
|
|
|
const size_t size = tag__size(type, cu);
|
2007-04-28 21:13:35 +02:00
|
|
|
size_t printed = type__fprintf(type, cu, self->name, conf, fp);
|
[CLASSES]: Fully support nested classes
Example:
[acme@newtoy pahole]$ pahole net/ipv4/tcp.o flowi
/* include/net/flow.h:13 */
struct flowi {
int oif; /* 0 4 */
int iif; /* 4 4 */
__u32 mark; /* 8 4 */
union {
struct {
__be32 daddr; /* 0 4 */
__be32 saddr; /* 4 4 */
__u8 tos; /* 8 1 */
__u8 scope; /* 9 1 */
} ip4_u; /* 12 */
struct {
struct in6_addr daddr; /* 0 16 */
struct in6_addr saddr; /* 16 16 */
/* --- cacheline 1 boundary (32 bytes) --- */
__be32 flowlabel; /* 32 4 */
} ip6_u; /* 36 */
struct {
__le16 daddr; /* 0 2 */
__le16 saddr; /* 2 2 */
__u8 scope; /* 4 1 */
} dn_u; /* 6 */
} nl_u; /* 12 36 */
/* --- cacheline 1 boundary (32 bytes) was 16 bytes ago --- */
__u8 proto; /* 48 1 */
__u8 flags; /* 49 1 */
/* XXX 2 bytes hole, try to pack */
union {
struct {
__be16 sport; /* 0 2 */
__be16 dport; /* 2 2 */
} ports; /* 4 */
struct {
__u8 type; /* 0 1 */
__u8 code; /* 1 1 */
} icmpt; /* 2 */
struct {
__le16 sport; /* 0 2 */
__le16 dport; /* 2 2 */
} dnports; /* 4 */
__be32 spi; /* 4 */
} uli_u; /* 52 4 */
__u32 secid; /* 56 4 */
}; /* size: 60, cachelines: 2 */
/* sum members: 58, holes: 1, sum holes: 2 */
/* last cacheline: 28 bytes */
Supporting anonymous structs and unions just fine, even combinations of both,
like in struct page, in the Linux kernel:
[acme@newtoy pahole]$ pahole mm/mmap.o page
/* include/linux/mmzone.h:391 */
struct page {
long unsigned int flags; /* 0 4 */
atomic_t _count; /* 4 4 */
atomic_t _mapcount; /* 8 4 */
union {
struct {
long unsigned int private; /* 0 4 */
struct address_space * mapping; /* 4 4 */
}; /* 8 */
}; /* 12 8 */
long unsigned int index; /* 20 4 */
struct list_head lru; /* 24 8 */
/* --- cacheline 1 boundary (32 bytes) --- */
}; /* size: 32, cachelines: 1 */
Or struct freebsd_sys_getdents_args in the OpenBSD kernel:
/* /usr/home/leonardo/openbsd/src/sys/compat/freebsd/freebsd_syscallargs.h:231 */
struct freebsd_sys_getdents_args {
union {
register_t pad; /* 4 */
struct {
int datum; /* 0 4 */
} le; /* 4 */
struct {
int8_t pad[0]; /* 0 0 */
int datum; /* 0 4 */
} be; /* 4 */
} fd; /* 0 4 */
union {
register_t pad; /* 4 */
struct {
void * datum; /* 0 4 */
} le; /* 4 */
struct {
int8_t pad[0]; /* 0 0 */
void * datum; /* 0 4 */
} be; /* 4 */
} dirent; /* 4 4 */
union {
register_t pad; /* 4 */
struct {
unsigned int datum; /* 0 4 */
} le; /* 4 */
struct {
int8_t pad[0]; /* 0 0 */
unsigned int datum; /* 0 4 */
} be; /* 4 */
} count; /* 8 4 */
}; /* size: 12, cachelines: 1 */
/* last cacheline: 12 bytes */
/* definitions: 7 */
One more from the OpenBSD kernel:
/* /usr/home/leonardo/openbsd/src/sys/nfs/nfs.h:344 */
struct nfssvc_sock {
struct {
struct nfssvc_sock * tqe_next; /* 0 4 */
struct nfssvc_sock * * tqe_prev; /* 4 4 */
} ns_chain; /* 0 8 */
struct {
struct nfsuid * tqh_first; /* 0 4 */
struct nfsuid * * tqh_last; /* 4 4 */
} ns_uidlruhead; /* 8 8 */
struct file * ns_fp; /* 16 4 */
struct socket * ns_so; /* 20 4 */
struct mbuf * ns_nam; /* 24 4 */
struct mbuf * ns_raw; /* 28 4 */
/* --- cacheline 1 boundary (32 bytes) --- */
struct mbuf * ns_rawend; /* 32 4 */
struct mbuf * ns_rec; /* 36 4 */
struct mbuf * ns_recend; /* 40 4 */
struct mbuf * ns_frag; /* 44 4 */
int ns_flag; /* 48 4 */
int ns_solock; /* 52 4 */
int ns_cc; /* 56 4 */
int ns_reclen; /* 60 4 */
/* --- cacheline 2 boundary (64 bytes) --- */
int ns_numuids; /* 64 4 */
u_int32_t ns_sref; /* 68 4 */
struct {
struct nfsrv_descript * lh_first; /* 0 4 */
} ns_tq; /* 72 4 */
struct ns_uidhashtbl[29]; /* 76 116 */
/* --- cacheline 6 boundary (192 bytes) --- */
struct nfsrvw_delayhash ns_wdelayhashtbl[16]; /* 192 64 */
/* --- cacheline 8 boundary (256 bytes) --- */
}; /* size: 256, cachelines: 8 */
/* definitions: 12 */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 22:46:47 +01:00
|
|
|
|
2007-05-31 07:21:36 +02:00
|
|
|
if ((tag__is_union(type) || tag__is_struct(type) ||
|
|
|
|
tag__is_enumeration(type)) &&
|
[CLASSES]: Fully support nested classes
Example:
[acme@newtoy pahole]$ pahole net/ipv4/tcp.o flowi
/* include/net/flow.h:13 */
struct flowi {
int oif; /* 0 4 */
int iif; /* 4 4 */
__u32 mark; /* 8 4 */
union {
struct {
__be32 daddr; /* 0 4 */
__be32 saddr; /* 4 4 */
__u8 tos; /* 8 1 */
__u8 scope; /* 9 1 */
} ip4_u; /* 12 */
struct {
struct in6_addr daddr; /* 0 16 */
struct in6_addr saddr; /* 16 16 */
/* --- cacheline 1 boundary (32 bytes) --- */
__be32 flowlabel; /* 32 4 */
} ip6_u; /* 36 */
struct {
__le16 daddr; /* 0 2 */
__le16 saddr; /* 2 2 */
__u8 scope; /* 4 1 */
} dn_u; /* 6 */
} nl_u; /* 12 36 */
/* --- cacheline 1 boundary (32 bytes) was 16 bytes ago --- */
__u8 proto; /* 48 1 */
__u8 flags; /* 49 1 */
/* XXX 2 bytes hole, try to pack */
union {
struct {
__be16 sport; /* 0 2 */
__be16 dport; /* 2 2 */
} ports; /* 4 */
struct {
__u8 type; /* 0 1 */
__u8 code; /* 1 1 */
} icmpt; /* 2 */
struct {
__le16 sport; /* 0 2 */
__le16 dport; /* 2 2 */
} dnports; /* 4 */
__be32 spi; /* 4 */
} uli_u; /* 52 4 */
__u32 secid; /* 56 4 */
}; /* size: 60, cachelines: 2 */
/* sum members: 58, holes: 1, sum holes: 2 */
/* last cacheline: 28 bytes */
Supporting anonymous structs and unions just fine, even combinations of both,
like in struct page, in the Linux kernel:
[acme@newtoy pahole]$ pahole mm/mmap.o page
/* include/linux/mmzone.h:391 */
struct page {
long unsigned int flags; /* 0 4 */
atomic_t _count; /* 4 4 */
atomic_t _mapcount; /* 8 4 */
union {
struct {
long unsigned int private; /* 0 4 */
struct address_space * mapping; /* 4 4 */
}; /* 8 */
}; /* 12 8 */
long unsigned int index; /* 20 4 */
struct list_head lru; /* 24 8 */
/* --- cacheline 1 boundary (32 bytes) --- */
}; /* size: 32, cachelines: 1 */
Or struct freebsd_sys_getdents_args in the OpenBSD kernel:
/* /usr/home/leonardo/openbsd/src/sys/compat/freebsd/freebsd_syscallargs.h:231 */
struct freebsd_sys_getdents_args {
union {
register_t pad; /* 4 */
struct {
int datum; /* 0 4 */
} le; /* 4 */
struct {
int8_t pad[0]; /* 0 0 */
int datum; /* 0 4 */
} be; /* 4 */
} fd; /* 0 4 */
union {
register_t pad; /* 4 */
struct {
void * datum; /* 0 4 */
} le; /* 4 */
struct {
int8_t pad[0]; /* 0 0 */
void * datum; /* 0 4 */
} be; /* 4 */
} dirent; /* 4 4 */
union {
register_t pad; /* 4 */
struct {
unsigned int datum; /* 0 4 */
} le; /* 4 */
struct {
int8_t pad[0]; /* 0 0 */
unsigned int datum; /* 0 4 */
} be; /* 4 */
} count; /* 8 4 */
}; /* size: 12, cachelines: 1 */
/* last cacheline: 12 bytes */
/* definitions: 7 */
One more from the OpenBSD kernel:
/* /usr/home/leonardo/openbsd/src/sys/nfs/nfs.h:344 */
struct nfssvc_sock {
struct {
struct nfssvc_sock * tqe_next; /* 0 4 */
struct nfssvc_sock * * tqe_prev; /* 4 4 */
} ns_chain; /* 0 8 */
struct {
struct nfsuid * tqh_first; /* 0 4 */
struct nfsuid * * tqh_last; /* 4 4 */
} ns_uidlruhead; /* 8 8 */
struct file * ns_fp; /* 16 4 */
struct socket * ns_so; /* 20 4 */
struct mbuf * ns_nam; /* 24 4 */
struct mbuf * ns_raw; /* 28 4 */
/* --- cacheline 1 boundary (32 bytes) --- */
struct mbuf * ns_rawend; /* 32 4 */
struct mbuf * ns_rec; /* 36 4 */
struct mbuf * ns_recend; /* 40 4 */
struct mbuf * ns_frag; /* 44 4 */
int ns_flag; /* 48 4 */
int ns_solock; /* 52 4 */
int ns_cc; /* 56 4 */
int ns_reclen; /* 60 4 */
/* --- cacheline 2 boundary (64 bytes) --- */
int ns_numuids; /* 64 4 */
u_int32_t ns_sref; /* 68 4 */
struct {
struct nfsrv_descript * lh_first; /* 0 4 */
} ns_tq; /* 72 4 */
struct ns_uidhashtbl[29]; /* 76 116 */
/* --- cacheline 6 boundary (192 bytes) --- */
struct nfsrvw_delayhash ns_wdelayhashtbl[16]; /* 192 64 */
/* --- cacheline 8 boundary (256 bytes) --- */
}; /* size: 256, cachelines: 8 */
/* definitions: 12 */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 22:46:47 +01:00
|
|
|
/* Look if is a type defined inline */
|
2007-05-24 23:45:34 +02:00
|
|
|
type__name(tag__type(type), cu) == NULL) {
|
2007-07-07 19:41:41 +02:00
|
|
|
if (!conf->suppress_offset_comment) {
|
|
|
|
/* Check if this is a anonymous union */
|
|
|
|
const int slen = self->name != NULL ? (int)strlen(self->name) : -1;
|
|
|
|
/*
|
|
|
|
* Add the comment with the union size after padding the
|
|
|
|
* '} member_name;' last line of the type printed in the
|
|
|
|
* above call to type__fprintf.
|
|
|
|
*/
|
2007-11-11 20:30:43 +01:00
|
|
|
printed += fprintf(fp, ";%*s/* %11zd */",
|
2007-07-07 19:41:41 +02:00
|
|
|
(conf->type_spacing +
|
|
|
|
conf->name_spacing - slen - 3), " ", size);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
printed += fprintf(fp, ";");
|
|
|
|
|
|
|
|
if (!conf->suppress_offset_comment) {
|
|
|
|
const int spacing = conf->type_spacing + conf->name_spacing - printed;
|
|
|
|
printed += fprintf(fp, "%*s/* %11zd */",
|
|
|
|
spacing > 0 ? spacing : 0, " ", size);
|
|
|
|
}
|
[CLASSES]: Fully support nested classes
Example:
[acme@newtoy pahole]$ pahole net/ipv4/tcp.o flowi
/* include/net/flow.h:13 */
struct flowi {
int oif; /* 0 4 */
int iif; /* 4 4 */
__u32 mark; /* 8 4 */
union {
struct {
__be32 daddr; /* 0 4 */
__be32 saddr; /* 4 4 */
__u8 tos; /* 8 1 */
__u8 scope; /* 9 1 */
} ip4_u; /* 12 */
struct {
struct in6_addr daddr; /* 0 16 */
struct in6_addr saddr; /* 16 16 */
/* --- cacheline 1 boundary (32 bytes) --- */
__be32 flowlabel; /* 32 4 */
} ip6_u; /* 36 */
struct {
__le16 daddr; /* 0 2 */
__le16 saddr; /* 2 2 */
__u8 scope; /* 4 1 */
} dn_u; /* 6 */
} nl_u; /* 12 36 */
/* --- cacheline 1 boundary (32 bytes) was 16 bytes ago --- */
__u8 proto; /* 48 1 */
__u8 flags; /* 49 1 */
/* XXX 2 bytes hole, try to pack */
union {
struct {
__be16 sport; /* 0 2 */
__be16 dport; /* 2 2 */
} ports; /* 4 */
struct {
__u8 type; /* 0 1 */
__u8 code; /* 1 1 */
} icmpt; /* 2 */
struct {
__le16 sport; /* 0 2 */
__le16 dport; /* 2 2 */
} dnports; /* 4 */
__be32 spi; /* 4 */
} uli_u; /* 52 4 */
__u32 secid; /* 56 4 */
}; /* size: 60, cachelines: 2 */
/* sum members: 58, holes: 1, sum holes: 2 */
/* last cacheline: 28 bytes */
Supporting anonymous structs and unions just fine, even combinations of both,
like in struct page, in the Linux kernel:
[acme@newtoy pahole]$ pahole mm/mmap.o page
/* include/linux/mmzone.h:391 */
struct page {
long unsigned int flags; /* 0 4 */
atomic_t _count; /* 4 4 */
atomic_t _mapcount; /* 8 4 */
union {
struct {
long unsigned int private; /* 0 4 */
struct address_space * mapping; /* 4 4 */
}; /* 8 */
}; /* 12 8 */
long unsigned int index; /* 20 4 */
struct list_head lru; /* 24 8 */
/* --- cacheline 1 boundary (32 bytes) --- */
}; /* size: 32, cachelines: 1 */
Or struct freebsd_sys_getdents_args in the OpenBSD kernel:
/* /usr/home/leonardo/openbsd/src/sys/compat/freebsd/freebsd_syscallargs.h:231 */
struct freebsd_sys_getdents_args {
union {
register_t pad; /* 4 */
struct {
int datum; /* 0 4 */
} le; /* 4 */
struct {
int8_t pad[0]; /* 0 0 */
int datum; /* 0 4 */
} be; /* 4 */
} fd; /* 0 4 */
union {
register_t pad; /* 4 */
struct {
void * datum; /* 0 4 */
} le; /* 4 */
struct {
int8_t pad[0]; /* 0 0 */
void * datum; /* 0 4 */
} be; /* 4 */
} dirent; /* 4 4 */
union {
register_t pad; /* 4 */
struct {
unsigned int datum; /* 0 4 */
} le; /* 4 */
struct {
int8_t pad[0]; /* 0 0 */
unsigned int datum; /* 0 4 */
} be; /* 4 */
} count; /* 8 4 */
}; /* size: 12, cachelines: 1 */
/* last cacheline: 12 bytes */
/* definitions: 7 */
One more from the OpenBSD kernel:
/* /usr/home/leonardo/openbsd/src/sys/nfs/nfs.h:344 */
struct nfssvc_sock {
struct {
struct nfssvc_sock * tqe_next; /* 0 4 */
struct nfssvc_sock * * tqe_prev; /* 4 4 */
} ns_chain; /* 0 8 */
struct {
struct nfsuid * tqh_first; /* 0 4 */
struct nfsuid * * tqh_last; /* 4 4 */
} ns_uidlruhead; /* 8 8 */
struct file * ns_fp; /* 16 4 */
struct socket * ns_so; /* 20 4 */
struct mbuf * ns_nam; /* 24 4 */
struct mbuf * ns_raw; /* 28 4 */
/* --- cacheline 1 boundary (32 bytes) --- */
struct mbuf * ns_rawend; /* 32 4 */
struct mbuf * ns_rec; /* 36 4 */
struct mbuf * ns_recend; /* 40 4 */
struct mbuf * ns_frag; /* 44 4 */
int ns_flag; /* 48 4 */
int ns_solock; /* 52 4 */
int ns_cc; /* 56 4 */
int ns_reclen; /* 60 4 */
/* --- cacheline 2 boundary (64 bytes) --- */
int ns_numuids; /* 64 4 */
u_int32_t ns_sref; /* 68 4 */
struct {
struct nfsrv_descript * lh_first; /* 0 4 */
} ns_tq; /* 72 4 */
struct ns_uidhashtbl[29]; /* 76 116 */
/* --- cacheline 6 boundary (192 bytes) --- */
struct nfsrvw_delayhash ns_wdelayhashtbl[16]; /* 192 64 */
/* --- cacheline 8 boundary (256 bytes) --- */
}; /* size: 256, cachelines: 8 */
/* definitions: 12 */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 22:46:47 +01:00
|
|
|
}
|
2007-07-07 19:41:41 +02:00
|
|
|
|
|
|
|
return printed;
|
[CLASSES]: Ditch class_member__names
Was a awful function, to replace it added some new __snprintf methods for more
classes (array_type, class_member, etc), the end result is a much nicer
rendering, for instance:
@@ -6549,11 +6549,11 @@
/* XXX 2 bytes hole, try to pack */
union {
- struct ff_constant_effect constant; /* 10 */
- struct ff_ramp_effect ramp; /* 12 */
- struct ff_periodic_effect periodic; /* 28 */
- struct ff_condition_effect condition[2]; /* 24 */
- struct ff_rumble_effect rumble; /* 4 */
+ struct ff_constant_effect constant; /* 10 */
+ struct ff_ramp_effect ramp; /* 12 */
+ struct ff_periodic_effect periodic; /* 28 */
+ struct ff_condition_effect condition[2]; /* 24 */
+ struct ff_rumble_effect rumble; /* 4 */
} u; /* 16 28 */
/* --- cacheline 1 boundary (32 bytes) was 12 bytes ago --- */
}; /* size: 44, cachelines: 2 */
Previously when such big class members appeared the comments with the size and
offset were unaligned, now its only in extreme cases, such as the array above
that things get unaligned.
End result is a smaller library:
[acme@newtoy pahole]$ codiff -V build/libclasses.so.orig build/libclasses.so
/home/acme/pahole/classes.c:
struct array_type | -4
nr_members: -1
-const char *name /* 36 4 */
1 struct changed
enumeration__print | +10 # 175 -> 185
union__snprintf | +32 # 576 -> 608
union__print | +16 # 182 -> 198
class_member__names | -851 (removed)
class_member__print | -721 # 1218 -> 497
class__print_struct | +54 # 1403 -> 1457
6 functions changed, 112 bytes added, 1572 bytes removed, diff: -1460
/home/acme/pahole/classes.c:
array_type__snprintf | +249 (added)
class_member__snprintf | +892 (added)
2 functions changed, 1141 bytes added
build/libclasses.so:
8 functions changed, 1253 bytes added, 1572 bytes removed, diff: -319
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 17:19:55 +01:00
|
|
|
}
|
|
|
|
|
2007-05-24 23:45:34 +02:00
|
|
|
static size_t union__fprintf(struct type *self, const struct cu *cu,
|
2007-04-28 21:13:35 +02:00
|
|
|
const struct conf_fprintf *conf, FILE *fp)
|
[CLASSES]: Ditch class_member__names
Was a awful function, to replace it added some new __snprintf methods for more
classes (array_type, class_member, etc), the end result is a much nicer
rendering, for instance:
@@ -6549,11 +6549,11 @@
/* XXX 2 bytes hole, try to pack */
union {
- struct ff_constant_effect constant; /* 10 */
- struct ff_ramp_effect ramp; /* 12 */
- struct ff_periodic_effect periodic; /* 28 */
- struct ff_condition_effect condition[2]; /* 24 */
- struct ff_rumble_effect rumble; /* 4 */
+ struct ff_constant_effect constant; /* 10 */
+ struct ff_ramp_effect ramp; /* 12 */
+ struct ff_periodic_effect periodic; /* 28 */
+ struct ff_condition_effect condition[2]; /* 24 */
+ struct ff_rumble_effect rumble; /* 4 */
} u; /* 16 28 */
/* --- cacheline 1 boundary (32 bytes) was 12 bytes ago --- */
}; /* size: 44, cachelines: 2 */
Previously when such big class members appeared the comments with the size and
offset were unaligned, now its only in extreme cases, such as the array above
that things get unaligned.
End result is a smaller library:
[acme@newtoy pahole]$ codiff -V build/libclasses.so.orig build/libclasses.so
/home/acme/pahole/classes.c:
struct array_type | -4
nr_members: -1
-const char *name /* 36 4 */
1 struct changed
enumeration__print | +10 # 175 -> 185
union__snprintf | +32 # 576 -> 608
union__print | +16 # 182 -> 198
class_member__names | -851 (removed)
class_member__print | -721 # 1218 -> 497
class__print_struct | +54 # 1403 -> 1457
6 functions changed, 112 bytes added, 1572 bytes removed, diff: -1460
/home/acme/pahole/classes.c:
array_type__snprintf | +249 (added)
class_member__snprintf | +892 (added)
2 functions changed, 1141 bytes added
build/libclasses.so:
8 functions changed, 1253 bytes added, 1572 bytes removed, diff: -319
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 17:19:55 +01:00
|
|
|
{
|
|
|
|
struct class_member *pos;
|
2007-02-15 15:28:02 +01:00
|
|
|
size_t printed = 0;
|
2007-04-28 21:13:35 +02:00
|
|
|
size_t indent = conf->indent;
|
|
|
|
struct conf_fprintf uconf;
|
[CLASSES]: Ditch class_member__names
Was a awful function, to replace it added some new __snprintf methods for more
classes (array_type, class_member, etc), the end result is a much nicer
rendering, for instance:
@@ -6549,11 +6549,11 @@
/* XXX 2 bytes hole, try to pack */
union {
- struct ff_constant_effect constant; /* 10 */
- struct ff_ramp_effect ramp; /* 12 */
- struct ff_periodic_effect periodic; /* 28 */
- struct ff_condition_effect condition[2]; /* 24 */
- struct ff_rumble_effect rumble; /* 4 */
+ struct ff_constant_effect constant; /* 10 */
+ struct ff_ramp_effect ramp; /* 12 */
+ struct ff_periodic_effect periodic; /* 28 */
+ struct ff_condition_effect condition[2]; /* 24 */
+ struct ff_rumble_effect rumble; /* 4 */
} u; /* 16 28 */
/* --- cacheline 1 boundary (32 bytes) was 12 bytes ago --- */
}; /* size: 44, cachelines: 2 */
Previously when such big class members appeared the comments with the size and
offset were unaligned, now its only in extreme cases, such as the array above
that things get unaligned.
End result is a smaller library:
[acme@newtoy pahole]$ codiff -V build/libclasses.so.orig build/libclasses.so
/home/acme/pahole/classes.c:
struct array_type | -4
nr_members: -1
-const char *name /* 36 4 */
1 struct changed
enumeration__print | +10 # 175 -> 185
union__snprintf | +32 # 576 -> 608
union__print | +16 # 182 -> 198
class_member__names | -851 (removed)
class_member__print | -721 # 1218 -> 497
class__print_struct | +54 # 1403 -> 1457
6 functions changed, 112 bytes added, 1572 bytes removed, diff: -1460
/home/acme/pahole/classes.c:
array_type__snprintf | +249 (added)
class_member__snprintf | +892 (added)
2 functions changed, 1141 bytes added
build/libclasses.so:
8 functions changed, 1253 bytes added, 1572 bytes removed, diff: -319
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 17:19:55 +01:00
|
|
|
|
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
|
|
|
|
2007-04-28 21:13:35 +02:00
|
|
|
if (conf->prefix != NULL)
|
|
|
|
printed += fprintf(fp, "%s ", conf->prefix);
|
2007-05-24 23:45:34 +02:00
|
|
|
printed += fprintf(fp, "union%s%s {\n", type__name(self, cu) ? " " : "",
|
|
|
|
type__name(self, cu) ?: "");
|
2007-04-28 21:13:35 +02:00
|
|
|
|
|
|
|
uconf = *conf;
|
|
|
|
uconf.indent = indent + 1;
|
2007-05-24 02:43:01 +02:00
|
|
|
type__for_each_member(self, pos) {
|
[CLASSES]: Ditch class_member__names
Was a awful function, to replace it added some new __snprintf methods for more
classes (array_type, class_member, etc), the end result is a much nicer
rendering, for instance:
@@ -6549,11 +6549,11 @@
/* XXX 2 bytes hole, try to pack */
union {
- struct ff_constant_effect constant; /* 10 */
- struct ff_ramp_effect ramp; /* 12 */
- struct ff_periodic_effect periodic; /* 28 */
- struct ff_condition_effect condition[2]; /* 24 */
- struct ff_rumble_effect rumble; /* 4 */
+ struct ff_constant_effect constant; /* 10 */
+ struct ff_ramp_effect ramp; /* 12 */
+ struct ff_periodic_effect periodic; /* 28 */
+ struct ff_condition_effect condition[2]; /* 24 */
+ struct ff_rumble_effect rumble; /* 4 */
} u; /* 16 28 */
/* --- cacheline 1 boundary (32 bytes) was 12 bytes ago --- */
}; /* size: 44, cachelines: 2 */
Previously when such big class members appeared the comments with the size and
offset were unaligned, now its only in extreme cases, such as the array above
that things get unaligned.
End result is a smaller library:
[acme@newtoy pahole]$ codiff -V build/libclasses.so.orig build/libclasses.so
/home/acme/pahole/classes.c:
struct array_type | -4
nr_members: -1
-const char *name /* 36 4 */
1 struct changed
enumeration__print | +10 # 175 -> 185
union__snprintf | +32 # 576 -> 608
union__print | +16 # 182 -> 198
class_member__names | -851 (removed)
class_member__print | -721 # 1218 -> 497
class__print_struct | +54 # 1403 -> 1457
6 functions changed, 112 bytes added, 1572 bytes removed, diff: -1460
/home/acme/pahole/classes.c:
array_type__snprintf | +249 (added)
class_member__snprintf | +892 (added)
2 functions changed, 1141 bytes added
build/libclasses.so:
8 functions changed, 1253 bytes added, 1572 bytes removed, diff: -319
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 17:19:55 +01:00
|
|
|
struct tag *type = cu__find_tag_by_id(cu, pos->tag.type);
|
|
|
|
|
2007-04-28 21:13:35 +02:00
|
|
|
printed += fprintf(fp, "%.*s", uconf.indent, tabs);
|
|
|
|
printed += union_member__fprintf(pos, type, cu, &uconf, fp);
|
2007-02-15 14:36:49 +01:00
|
|
|
fputc('\n', fp);
|
2007-02-15 15:28:02 +01:00
|
|
|
++printed;
|
[CLASSES]: Ditch class_member__names
Was a awful function, to replace it added some new __snprintf methods for more
classes (array_type, class_member, etc), the end result is a much nicer
rendering, for instance:
@@ -6549,11 +6549,11 @@
/* XXX 2 bytes hole, try to pack */
union {
- struct ff_constant_effect constant; /* 10 */
- struct ff_ramp_effect ramp; /* 12 */
- struct ff_periodic_effect periodic; /* 28 */
- struct ff_condition_effect condition[2]; /* 24 */
- struct ff_rumble_effect rumble; /* 4 */
+ struct ff_constant_effect constant; /* 10 */
+ struct ff_ramp_effect ramp; /* 12 */
+ struct ff_periodic_effect periodic; /* 28 */
+ struct ff_condition_effect condition[2]; /* 24 */
+ struct ff_rumble_effect rumble; /* 4 */
} u; /* 16 28 */
/* --- cacheline 1 boundary (32 bytes) was 12 bytes ago --- */
}; /* size: 44, cachelines: 2 */
Previously when such big class members appeared the comments with the size and
offset were unaligned, now its only in extreme cases, such as the array above
that things get unaligned.
End result is a smaller library:
[acme@newtoy pahole]$ codiff -V build/libclasses.so.orig build/libclasses.so
/home/acme/pahole/classes.c:
struct array_type | -4
nr_members: -1
-const char *name /* 36 4 */
1 struct changed
enumeration__print | +10 # 175 -> 185
union__snprintf | +32 # 576 -> 608
union__print | +16 # 182 -> 198
class_member__names | -851 (removed)
class_member__print | -721 # 1218 -> 497
class__print_struct | +54 # 1403 -> 1457
6 functions changed, 112 bytes added, 1572 bytes removed, diff: -1460
/home/acme/pahole/classes.c:
array_type__snprintf | +249 (added)
class_member__snprintf | +892 (added)
2 functions changed, 1141 bytes added
build/libclasses.so:
8 functions changed, 1253 bytes added, 1572 bytes removed, diff: -319
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 17:19:55 +01:00
|
|
|
}
|
|
|
|
|
2007-02-15 15:28:02 +01:00
|
|
|
return printed + fprintf(fp, "%.*s}%s%s", indent, tabs,
|
2007-04-28 21:13:35 +02:00
|
|
|
conf->suffix ? " " : "", conf->suffix ?: "");
|
2007-01-12 21:00:32 +01:00
|
|
|
}
|
|
|
|
|
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-07-09 01:57:23 +02:00
|
|
|
if (self != NULL) {
|
2007-01-07 15:30:58 +01:00
|
|
|
type__init(&self->type, die);
|
2007-07-09 01:57:23 +02:00
|
|
|
INIT_LIST_HEAD(&self->vtable);
|
|
|
|
}
|
2006-10-28 23:22:42 +02:00
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2007-02-01 17:09:48 +01:00
|
|
|
void class__delete(struct class *self)
|
2007-01-30 16:32:55 +01:00
|
|
|
{
|
2007-02-01 18:54:42 +01:00
|
|
|
struct class_member *pos, *next;
|
2007-01-30 16:32:55 +01:00
|
|
|
|
2007-05-24 03:38:29 +02:00
|
|
|
type__for_each_member_safe(&self->type, pos, next)
|
2007-01-30 16:32:55 +01:00
|
|
|
class_member__delete(pos);
|
|
|
|
|
|
|
|
free(self);
|
|
|
|
}
|
|
|
|
|
2007-07-09 01:57:23 +02:00
|
|
|
static void class__add_vtable_entry(struct class *self, struct function *vtable_entry)
|
|
|
|
{
|
|
|
|
++self->nr_vtable_entries;
|
|
|
|
list_add_tail(&vtable_entry->vtable_node, &self->vtable);
|
|
|
|
}
|
|
|
|
|
2007-05-24 17:16:59 +02:00
|
|
|
static void namespace__add_tag(struct namespace *self, struct tag *tag)
|
2007-05-24 03:38:29 +02:00
|
|
|
{
|
|
|
|
++self->nr_tags;
|
|
|
|
list_add_tail(&tag->node, &self->tags);
|
|
|
|
}
|
|
|
|
|
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;
|
2007-05-24 17:16:59 +02:00
|
|
|
namespace__add_tag(&self->namespace, &member->tag);
|
2006-10-28 23:22:42 +02:00
|
|
|
}
|
|
|
|
|
2007-05-24 03:10:50 +02:00
|
|
|
struct class_member *type__last_member(struct type *self)
|
|
|
|
{
|
2007-05-24 03:38:29 +02:00
|
|
|
struct class_member *pos;
|
|
|
|
|
2007-05-24 17:16:59 +02:00
|
|
|
list_for_each_entry_reverse(pos, &self->namespace.tags, tag.node)
|
2007-05-24 03:38:29 +02:00
|
|
|
if (pos->tag.tag == DW_TAG_member)
|
|
|
|
return pos;
|
|
|
|
return NULL;
|
2007-05-24 03:10:50 +02:00
|
|
|
}
|
|
|
|
|
2007-01-30 16:32:55 +01:00
|
|
|
static int type__clone_members(struct type *self, const struct type *from)
|
|
|
|
{
|
|
|
|
struct class_member *pos;
|
|
|
|
|
|
|
|
self->nr_members = 0;
|
2007-05-24 17:16:59 +02:00
|
|
|
INIT_LIST_HEAD(&self->namespace.tags);
|
2007-01-30 16:32:55 +01:00
|
|
|
|
2007-05-24 02:43:01 +02:00
|
|
|
type__for_each_member(from, pos) {
|
2007-01-30 16:32:55 +01:00
|
|
|
struct class_member *member_clone = class_member__clone(pos);
|
|
|
|
|
|
|
|
if (member_clone == NULL)
|
|
|
|
return -1;
|
|
|
|
type__add_member(self, member_clone);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-02-01 17:09:48 +01:00
|
|
|
struct class *class__clone(const struct class *from,
|
|
|
|
const char *new_class_name)
|
2007-01-30 16:32:55 +01:00
|
|
|
{
|
|
|
|
struct class *self = zalloc(sizeof(*self));
|
|
|
|
|
2007-02-01 17:09:48 +01:00
|
|
|
if (self != NULL) {
|
2007-01-30 16:32:55 +01:00
|
|
|
memcpy(self, from, sizeof(*self));
|
|
|
|
if (type__clone_members(&self->type, &from->type) != 0) {
|
|
|
|
class__delete(self);
|
|
|
|
self = NULL;
|
|
|
|
}
|
2007-02-01 17:09:48 +01:00
|
|
|
if (new_class_name != NULL)
|
2007-05-24 17:16:59 +02:00
|
|
|
self->type.namespace.name = strings__add(new_class_name);
|
2007-01-30 16:32:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
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;
|
2007-05-24 17:16:59 +02:00
|
|
|
namespace__add_tag(&self->namespace, &enumerator->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-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-29 13:42:03 +01:00
|
|
|
static void 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-07-09 00:47:26 +02:00
|
|
|
self->linkage_name = strings__add(attr_string(die, DW_AT_MIPS_linkage_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-25 19:24:09 +01:00
|
|
|
self->abstract_origin = attr_type(die, DW_AT_abstract_origin);
|
|
|
|
self->specification = attr_type(die, DW_AT_specification);
|
2007-05-25 21:42:49 +02:00
|
|
|
self->accessibility = attr_numeric(die, DW_AT_accessibility);
|
|
|
|
self->virtuality = attr_numeric(die, DW_AT_virtuality);
|
2007-07-09 01:57:23 +02:00
|
|
|
INIT_LIST_HEAD(&self->vtable_node);
|
2007-07-09 01:35:49 +02:00
|
|
|
self->vtable_entry = -1;
|
|
|
|
if (dwarf_hasattr(die, DW_AT_vtable_elem_location))
|
|
|
|
self->vtable_entry = attr_offset(die, DW_AT_vtable_elem_location);
|
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) {
|
2007-05-26 20:40:52 +02:00
|
|
|
tag__id_not_found(&self->proto.tag,
|
|
|
|
self->specification);
|
2007-01-13 14:37:41 +01:00
|
|
|
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
|
|
|
|
2007-06-12 20:01:23 +02:00
|
|
|
ftype__for_each_parameter(self, pos) {
|
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
|
|
|
}
|
|
|
|
|
2007-01-26 03:29:53 +01:00
|
|
|
static void lexblock__add_tag(struct lexblock *self, struct tag *tag)
|
|
|
|
{
|
|
|
|
list_add_tail(&tag->node, &self->tags);
|
|
|
|
}
|
|
|
|
|
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-26 03:29:53 +01:00
|
|
|
lexblock__add_tag(self, &exp->tag);
|
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-26 03:29:53 +01:00
|
|
|
lexblock__add_tag(self, &var->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
|
|
|
}
|
|
|
|
|
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-26 03:29:53 +01:00
|
|
|
lexblock__add_tag(self, &label->tag);
|
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-05-29 19:06:33 +02:00
|
|
|
type__for_each_data_member(&self->type, pos)
|
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-05-29 19:24:50 +02:00
|
|
|
type__for_each_member(ctype, pos) {
|
2007-05-25 00:11:53 +02:00
|
|
|
/* XXX for now just skip these */
|
|
|
|
if (pos->tag.tag == DW_TAG_inheritance &&
|
|
|
|
pos->virtuality == DW_VIRTUALITY_virtual)
|
|
|
|
continue;
|
|
|
|
|
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.
|
|
|
|
*/
|
2007-01-29 13:42:03 +01:00
|
|
|
if ((size_t)cc_last_size < last_size)
|
2006-12-14 19:49:06 +01:00
|
|
|
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;
|
2007-05-25 00:11:53 +02:00
|
|
|
} else
|
|
|
|
self->padding = ctype->size;
|
2006-10-28 23:22:42 +02:00
|
|
|
}
|
|
|
|
|
[LIB]: Introduce class__has_hole_ge()
That returns if the class has a hole greater or equal to the size specified.
Pahole now has a --hole_size_ge command line option to use it.
Example on a linux kernel built for x86_64 where we list the structs that have
holes bigger than 32 bytes, that provides an approximation of structs with
____cacheline_aligned_in_smp annotated members:
[acme@filo pahole]$ pahole --hole_size_ge 32 examples/vmlinux-x86_64
inet_hashinfo
rcu_ctrlblk
hh_cache
net_device
files_struct
module
zone
For instance, look at struct zone clever use of such construct:
_pad1_ is defined with ZONE_PADDING(_pad1_), that is:
/* <40e> /home/acme/git/net-2.6.22/include/linux/mmzone.h:179 */
struct zone {
long unsigned int pages_min; /* 0 8 */
long unsigned int pages_low; /* 8 8 */
long unsigned int pages_high; /* 16 8 */
long unsigned int lowmem_reserve[3]; /* 24 24 */
int node; /* 48 4 */
/* XXX 4 bytes hole, try to pack */
long unsigned int min_unmapped_pages; /* 56 8 */
/* --- cacheline 1 boundary (64 bytes) --- */
long unsigned int min_slab_pages; /* 64 8 */
struct per_cpu_pageset * pageset[255]; /* 72 2040 */
/* --- cacheline 33 boundary (2112 bytes) --- */
spinlock_t lock; /* 2112 4 */
/* XXX 4 bytes hole, try to pack */
struct free_area free_area[11]; /* 2120 264 */
/* XXX 48 bytes hole, try to pack */
/* --- cacheline 38 boundary (2432 bytes) --- */
struct zone_padding _pad1_; /* 2432 0 */
spinlock_t lru_lock; /* 2432 4 */
/* XXX 4 bytes hole, try to pack */
struct list_head active_list; /* 2440 16 */
struct list_head inactive_list; /* 2456 16 */
long unsigned int nr_scan_active; /* 2472 8 */
long unsigned int nr_scan_inactive; /* 2480 8 */
long unsigned int pages_scanned; /* 2488 8 */
/* --- cacheline 39 boundary (2496 bytes) --- */
int all_unreclaimable; /* 2496 4 */
atomic_t reclaim_in_progress; /* 2500 4 */
atomic_long_t vm_stat[20]; /* 2504 160 */
/* --- cacheline 41 boundary (2624 bytes) was 40 bytes ago --- */
int prev_priority; /* 2664 4 */
/* XXX 20 bytes hole, try to pack */
/* --- cacheline 42 boundary (2688 bytes) --- */
struct zone_padding _pad2_; /* 2688 0 */
wait_queue_head_t * wait_table; /* 2688 8 */
long unsigned int wait_table_hash_nr_entries; /* 2696 8 */
long unsigned int wait_table_bits; /* 2704 8 */
struct pglist_data * zone_pgdat; /* 2712 8 */
long unsigned int zone_start_pfn; /* 2720 8 */
long unsigned int spanned_pages; /* 2728 8 */
long unsigned int present_pages; /* 2736 8 */
const char * name; /* 2744 8 */
/* --- cacheline 43 boundary (2752 bytes) --- */
}; /* size: 2752, cachelines: 43 */
/* sum members: 2672, holes: 5, sum holes: 80 */
/* definitions: 933 */
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-05-11 18:32:53 +02:00
|
|
|
/** class__has_hole_ge - check if class has a hole greater or equal to @size
|
|
|
|
* @self - class instance
|
|
|
|
* @size - hole size to check
|
|
|
|
*/
|
|
|
|
int class__has_hole_ge(const struct class *self, const uint16_t size)
|
|
|
|
{
|
|
|
|
struct class_member *pos;
|
|
|
|
|
|
|
|
if (self->nr_holes == 0)
|
|
|
|
return 0;
|
|
|
|
|
2007-05-29 19:06:33 +02:00
|
|
|
type__for_each_data_member(&self->type, pos)
|
[LIB]: Introduce class__has_hole_ge()
That returns if the class has a hole greater or equal to the size specified.
Pahole now has a --hole_size_ge command line option to use it.
Example on a linux kernel built for x86_64 where we list the structs that have
holes bigger than 32 bytes, that provides an approximation of structs with
____cacheline_aligned_in_smp annotated members:
[acme@filo pahole]$ pahole --hole_size_ge 32 examples/vmlinux-x86_64
inet_hashinfo
rcu_ctrlblk
hh_cache
net_device
files_struct
module
zone
For instance, look at struct zone clever use of such construct:
_pad1_ is defined with ZONE_PADDING(_pad1_), that is:
/* <40e> /home/acme/git/net-2.6.22/include/linux/mmzone.h:179 */
struct zone {
long unsigned int pages_min; /* 0 8 */
long unsigned int pages_low; /* 8 8 */
long unsigned int pages_high; /* 16 8 */
long unsigned int lowmem_reserve[3]; /* 24 24 */
int node; /* 48 4 */
/* XXX 4 bytes hole, try to pack */
long unsigned int min_unmapped_pages; /* 56 8 */
/* --- cacheline 1 boundary (64 bytes) --- */
long unsigned int min_slab_pages; /* 64 8 */
struct per_cpu_pageset * pageset[255]; /* 72 2040 */
/* --- cacheline 33 boundary (2112 bytes) --- */
spinlock_t lock; /* 2112 4 */
/* XXX 4 bytes hole, try to pack */
struct free_area free_area[11]; /* 2120 264 */
/* XXX 48 bytes hole, try to pack */
/* --- cacheline 38 boundary (2432 bytes) --- */
struct zone_padding _pad1_; /* 2432 0 */
spinlock_t lru_lock; /* 2432 4 */
/* XXX 4 bytes hole, try to pack */
struct list_head active_list; /* 2440 16 */
struct list_head inactive_list; /* 2456 16 */
long unsigned int nr_scan_active; /* 2472 8 */
long unsigned int nr_scan_inactive; /* 2480 8 */
long unsigned int pages_scanned; /* 2488 8 */
/* --- cacheline 39 boundary (2496 bytes) --- */
int all_unreclaimable; /* 2496 4 */
atomic_t reclaim_in_progress; /* 2500 4 */
atomic_long_t vm_stat[20]; /* 2504 160 */
/* --- cacheline 41 boundary (2624 bytes) was 40 bytes ago --- */
int prev_priority; /* 2664 4 */
/* XXX 20 bytes hole, try to pack */
/* --- cacheline 42 boundary (2688 bytes) --- */
struct zone_padding _pad2_; /* 2688 0 */
wait_queue_head_t * wait_table; /* 2688 8 */
long unsigned int wait_table_hash_nr_entries; /* 2696 8 */
long unsigned int wait_table_bits; /* 2704 8 */
struct pglist_data * zone_pgdat; /* 2712 8 */
long unsigned int zone_start_pfn; /* 2720 8 */
long unsigned int spanned_pages; /* 2728 8 */
long unsigned int present_pages; /* 2736 8 */
const char * name; /* 2744 8 */
/* --- cacheline 43 boundary (2752 bytes) --- */
}; /* size: 2752, cachelines: 43 */
/* sum members: 2672, holes: 5, sum holes: 80 */
/* definitions: 933 */
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-05-11 18:32:53 +02:00
|
|
|
if (pos->hole >= size)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
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;
|
2007-05-29 19:06:33 +02:00
|
|
|
type__for_each_data_member(self, pos)
|
2007-01-09 13:00:47 +01:00
|
|
|
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-05-10 20:28:00 +02:00
|
|
|
uint32_t type__nr_members_of_type(const struct type *self, const Dwarf_Off type)
|
|
|
|
{
|
|
|
|
struct class_member *pos;
|
|
|
|
uint32_t nr_members_of_type = 0;
|
|
|
|
|
2007-05-24 02:43:01 +02:00
|
|
|
type__for_each_member(self, pos)
|
2007-05-10 20:28:00 +02:00
|
|
|
if (pos->tag.type == type)
|
|
|
|
++nr_members_of_type;
|
|
|
|
|
|
|
|
return nr_members_of_type;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-04-30 21:26:29 +02:00
|
|
|
static size_t ftype__fprintf_parms(const struct ftype *self,
|
2007-04-30 21:37:18 +02:00
|
|
|
const struct cu *cu, size_t indent,
|
|
|
|
FILE *fp)
|
2007-04-30 21:26:29 +02:00
|
|
|
{
|
|
|
|
struct parameter *pos;
|
|
|
|
int first_parm = 1;
|
|
|
|
char sbf[128];
|
|
|
|
struct tag *type;
|
|
|
|
const char *name, *stype;
|
|
|
|
size_t printed = fprintf(fp, "(");
|
|
|
|
|
2007-06-12 20:01:23 +02:00
|
|
|
ftype__for_each_parameter(self, pos) {
|
2007-04-30 21:37:18 +02:00
|
|
|
if (!first_parm) {
|
|
|
|
if (indent == 0)
|
|
|
|
printed += fprintf(fp, ", ");
|
|
|
|
else
|
|
|
|
printed += fprintf(fp, ",\n%.*s",
|
|
|
|
indent, tabs);
|
|
|
|
} else
|
2007-04-30 21:26:29 +02:00
|
|
|
first_parm = 0;
|
|
|
|
name = parameter__name(pos, cu);
|
|
|
|
type = cu__find_tag_by_id(cu, parameter__type(pos, cu));
|
|
|
|
if (type == NULL) {
|
|
|
|
stype = "<ERROR>";
|
|
|
|
goto print_it;
|
|
|
|
}
|
|
|
|
if (type->tag == DW_TAG_pointer_type) {
|
|
|
|
if (type->type != 0) {
|
|
|
|
struct tag *ptype =
|
|
|
|
cu__find_tag_by_id(cu, type->type);
|
|
|
|
if (ptype == NULL) {
|
|
|
|
printed += fprintf(fp, ">>>ERROR: type "
|
|
|
|
"for %s not found!",
|
|
|
|
name);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (ptype->tag == DW_TAG_subroutine_type) {
|
|
|
|
printed +=
|
|
|
|
ftype__fprintf(tag__ftype(ptype),
|
|
|
|
cu, name, 0, 1, 0,
|
|
|
|
fp);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (type->tag == DW_TAG_subroutine_type) {
|
|
|
|
printed += ftype__fprintf(tag__ftype(type), cu, name,
|
|
|
|
0, 0, 0, fp);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
print_it:
|
|
|
|
stype = tag__name(type, cu, sbf, sizeof(sbf));
|
|
|
|
printed += fprintf(fp, "%s%s%s", stype, name ? " " : "",
|
|
|
|
name ?: "");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No parameters? */
|
|
|
|
if (first_parm)
|
|
|
|
printed += fprintf(fp, "void)");
|
|
|
|
else if (self->unspec_parms)
|
|
|
|
printed += fprintf(fp, ", ...)");
|
|
|
|
else
|
|
|
|
printed += fprintf(fp, ")");
|
|
|
|
return printed;
|
|
|
|
}
|
|
|
|
|
2007-02-15 14:56:16 +01:00
|
|
|
static size_t function__tag_fprintf(const struct tag *tag, const struct cu *cu,
|
2007-07-31 19:00:44 +02:00
|
|
|
struct function *function,
|
2007-02-15 14:56:16 +01:00
|
|
|
uint16_t indent, FILE *fp)
|
2006-11-20 18:43:39 +01:00
|
|
|
{
|
|
|
|
char bf[512];
|
2007-02-15 14:56:16 +01:00
|
|
|
size_t printed = 0, n;
|
2006-11-20 18:43:39 +01:00
|
|
|
const void *vtag = tag;
|
2007-03-28 16:38:32 +02:00
|
|
|
int c;
|
2007-01-03 01:26:01 +01:00
|
|
|
|
|
|
|
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);
|
2007-04-30 21:37:18 +02:00
|
|
|
const char *name;
|
2006-11-20 19:17:42 +01:00
|
|
|
|
2007-01-12 02:09:06 +01:00
|
|
|
if (alias == NULL) {
|
2007-01-29 13:42:03 +01:00
|
|
|
tag__type_not_found(&exp->tag);
|
2007-01-12 02:09:06 +01:00
|
|
|
break;
|
|
|
|
}
|
2007-02-15 14:56:16 +01:00
|
|
|
printed = fprintf(fp, "%.*s", indent, tabs);
|
2007-04-30 21:37:18 +02:00
|
|
|
name = function__name(alias, cu);
|
|
|
|
n = fprintf(fp, "%s", name);
|
|
|
|
n += ftype__fprintf_parms(&alias->proto, cu,
|
|
|
|
indent + (strlen(name) + 7) / 8,
|
|
|
|
fp);
|
2007-04-30 21:26:29 +02:00
|
|
|
n += fprintf(fp, "; /* size=%zd, low_pc=%#llx */",
|
|
|
|
exp->size, (unsigned long long)exp->low_pc);
|
|
|
|
#if 0
|
2007-04-30 21:10:54 +02:00
|
|
|
n = fprintf(fp, "%s(); /* size=%zd, low_pc=%#llx */",
|
|
|
|
function__name(alias, cu), exp->size,
|
2007-03-28 16:38:32 +02:00
|
|
|
(unsigned long long)exp->low_pc);
|
2007-04-30 21:26:29 +02:00
|
|
|
#endif
|
2007-04-30 21:37:18 +02:00
|
|
|
c = 69;
|
2007-02-15 14:56:16 +01:00
|
|
|
printed += n;
|
2006-11-20 18:43:39 +01:00
|
|
|
}
|
|
|
|
break;
|
2006-11-20 19:17:42 +01:00
|
|
|
case DW_TAG_variable:
|
2007-02-15 14:56:16 +01:00
|
|
|
printed = fprintf(fp, "%.*s", indent, tabs);
|
|
|
|
n = fprintf(fp, "%s %s;",
|
|
|
|
variable__type_name(vtag, cu, bf, sizeof(bf)),
|
|
|
|
variable__name(vtag, cu));
|
|
|
|
c += n;
|
|
|
|
printed += n;
|
2006-11-20 19:17:42 +01:00
|
|
|
break;
|
|
|
|
case DW_TAG_label: {
|
|
|
|
const struct label *label = vtag;
|
2007-02-15 14:56:16 +01:00
|
|
|
printed = fprintf(fp, "%.*s", indent, tabs);
|
2007-02-01 16:50:28 +01:00
|
|
|
fputc('\n', fp);
|
2007-02-15 14:56:16 +01:00
|
|
|
++printed;
|
2007-02-01 16:50:28 +01:00
|
|
|
c = fprintf(fp, "%s:", label->name);
|
2007-02-15 14:56:16 +01:00
|
|
|
printed += c;
|
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-07-31 19:00:44 +02:00
|
|
|
printed = lexblock__fprintf(vtag, cu, function, indent, fp);
|
2007-05-31 06:39:44 +02:00
|
|
|
fputc('\n', fp);
|
|
|
|
return printed + 1;
|
2006-11-20 18:43:39 +01:00
|
|
|
default:
|
2007-02-15 14:56:16 +01:00
|
|
|
printed = fprintf(fp, "%.*s", indent, tabs);
|
|
|
|
n = fprintf(fp, "%s <%llx>", dwarf_tag_name(tag->tag),
|
2007-03-28 16:38:32 +02:00
|
|
|
(unsigned long long)tag->id);
|
2007-02-15 14:56:16 +01:00
|
|
|
c += n;
|
|
|
|
printed += n;
|
2006-11-20 18:43:39 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-02-15 14:56:16 +01:00
|
|
|
return printed + fprintf(fp, "%-*.*s// %5u\n", 70 - c, 70 - c, " ",
|
|
|
|
tag->decl_line);
|
2006-11-03 16:41:19 +01:00
|
|
|
}
|
|
|
|
|
2007-02-15 14:56:16 +01:00
|
|
|
size_t lexblock__fprintf(const struct lexblock *self, const struct cu *cu,
|
2007-07-31 19:00:44 +02:00
|
|
|
struct function *function, uint16_t indent, FILE *fp)
|
2006-11-20 18:43:39 +01:00
|
|
|
{
|
|
|
|
struct tag *pos;
|
2007-02-15 15:28:02 +01:00
|
|
|
size_t printed;
|
[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;
|
2007-07-31 18:25:22 +02:00
|
|
|
printed = fprintf(fp, "%.*s{", indent, tabs);
|
2007-07-31 19:00:44 +02:00
|
|
|
if (self->low_pc != 0) {
|
|
|
|
Dwarf_Off offset = self->low_pc - function->lexblock.low_pc;
|
|
|
|
|
|
|
|
if (offset == 0)
|
2007-11-10 18:56:30 +01:00
|
|
|
printed += fprintf(fp, " /* low_pc=%#llx */",
|
|
|
|
(unsigned long long)self->low_pc);
|
2007-07-31 19:00:44 +02:00
|
|
|
else
|
|
|
|
printed += fprintf(fp, " /* %s+%#llx */",
|
|
|
|
function__name(function, cu),
|
2007-11-10 18:56:30 +01:00
|
|
|
(unsigned long long)offset);
|
2007-07-31 19:00:44 +02:00
|
|
|
}
|
2007-07-31 18:25:22 +02:00
|
|
|
printed += fprintf(fp, "\n");
|
2007-01-03 01:26:01 +01:00
|
|
|
list_for_each_entry(pos, &self->tags, node)
|
2007-07-31 19:00:44 +02:00
|
|
|
printed += function__tag_fprintf(pos, cu, function, indent + 1, fp);
|
2007-07-31 18:25:22 +02:00
|
|
|
printed += fprintf(fp, "%.*s}", indent, tabs);
|
2007-07-31 19:00:44 +02:00
|
|
|
|
|
|
|
if (function->lexblock.low_pc != self->low_pc) {
|
|
|
|
const size_t size = self->high_pc - self->low_pc;
|
|
|
|
printed += fprintf(fp, " /* lexblock size=%zd */", size);
|
|
|
|
}
|
2007-07-31 18:25:22 +02:00
|
|
|
return printed;
|
[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-02-15 14:36:49 +01:00
|
|
|
size_t ftype__fprintf(const struct ftype *self, const struct cu *cu,
|
|
|
|
const char *name, const int inlined,
|
2007-03-28 16:38:32 +02:00
|
|
|
const int is_pointer, int type_spacing, FILE *fp)
|
2006-12-30 19:34:20 +01:00
|
|
|
{
|
|
|
|
struct tag *type = cu__find_tag_by_id(cu, self->tag.type);
|
2007-02-15 14:36:49 +01:00
|
|
|
char sbf[128];
|
2006-12-30 19:34:20 +01:00
|
|
|
const char *stype = tag__name(type, cu, sbf, sizeof(sbf));
|
2007-04-30 21:26:29 +02:00
|
|
|
size_t printed = fprintf(fp, "%s%-*s %s%s%s%s",
|
2007-02-15 15:28:02 +01:00
|
|
|
inlined ? "inline " : "",
|
|
|
|
type_spacing, stype,
|
|
|
|
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
|
|
|
|
2007-04-30 21:37:18 +02:00
|
|
|
return printed + ftype__fprintf_parms(self, cu, 0, fp);
|
2006-12-30 19:34:20 +01:00
|
|
|
}
|
|
|
|
|
2007-02-15 14:58:28 +01:00
|
|
|
static size_t function__fprintf(const struct tag *tag_self,
|
|
|
|
const struct cu *cu, FILE *fp)
|
2006-10-28 23:49:27 +02:00
|
|
|
{
|
2007-01-12 18:47:26 +01:00
|
|
|
struct function *self = tag__function(tag_self);
|
2007-07-08 19:55:15 +02:00
|
|
|
size_t printed = 0;
|
|
|
|
|
|
|
|
if (self->virtuality == DW_VIRTUALITY_virtual ||
|
|
|
|
self->virtuality == DW_VIRTUALITY_pure_virtual)
|
|
|
|
printed += fprintf(fp, "virtual ");
|
|
|
|
|
|
|
|
printed += ftype__fprintf(&self->proto, cu, function__name(self, cu),
|
|
|
|
function__declared_inline(self), 0, 0, fp);
|
2006-10-28 23:49:27 +02:00
|
|
|
|
2007-07-08 19:55:15 +02:00
|
|
|
if (self->virtuality == DW_VIRTUALITY_pure_virtual)
|
|
|
|
printed += fprintf(fp, " = 0");
|
|
|
|
|
|
|
|
return printed;
|
2007-01-12 19:00:07 +01:00
|
|
|
}
|
2006-11-20 18:43:39 +01:00
|
|
|
|
2007-02-15 15:01:01 +01:00
|
|
|
size_t function__fprintf_stats(const struct tag *tag_self,
|
|
|
|
const struct cu *cu, FILE *fp)
|
2007-01-12 19:00:07 +01:00
|
|
|
{
|
|
|
|
struct function *self = tag__function(tag_self);
|
2007-07-31 19:00:44 +02:00
|
|
|
size_t printed = lexblock__fprintf(&self->lexblock, cu, self, 0, fp);
|
2007-01-12 19:00:07 +01:00
|
|
|
|
2007-03-28 16:38:32 +02:00
|
|
|
printed += fprintf(fp, "/* size: %zd", function__size(self));
|
2007-01-12 19:00:07 +01:00
|
|
|
if (self->lexblock.nr_variables > 0)
|
2007-02-15 15:01:01 +01:00
|
|
|
printed += fprintf(fp, ", variables: %u",
|
|
|
|
self->lexblock.nr_variables);
|
2007-01-12 19:00:07 +01:00
|
|
|
if (self->lexblock.nr_labels > 0)
|
2007-02-15 15:01:01 +01:00
|
|
|
printed += fprintf(fp, ", goto labels: %u",
|
|
|
|
self->lexblock.nr_labels);
|
2007-01-12 19:00:07 +01:00
|
|
|
if (self->lexblock.nr_inline_expansions > 0)
|
2007-03-28 16:38:32 +02:00
|
|
|
printed += fprintf(fp, ", inline expansions: %u (%zd bytes)",
|
2007-02-01 16:50:28 +01:00
|
|
|
self->lexblock.nr_inline_expansions,
|
|
|
|
self->lexblock.size_inline_expansions);
|
2007-02-15 15:01:01 +01:00
|
|
|
return printed + fprintf(fp, " */\n");
|
2006-10-28 23:49:27 +02:00
|
|
|
}
|
|
|
|
|
2007-02-15 14:36:49 +01:00
|
|
|
static size_t class__fprintf_cacheline_boundary(uint32_t last_cacheline,
|
|
|
|
size_t sum, size_t sum_holes,
|
|
|
|
uint8_t *newline,
|
|
|
|
uint32_t *cacheline,
|
2007-03-28 16:38:32 +02:00
|
|
|
int indent, FILE *fp)
|
2006-12-07 22:20:46 +01:00
|
|
|
{
|
2006-12-25 01:27:22 +01:00
|
|
|
const size_t real_sum = sum + sum_holes;
|
2007-02-15 15:28:02 +01:00
|
|
|
size_t printed = 0;
|
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;
|
2006-12-14 19:49:06 +01:00
|
|
|
|
|
|
|
if (*newline) {
|
2007-02-15 14:36:49 +01:00
|
|
|
fputc('\n', fp);
|
2006-12-14 19:49:06 +01:00
|
|
|
*newline = 0;
|
2007-02-15 15:28:02 +01:00
|
|
|
++printed;
|
2006-12-14 19:49:06 +01:00
|
|
|
}
|
|
|
|
|
2007-02-15 15:28:02 +01:00
|
|
|
printed += fprintf(fp, "%.*s", indent, tabs);
|
[CLASSES]: Fully support nested classes
Example:
[acme@newtoy pahole]$ pahole net/ipv4/tcp.o flowi
/* include/net/flow.h:13 */
struct flowi {
int oif; /* 0 4 */
int iif; /* 4 4 */
__u32 mark; /* 8 4 */
union {
struct {
__be32 daddr; /* 0 4 */
__be32 saddr; /* 4 4 */
__u8 tos; /* 8 1 */
__u8 scope; /* 9 1 */
} ip4_u; /* 12 */
struct {
struct in6_addr daddr; /* 0 16 */
struct in6_addr saddr; /* 16 16 */
/* --- cacheline 1 boundary (32 bytes) --- */
__be32 flowlabel; /* 32 4 */
} ip6_u; /* 36 */
struct {
__le16 daddr; /* 0 2 */
__le16 saddr; /* 2 2 */
__u8 scope; /* 4 1 */
} dn_u; /* 6 */
} nl_u; /* 12 36 */
/* --- cacheline 1 boundary (32 bytes) was 16 bytes ago --- */
__u8 proto; /* 48 1 */
__u8 flags; /* 49 1 */
/* XXX 2 bytes hole, try to pack */
union {
struct {
__be16 sport; /* 0 2 */
__be16 dport; /* 2 2 */
} ports; /* 4 */
struct {
__u8 type; /* 0 1 */
__u8 code; /* 1 1 */
} icmpt; /* 2 */
struct {
__le16 sport; /* 0 2 */
__le16 dport; /* 2 2 */
} dnports; /* 4 */
__be32 spi; /* 4 */
} uli_u; /* 52 4 */
__u32 secid; /* 56 4 */
}; /* size: 60, cachelines: 2 */
/* sum members: 58, holes: 1, sum holes: 2 */
/* last cacheline: 28 bytes */
Supporting anonymous structs and unions just fine, even combinations of both,
like in struct page, in the Linux kernel:
[acme@newtoy pahole]$ pahole mm/mmap.o page
/* include/linux/mmzone.h:391 */
struct page {
long unsigned int flags; /* 0 4 */
atomic_t _count; /* 4 4 */
atomic_t _mapcount; /* 8 4 */
union {
struct {
long unsigned int private; /* 0 4 */
struct address_space * mapping; /* 4 4 */
}; /* 8 */
}; /* 12 8 */
long unsigned int index; /* 20 4 */
struct list_head lru; /* 24 8 */
/* --- cacheline 1 boundary (32 bytes) --- */
}; /* size: 32, cachelines: 1 */
Or struct freebsd_sys_getdents_args in the OpenBSD kernel:
/* /usr/home/leonardo/openbsd/src/sys/compat/freebsd/freebsd_syscallargs.h:231 */
struct freebsd_sys_getdents_args {
union {
register_t pad; /* 4 */
struct {
int datum; /* 0 4 */
} le; /* 4 */
struct {
int8_t pad[0]; /* 0 0 */
int datum; /* 0 4 */
} be; /* 4 */
} fd; /* 0 4 */
union {
register_t pad; /* 4 */
struct {
void * datum; /* 0 4 */
} le; /* 4 */
struct {
int8_t pad[0]; /* 0 0 */
void * datum; /* 0 4 */
} be; /* 4 */
} dirent; /* 4 4 */
union {
register_t pad; /* 4 */
struct {
unsigned int datum; /* 0 4 */
} le; /* 4 */
struct {
int8_t pad[0]; /* 0 0 */
unsigned int datum; /* 0 4 */
} be; /* 4 */
} count; /* 8 4 */
}; /* size: 12, cachelines: 1 */
/* last cacheline: 12 bytes */
/* definitions: 7 */
One more from the OpenBSD kernel:
/* /usr/home/leonardo/openbsd/src/sys/nfs/nfs.h:344 */
struct nfssvc_sock {
struct {
struct nfssvc_sock * tqe_next; /* 0 4 */
struct nfssvc_sock * * tqe_prev; /* 4 4 */
} ns_chain; /* 0 8 */
struct {
struct nfsuid * tqh_first; /* 0 4 */
struct nfsuid * * tqh_last; /* 4 4 */
} ns_uidlruhead; /* 8 8 */
struct file * ns_fp; /* 16 4 */
struct socket * ns_so; /* 20 4 */
struct mbuf * ns_nam; /* 24 4 */
struct mbuf * ns_raw; /* 28 4 */
/* --- cacheline 1 boundary (32 bytes) --- */
struct mbuf * ns_rawend; /* 32 4 */
struct mbuf * ns_rec; /* 36 4 */
struct mbuf * ns_recend; /* 40 4 */
struct mbuf * ns_frag; /* 44 4 */
int ns_flag; /* 48 4 */
int ns_solock; /* 52 4 */
int ns_cc; /* 56 4 */
int ns_reclen; /* 60 4 */
/* --- cacheline 2 boundary (64 bytes) --- */
int ns_numuids; /* 64 4 */
u_int32_t ns_sref; /* 68 4 */
struct {
struct nfsrv_descript * lh_first; /* 0 4 */
} ns_tq; /* 72 4 */
struct ns_uidhashtbl[29]; /* 76 116 */
/* --- cacheline 6 boundary (192 bytes) --- */
struct nfsrvw_delayhash ns_wdelayhashtbl[16]; /* 192 64 */
/* --- cacheline 8 boundary (256 bytes) --- */
}; /* size: 256, cachelines: 8 */
/* definitions: 12 */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 22:46:47 +01:00
|
|
|
|
2006-12-07 22:20:46 +01:00
|
|
|
if (cacheline_pos == 0)
|
2007-02-15 15:28:02 +01:00
|
|
|
printed += fprintf(fp, "/* --- cacheline %u boundary "
|
|
|
|
"(%u bytes) --- */\n", *cacheline,
|
|
|
|
cacheline_in_bytes);
|
2006-12-07 22:20:46 +01:00
|
|
|
else
|
2007-02-15 15:28:02 +01:00
|
|
|
printed += fprintf(fp, "/* --- cacheline %u boundary "
|
|
|
|
"(%u bytes) was %u bytes ago --- "
|
|
|
|
"*/\n", *cacheline,
|
|
|
|
cacheline_in_bytes, cacheline_pos);
|
2006-12-07 22:20:46 +01:00
|
|
|
}
|
2007-02-15 15:28:02 +01:00
|
|
|
return printed;
|
2006-12-07 22:20:46 +01:00
|
|
|
}
|
|
|
|
|
2007-07-09 01:57:23 +02:00
|
|
|
static size_t class__vtable_fprintf(struct class *self,
|
|
|
|
const struct conf_fprintf *conf, FILE *fp)
|
|
|
|
{
|
|
|
|
struct function *pos;
|
|
|
|
size_t printed = 0;
|
|
|
|
|
|
|
|
if (self->nr_vtable_entries == 0)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
printed += fprintf(fp, "%.*s/* vtable has %u entries: {\n",
|
|
|
|
conf->indent, tabs, self->nr_vtable_entries);
|
|
|
|
|
|
|
|
list_for_each_entry(pos, &self->vtable, vtable_node) {
|
|
|
|
printed += fprintf(fp, "%.*s [%d] = %s(%s), \n",
|
|
|
|
conf->indent, tabs, pos->vtable_entry,
|
|
|
|
pos->name, pos->linkage_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
printed += fprintf(fp, "%.*s} */", conf->indent, tabs);
|
|
|
|
out:
|
|
|
|
return printed;
|
|
|
|
}
|
|
|
|
|
2007-05-24 23:45:34 +02:00
|
|
|
size_t class__fprintf(struct class *self, const struct cu *cu,
|
2007-04-28 21:13:35 +02:00
|
|
|
const struct conf_fprintf *conf, FILE *fp)
|
2006-10-28 23:22:42 +02:00
|
|
|
{
|
2007-05-24 23:45:34 +02:00
|
|
|
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-29 15:01:15 +01:00
|
|
|
uint16_t nr_paddings = 0;
|
2007-01-10 19:39:20 +01:00
|
|
|
uint32_t sum = 0;
|
|
|
|
uint32_t sum_holes = 0;
|
2007-01-29 15:01:15 +01:00
|
|
|
uint32_t sum_paddings = 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;
|
2007-05-24 18:38:13 +02:00
|
|
|
int last_offset = -1, first = 1;
|
2007-01-10 19:39:20 +01:00
|
|
|
struct class_member *pos;
|
2007-05-24 05:16:23 +02:00
|
|
|
struct tag *tag_pos;
|
2007-05-25 22:33:49 +02:00
|
|
|
const char *current_accessibility = NULL;
|
2007-04-28 21:13:35 +02:00
|
|
|
struct conf_fprintf cconf = conf ? *conf : conf_fprintf__defaults;
|
2007-05-24 18:38:13 +02:00
|
|
|
size_t printed = fprintf(fp, "%s%sstruct%s%s",
|
2007-04-28 21:13:35 +02:00
|
|
|
cconf.prefix ?: "", cconf.prefix ? " " : "",
|
2007-05-24 23:45:34 +02:00
|
|
|
type__name(tself, cu) ? " " : "",
|
|
|
|
type__name(tself, cu) ?: "");
|
2007-04-28 21:13:35 +02:00
|
|
|
size_t indent = cconf.indent;
|
2007-01-10 19:39:20 +01:00
|
|
|
|
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-04-28 21:13:35 +02:00
|
|
|
cconf.indent = indent + 1;
|
2007-05-31 06:39:44 +02:00
|
|
|
cconf.no_semicolon = 0;
|
2007-04-28 21:13:35 +02:00
|
|
|
|
2007-05-24 18:38:13 +02:00
|
|
|
/* First look if we have DW_TAG_inheritance */
|
|
|
|
type__for_each_tag(tself, tag_pos) {
|
|
|
|
struct tag *type;
|
2007-05-25 22:02:05 +02:00
|
|
|
const char *accessibility;
|
2007-05-24 18:57:08 +02:00
|
|
|
|
2007-05-24 18:38:13 +02:00
|
|
|
if (tag_pos->tag != DW_TAG_inheritance)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (first) {
|
|
|
|
printed += fprintf(fp, " :");
|
|
|
|
first = 0;
|
|
|
|
} else
|
|
|
|
printed += fprintf(fp, ",");
|
|
|
|
|
2007-05-24 18:57:08 +02:00
|
|
|
pos = tag__class_member(tag_pos);
|
|
|
|
|
|
|
|
if (pos->virtuality == DW_VIRTUALITY_virtual)
|
|
|
|
printed += fprintf(fp, " virtual");
|
|
|
|
|
2007-05-25 22:02:05 +02:00
|
|
|
accessibility = tag__accessibility(tag_pos);
|
|
|
|
if (accessibility != NULL)
|
|
|
|
printed += fprintf(fp, " %s", accessibility);
|
2007-05-24 18:57:08 +02:00
|
|
|
|
2007-05-24 18:38:13 +02:00
|
|
|
type = cu__find_tag_by_id(cu, tag_pos->type);
|
2007-05-24 23:45:34 +02:00
|
|
|
printed += fprintf(fp, " %s", type__name(tag__type(type), cu));
|
2007-05-24 18:38:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
printed += fprintf(fp, " {\n");
|
|
|
|
|
2007-05-24 05:16:23 +02:00
|
|
|
type__for_each_tag(tself, tag_pos) {
|
[CLASSES]: Ditch class_member__names
Was a awful function, to replace it added some new __snprintf methods for more
classes (array_type, class_member, etc), the end result is a much nicer
rendering, for instance:
@@ -6549,11 +6549,11 @@
/* XXX 2 bytes hole, try to pack */
union {
- struct ff_constant_effect constant; /* 10 */
- struct ff_ramp_effect ramp; /* 12 */
- struct ff_periodic_effect periodic; /* 28 */
- struct ff_condition_effect condition[2]; /* 24 */
- struct ff_rumble_effect rumble; /* 4 */
+ struct ff_constant_effect constant; /* 10 */
+ struct ff_ramp_effect ramp; /* 12 */
+ struct ff_periodic_effect periodic; /* 28 */
+ struct ff_condition_effect condition[2]; /* 24 */
+ struct ff_rumble_effect rumble; /* 4 */
} u; /* 16 28 */
/* --- cacheline 1 boundary (32 bytes) was 12 bytes ago --- */
}; /* size: 44, cachelines: 2 */
Previously when such big class members appeared the comments with the size and
offset were unaligned, now its only in extreme cases, such as the array above
that things get unaligned.
End result is a smaller library:
[acme@newtoy pahole]$ codiff -V build/libclasses.so.orig build/libclasses.so
/home/acme/pahole/classes.c:
struct array_type | -4
nr_members: -1
-const char *name /* 36 4 */
1 struct changed
enumeration__print | +10 # 175 -> 185
union__snprintf | +32 # 576 -> 608
union__print | +16 # 182 -> 198
class_member__names | -851 (removed)
class_member__print | -721 # 1218 -> 497
class__print_struct | +54 # 1403 -> 1457
6 functions changed, 112 bytes added, 1572 bytes removed, diff: -1460
/home/acme/pahole/classes.c:
array_type__snprintf | +249 (added)
class_member__snprintf | +892 (added)
2 functions changed, 1141 bytes added
build/libclasses.so:
8 functions changed, 1253 bytes added, 1572 bytes removed, diff: -319
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 17:19:55 +01:00
|
|
|
struct tag *type;
|
2007-05-25 22:33:49 +02:00
|
|
|
const char *accessibility = tag__accessibility(tag_pos);
|
|
|
|
|
|
|
|
if (accessibility != NULL &&
|
|
|
|
accessibility != current_accessibility) {
|
|
|
|
current_accessibility = accessibility;
|
|
|
|
printed += fprintf(fp, "%.*s%s:\n\n",
|
|
|
|
cconf.indent - 1, tabs,
|
|
|
|
accessibility);
|
|
|
|
}
|
2006-12-14 19:49:06 +01:00
|
|
|
|
2007-05-24 19:11:33 +02:00
|
|
|
if (tag_pos->tag != DW_TAG_member &&
|
|
|
|
tag_pos->tag != DW_TAG_inheritance) {
|
2007-05-30 16:36:54 +02:00
|
|
|
if (!cconf.show_only_data_members) {
|
|
|
|
printed += tag__fprintf(tag_pos, cu, &cconf, fp);
|
2007-05-31 06:39:44 +02:00
|
|
|
printed += fprintf(fp, "\n\n");
|
2007-05-30 16:36:54 +02:00
|
|
|
}
|
2007-05-24 05:16:23 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
pos = tag__class_member(tag_pos);
|
|
|
|
|
2007-06-22 21:51:31 +02:00
|
|
|
if ((int)pos->offset != last_offset && !cconf.suppress_comments)
|
2007-03-28 18:21:27 +02:00
|
|
|
printed +=
|
|
|
|
class__fprintf_cacheline_boundary(last_cacheline,
|
|
|
|
sum, sum_holes,
|
|
|
|
&newline,
|
|
|
|
&last_cacheline,
|
2007-04-28 21:13:35 +02:00
|
|
|
cconf.indent,
|
|
|
|
fp);
|
2007-05-25 00:11:53 +02:00
|
|
|
/*
|
|
|
|
* These paranoid checks doesn't make much sense on
|
|
|
|
* DW_TAG_inheritance, have to understand why virtual public
|
|
|
|
* ancestors make the offset go backwards...
|
|
|
|
*/
|
2007-06-22 21:51:31 +02:00
|
|
|
if (!cconf.suppress_comments &&
|
|
|
|
last_offset != -1 && tag_pos->tag == DW_TAG_member) {
|
2007-03-29 16:25:02 +02:00
|
|
|
const ssize_t cc_last_size = pos->offset - last_offset;
|
|
|
|
|
2007-05-06 19:50:28 +02:00
|
|
|
if ((int)pos->offset < last_offset) {
|
2007-03-29 16:25:02 +02:00
|
|
|
if (!newline++) {
|
|
|
|
fputc('\n', fp);
|
|
|
|
++printed;
|
|
|
|
}
|
|
|
|
printed += fprintf(fp, "%.*s/* WARNING: DWARF"
|
|
|
|
" offset=%zd, real offset="
|
|
|
|
"%zd */\n",
|
2007-04-28 21:13:35 +02:00
|
|
|
cconf.indent, tabs,
|
2007-03-29 16:25:02 +02:00
|
|
|
pos->offset,
|
|
|
|
last_offset + last_size);
|
|
|
|
} else if (cc_last_size > 0 &&
|
2007-01-29 13:42:03 +01:00
|
|
|
(size_t)cc_last_size < last_size) {
|
[CLASSES]: Fully support nested classes
Example:
[acme@newtoy pahole]$ pahole net/ipv4/tcp.o flowi
/* include/net/flow.h:13 */
struct flowi {
int oif; /* 0 4 */
int iif; /* 4 4 */
__u32 mark; /* 8 4 */
union {
struct {
__be32 daddr; /* 0 4 */
__be32 saddr; /* 4 4 */
__u8 tos; /* 8 1 */
__u8 scope; /* 9 1 */
} ip4_u; /* 12 */
struct {
struct in6_addr daddr; /* 0 16 */
struct in6_addr saddr; /* 16 16 */
/* --- cacheline 1 boundary (32 bytes) --- */
__be32 flowlabel; /* 32 4 */
} ip6_u; /* 36 */
struct {
__le16 daddr; /* 0 2 */
__le16 saddr; /* 2 2 */
__u8 scope; /* 4 1 */
} dn_u; /* 6 */
} nl_u; /* 12 36 */
/* --- cacheline 1 boundary (32 bytes) was 16 bytes ago --- */
__u8 proto; /* 48 1 */
__u8 flags; /* 49 1 */
/* XXX 2 bytes hole, try to pack */
union {
struct {
__be16 sport; /* 0 2 */
__be16 dport; /* 2 2 */
} ports; /* 4 */
struct {
__u8 type; /* 0 1 */
__u8 code; /* 1 1 */
} icmpt; /* 2 */
struct {
__le16 sport; /* 0 2 */
__le16 dport; /* 2 2 */
} dnports; /* 4 */
__be32 spi; /* 4 */
} uli_u; /* 52 4 */
__u32 secid; /* 56 4 */
}; /* size: 60, cachelines: 2 */
/* sum members: 58, holes: 1, sum holes: 2 */
/* last cacheline: 28 bytes */
Supporting anonymous structs and unions just fine, even combinations of both,
like in struct page, in the Linux kernel:
[acme@newtoy pahole]$ pahole mm/mmap.o page
/* include/linux/mmzone.h:391 */
struct page {
long unsigned int flags; /* 0 4 */
atomic_t _count; /* 4 4 */
atomic_t _mapcount; /* 8 4 */
union {
struct {
long unsigned int private; /* 0 4 */
struct address_space * mapping; /* 4 4 */
}; /* 8 */
}; /* 12 8 */
long unsigned int index; /* 20 4 */
struct list_head lru; /* 24 8 */
/* --- cacheline 1 boundary (32 bytes) --- */
}; /* size: 32, cachelines: 1 */
Or struct freebsd_sys_getdents_args in the OpenBSD kernel:
/* /usr/home/leonardo/openbsd/src/sys/compat/freebsd/freebsd_syscallargs.h:231 */
struct freebsd_sys_getdents_args {
union {
register_t pad; /* 4 */
struct {
int datum; /* 0 4 */
} le; /* 4 */
struct {
int8_t pad[0]; /* 0 0 */
int datum; /* 0 4 */
} be; /* 4 */
} fd; /* 0 4 */
union {
register_t pad; /* 4 */
struct {
void * datum; /* 0 4 */
} le; /* 4 */
struct {
int8_t pad[0]; /* 0 0 */
void * datum; /* 0 4 */
} be; /* 4 */
} dirent; /* 4 4 */
union {
register_t pad; /* 4 */
struct {
unsigned int datum; /* 0 4 */
} le; /* 4 */
struct {
int8_t pad[0]; /* 0 0 */
unsigned int datum; /* 0 4 */
} be; /* 4 */
} count; /* 8 4 */
}; /* size: 12, cachelines: 1 */
/* last cacheline: 12 bytes */
/* definitions: 7 */
One more from the OpenBSD kernel:
/* /usr/home/leonardo/openbsd/src/sys/nfs/nfs.h:344 */
struct nfssvc_sock {
struct {
struct nfssvc_sock * tqe_next; /* 0 4 */
struct nfssvc_sock * * tqe_prev; /* 4 4 */
} ns_chain; /* 0 8 */
struct {
struct nfsuid * tqh_first; /* 0 4 */
struct nfsuid * * tqh_last; /* 4 4 */
} ns_uidlruhead; /* 8 8 */
struct file * ns_fp; /* 16 4 */
struct socket * ns_so; /* 20 4 */
struct mbuf * ns_nam; /* 24 4 */
struct mbuf * ns_raw; /* 28 4 */
/* --- cacheline 1 boundary (32 bytes) --- */
struct mbuf * ns_rawend; /* 32 4 */
struct mbuf * ns_rec; /* 36 4 */
struct mbuf * ns_recend; /* 40 4 */
struct mbuf * ns_frag; /* 44 4 */
int ns_flag; /* 48 4 */
int ns_solock; /* 52 4 */
int ns_cc; /* 56 4 */
int ns_reclen; /* 60 4 */
/* --- cacheline 2 boundary (64 bytes) --- */
int ns_numuids; /* 64 4 */
u_int32_t ns_sref; /* 68 4 */
struct {
struct nfsrv_descript * lh_first; /* 0 4 */
} ns_tq; /* 72 4 */
struct ns_uidhashtbl[29]; /* 76 116 */
/* --- cacheline 6 boundary (192 bytes) --- */
struct nfsrvw_delayhash ns_wdelayhashtbl[16]; /* 192 64 */
/* --- cacheline 8 boundary (256 bytes) --- */
}; /* size: 256, cachelines: 8 */
/* definitions: 12 */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 22:46:47 +01:00
|
|
|
if (!newline++) {
|
2007-02-15 14:36:49 +01:00
|
|
|
fputc('\n', fp);
|
2007-02-15 15:28:02 +01:00
|
|
|
++printed;
|
[CLASSES]: Fully support nested classes
Example:
[acme@newtoy pahole]$ pahole net/ipv4/tcp.o flowi
/* include/net/flow.h:13 */
struct flowi {
int oif; /* 0 4 */
int iif; /* 4 4 */
__u32 mark; /* 8 4 */
union {
struct {
__be32 daddr; /* 0 4 */
__be32 saddr; /* 4 4 */
__u8 tos; /* 8 1 */
__u8 scope; /* 9 1 */
} ip4_u; /* 12 */
struct {
struct in6_addr daddr; /* 0 16 */
struct in6_addr saddr; /* 16 16 */
/* --- cacheline 1 boundary (32 bytes) --- */
__be32 flowlabel; /* 32 4 */
} ip6_u; /* 36 */
struct {
__le16 daddr; /* 0 2 */
__le16 saddr; /* 2 2 */
__u8 scope; /* 4 1 */
} dn_u; /* 6 */
} nl_u; /* 12 36 */
/* --- cacheline 1 boundary (32 bytes) was 16 bytes ago --- */
__u8 proto; /* 48 1 */
__u8 flags; /* 49 1 */
/* XXX 2 bytes hole, try to pack */
union {
struct {
__be16 sport; /* 0 2 */
__be16 dport; /* 2 2 */
} ports; /* 4 */
struct {
__u8 type; /* 0 1 */
__u8 code; /* 1 1 */
} icmpt; /* 2 */
struct {
__le16 sport; /* 0 2 */
__le16 dport; /* 2 2 */
} dnports; /* 4 */
__be32 spi; /* 4 */
} uli_u; /* 52 4 */
__u32 secid; /* 56 4 */
}; /* size: 60, cachelines: 2 */
/* sum members: 58, holes: 1, sum holes: 2 */
/* last cacheline: 28 bytes */
Supporting anonymous structs and unions just fine, even combinations of both,
like in struct page, in the Linux kernel:
[acme@newtoy pahole]$ pahole mm/mmap.o page
/* include/linux/mmzone.h:391 */
struct page {
long unsigned int flags; /* 0 4 */
atomic_t _count; /* 4 4 */
atomic_t _mapcount; /* 8 4 */
union {
struct {
long unsigned int private; /* 0 4 */
struct address_space * mapping; /* 4 4 */
}; /* 8 */
}; /* 12 8 */
long unsigned int index; /* 20 4 */
struct list_head lru; /* 24 8 */
/* --- cacheline 1 boundary (32 bytes) --- */
}; /* size: 32, cachelines: 1 */
Or struct freebsd_sys_getdents_args in the OpenBSD kernel:
/* /usr/home/leonardo/openbsd/src/sys/compat/freebsd/freebsd_syscallargs.h:231 */
struct freebsd_sys_getdents_args {
union {
register_t pad; /* 4 */
struct {
int datum; /* 0 4 */
} le; /* 4 */
struct {
int8_t pad[0]; /* 0 0 */
int datum; /* 0 4 */
} be; /* 4 */
} fd; /* 0 4 */
union {
register_t pad; /* 4 */
struct {
void * datum; /* 0 4 */
} le; /* 4 */
struct {
int8_t pad[0]; /* 0 0 */
void * datum; /* 0 4 */
} be; /* 4 */
} dirent; /* 4 4 */
union {
register_t pad; /* 4 */
struct {
unsigned int datum; /* 0 4 */
} le; /* 4 */
struct {
int8_t pad[0]; /* 0 0 */
unsigned int datum; /* 0 4 */
} be; /* 4 */
} count; /* 8 4 */
}; /* size: 12, cachelines: 1 */
/* last cacheline: 12 bytes */
/* definitions: 7 */
One more from the OpenBSD kernel:
/* /usr/home/leonardo/openbsd/src/sys/nfs/nfs.h:344 */
struct nfssvc_sock {
struct {
struct nfssvc_sock * tqe_next; /* 0 4 */
struct nfssvc_sock * * tqe_prev; /* 4 4 */
} ns_chain; /* 0 8 */
struct {
struct nfsuid * tqh_first; /* 0 4 */
struct nfsuid * * tqh_last; /* 4 4 */
} ns_uidlruhead; /* 8 8 */
struct file * ns_fp; /* 16 4 */
struct socket * ns_so; /* 20 4 */
struct mbuf * ns_nam; /* 24 4 */
struct mbuf * ns_raw; /* 28 4 */
/* --- cacheline 1 boundary (32 bytes) --- */
struct mbuf * ns_rawend; /* 32 4 */
struct mbuf * ns_rec; /* 36 4 */
struct mbuf * ns_recend; /* 40 4 */
struct mbuf * ns_frag; /* 44 4 */
int ns_flag; /* 48 4 */
int ns_solock; /* 52 4 */
int ns_cc; /* 56 4 */
int ns_reclen; /* 60 4 */
/* --- cacheline 2 boundary (64 bytes) --- */
int ns_numuids; /* 64 4 */
u_int32_t ns_sref; /* 68 4 */
struct {
struct nfsrv_descript * lh_first; /* 0 4 */
} ns_tq; /* 72 4 */
struct ns_uidhashtbl[29]; /* 76 116 */
/* --- cacheline 6 boundary (192 bytes) --- */
struct nfsrvw_delayhash ns_wdelayhashtbl[16]; /* 192 64 */
/* --- cacheline 8 boundary (256 bytes) --- */
}; /* size: 256, cachelines: 8 */
/* definitions: 12 */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 22:46:47 +01:00
|
|
|
}
|
2007-02-15 15:28:02 +01:00
|
|
|
printed += fprintf(fp, "%.*s/* Bitfield "
|
2007-03-28 16:38:32 +02:00
|
|
|
"WARNING: DWARF size=%zd, "
|
|
|
|
"real size=%zd */\n",
|
2007-04-28 21:13:35 +02:00
|
|
|
cconf.indent, tabs,
|
2007-02-15 15:28:02 +01:00
|
|
|
last_size, cc_last_size);
|
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-02-15 14:36:49 +01:00
|
|
|
fputc('\n', fp);
|
2006-12-14 19:00:28 +01:00
|
|
|
newline = 0;
|
2007-02-15 15:28:02 +01:00
|
|
|
++printed;
|
2006-12-14 19:00:28 +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
|
|
|
type = cu__find_tag_by_id(cu, pos->tag.type);
|
2007-01-12 02:09:06 +01:00
|
|
|
if (type == NULL) {
|
2007-01-29 13:42:03 +01:00
|
|
|
tag__type_not_found(&pos->tag);
|
2007-02-15 15:28:02 +01:00
|
|
|
printed += fprintf(fp, "%.*s>>>ERROR: type for %s not "
|
2007-04-28 21:13:35 +02:00
|
|
|
"found!\n", cconf.indent, tabs, pos->name);
|
2007-01-12 02:09:06 +01:00
|
|
|
continue;
|
|
|
|
}
|
2007-01-29 03:16:33 +01:00
|
|
|
|
2007-01-29 15:43:49 +01:00
|
|
|
size = tag__size(type, cu);
|
2007-04-28 21:13:35 +02:00
|
|
|
printed += fprintf(fp, "%.*s", cconf.indent, tabs);
|
|
|
|
printed += struct_member__fprintf(pos, type, cu, &cconf, fp);
|
2007-01-29 15:43:49 +01:00
|
|
|
|
2007-06-22 21:51:31 +02:00
|
|
|
if (tag__is_struct(type) && !cconf.suppress_comments) {
|
2007-01-29 15:01:15 +01:00
|
|
|
const uint16_t padding = tag__class(type)->padding;
|
|
|
|
if (padding > 0) {
|
|
|
|
++nr_paddings;
|
|
|
|
sum_paddings += padding;
|
2007-01-29 15:43:49 +01:00
|
|
|
if (!newline++) {
|
2007-02-15 14:36:49 +01:00
|
|
|
fputc('\n', fp);
|
2007-02-15 15:28:02 +01:00
|
|
|
++printed;
|
2007-01-29 15:43:49 +01:00
|
|
|
}
|
|
|
|
|
2007-02-15 15:28:02 +01:00
|
|
|
printed += fprintf(fp, "\n%.*s/* XXX last "
|
|
|
|
"struct has %d byte%s of "
|
2007-04-28 21:13:35 +02:00
|
|
|
"padding */", cconf.indent,
|
2007-02-15 15:28:02 +01:00
|
|
|
tabs, padding,
|
|
|
|
padding != 1 ? "s" : "");
|
2007-01-29 15:01:15 +01:00
|
|
|
}
|
|
|
|
}
|
2007-01-29 03:16:33 +01:00
|
|
|
|
2007-06-22 21:51:31 +02:00
|
|
|
if (pos->bit_hole != 0 && !cconf.suppress_comments) {
|
2007-01-10 19:39:20 +01:00
|
|
|
if (!newline++) {
|
2007-02-15 14:36:49 +01:00
|
|
|
fputc('\n', fp);
|
2007-02-15 15:28:02 +01:00
|
|
|
++printed;
|
2007-01-10 19:39:20 +01:00
|
|
|
}
|
2007-02-15 15:28:02 +01:00
|
|
|
printed += fprintf(fp, "\n%.*s/* XXX %d bit%s hole, "
|
2007-04-28 21:13:35 +02:00
|
|
|
"try to pack */", cconf.indent, tabs,
|
2007-02-15 15:28:02 +01:00
|
|
|
pos->bit_hole,
|
|
|
|
pos->bit_hole != 1 ? "s" : "");
|
2006-12-07 16:07:22 +01:00
|
|
|
sum_bit_holes += pos->bit_hole;
|
|
|
|
}
|
|
|
|
|
2007-06-22 21:51:31 +02:00
|
|
|
if (pos->hole > 0 && !cconf.suppress_comments) {
|
2007-01-10 19:39:20 +01:00
|
|
|
if (!newline++) {
|
2007-02-15 14:36:49 +01:00
|
|
|
fputc('\n', fp);
|
2007-02-15 15:28:02 +01:00
|
|
|
++printed;
|
2007-01-10 19:39:20 +01:00
|
|
|
}
|
2007-02-15 15:28:02 +01:00
|
|
|
printed += fprintf(fp, "\n%.*s/* XXX %d byte%s hole, "
|
|
|
|
"try to pack */",
|
2007-04-28 21:13:35 +02:00
|
|
|
cconf.indent, tabs, pos->hole,
|
2007-02-15 15:28:02 +01:00
|
|
|
pos->hole != 1 ? "s" : "");
|
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-02-15 14:36:49 +01:00
|
|
|
fputc('\n', fp);
|
2007-02-15 15:28:02 +01:00
|
|
|
++printed;
|
2007-05-25 00:11:53 +02:00
|
|
|
|
|
|
|
/* XXX for now just skip these */
|
|
|
|
if (tag_pos->tag == DW_TAG_inheritance &&
|
|
|
|
pos->virtuality == DW_VIRTUALITY_virtual)
|
|
|
|
continue;
|
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.
|
|
|
|
*/
|
2007-05-06 19:50:28 +02:00
|
|
|
if (last_offset != (int)pos->offset ||
|
2006-12-06 18:09:36 +01:00
|
|
|
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-07-07 19:48:40 +02:00
|
|
|
if (!cconf.suppress_comments)
|
|
|
|
printed += class__fprintf_cacheline_boundary(last_cacheline,
|
|
|
|
sum, sum_holes,
|
|
|
|
&newline,
|
|
|
|
&last_cacheline,
|
|
|
|
cconf.indent, fp);
|
2007-07-09 01:57:23 +02:00
|
|
|
class__vtable_fprintf(self, &cconf, fp);
|
2007-04-28 21:13:35 +02:00
|
|
|
if (!cconf.emit_stats)
|
[CLASSES]: Fully support nested classes
Example:
[acme@newtoy pahole]$ pahole net/ipv4/tcp.o flowi
/* include/net/flow.h:13 */
struct flowi {
int oif; /* 0 4 */
int iif; /* 4 4 */
__u32 mark; /* 8 4 */
union {
struct {
__be32 daddr; /* 0 4 */
__be32 saddr; /* 4 4 */
__u8 tos; /* 8 1 */
__u8 scope; /* 9 1 */
} ip4_u; /* 12 */
struct {
struct in6_addr daddr; /* 0 16 */
struct in6_addr saddr; /* 16 16 */
/* --- cacheline 1 boundary (32 bytes) --- */
__be32 flowlabel; /* 32 4 */
} ip6_u; /* 36 */
struct {
__le16 daddr; /* 0 2 */
__le16 saddr; /* 2 2 */
__u8 scope; /* 4 1 */
} dn_u; /* 6 */
} nl_u; /* 12 36 */
/* --- cacheline 1 boundary (32 bytes) was 16 bytes ago --- */
__u8 proto; /* 48 1 */
__u8 flags; /* 49 1 */
/* XXX 2 bytes hole, try to pack */
union {
struct {
__be16 sport; /* 0 2 */
__be16 dport; /* 2 2 */
} ports; /* 4 */
struct {
__u8 type; /* 0 1 */
__u8 code; /* 1 1 */
} icmpt; /* 2 */
struct {
__le16 sport; /* 0 2 */
__le16 dport; /* 2 2 */
} dnports; /* 4 */
__be32 spi; /* 4 */
} uli_u; /* 52 4 */
__u32 secid; /* 56 4 */
}; /* size: 60, cachelines: 2 */
/* sum members: 58, holes: 1, sum holes: 2 */
/* last cacheline: 28 bytes */
Supporting anonymous structs and unions just fine, even combinations of both,
like in struct page, in the Linux kernel:
[acme@newtoy pahole]$ pahole mm/mmap.o page
/* include/linux/mmzone.h:391 */
struct page {
long unsigned int flags; /* 0 4 */
atomic_t _count; /* 4 4 */
atomic_t _mapcount; /* 8 4 */
union {
struct {
long unsigned int private; /* 0 4 */
struct address_space * mapping; /* 4 4 */
}; /* 8 */
}; /* 12 8 */
long unsigned int index; /* 20 4 */
struct list_head lru; /* 24 8 */
/* --- cacheline 1 boundary (32 bytes) --- */
}; /* size: 32, cachelines: 1 */
Or struct freebsd_sys_getdents_args in the OpenBSD kernel:
/* /usr/home/leonardo/openbsd/src/sys/compat/freebsd/freebsd_syscallargs.h:231 */
struct freebsd_sys_getdents_args {
union {
register_t pad; /* 4 */
struct {
int datum; /* 0 4 */
} le; /* 4 */
struct {
int8_t pad[0]; /* 0 0 */
int datum; /* 0 4 */
} be; /* 4 */
} fd; /* 0 4 */
union {
register_t pad; /* 4 */
struct {
void * datum; /* 0 4 */
} le; /* 4 */
struct {
int8_t pad[0]; /* 0 0 */
void * datum; /* 0 4 */
} be; /* 4 */
} dirent; /* 4 4 */
union {
register_t pad; /* 4 */
struct {
unsigned int datum; /* 0 4 */
} le; /* 4 */
struct {
int8_t pad[0]; /* 0 0 */
unsigned int datum; /* 0 4 */
} be; /* 4 */
} count; /* 8 4 */
}; /* size: 12, cachelines: 1 */
/* last cacheline: 12 bytes */
/* definitions: 7 */
One more from the OpenBSD kernel:
/* /usr/home/leonardo/openbsd/src/sys/nfs/nfs.h:344 */
struct nfssvc_sock {
struct {
struct nfssvc_sock * tqe_next; /* 0 4 */
struct nfssvc_sock * * tqe_prev; /* 4 4 */
} ns_chain; /* 0 8 */
struct {
struct nfsuid * tqh_first; /* 0 4 */
struct nfsuid * * tqh_last; /* 4 4 */
} ns_uidlruhead; /* 8 8 */
struct file * ns_fp; /* 16 4 */
struct socket * ns_so; /* 20 4 */
struct mbuf * ns_nam; /* 24 4 */
struct mbuf * ns_raw; /* 28 4 */
/* --- cacheline 1 boundary (32 bytes) --- */
struct mbuf * ns_rawend; /* 32 4 */
struct mbuf * ns_rec; /* 36 4 */
struct mbuf * ns_recend; /* 40 4 */
struct mbuf * ns_frag; /* 44 4 */
int ns_flag; /* 48 4 */
int ns_solock; /* 52 4 */
int ns_cc; /* 56 4 */
int ns_reclen; /* 60 4 */
/* --- cacheline 2 boundary (64 bytes) --- */
int ns_numuids; /* 64 4 */
u_int32_t ns_sref; /* 68 4 */
struct {
struct nfsrv_descript * lh_first; /* 0 4 */
} ns_tq; /* 72 4 */
struct ns_uidhashtbl[29]; /* 76 116 */
/* --- cacheline 6 boundary (192 bytes) --- */
struct nfsrvw_delayhash ns_wdelayhashtbl[16]; /* 192 64 */
/* --- cacheline 8 boundary (256 bytes) --- */
}; /* size: 256, cachelines: 8 */
/* definitions: 12 */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 22:46:47 +01:00
|
|
|
goto out;
|
|
|
|
|
2007-05-31 06:39:44 +02:00
|
|
|
printed += fprintf(fp, "\n%.*s/* size: %zd, cachelines: %zd */",
|
|
|
|
cconf.indent, tabs,
|
2007-02-15 15:28:02 +01:00
|
|
|
tself->size, tag__nr_cachelines(class__tag(self),
|
|
|
|
cu));
|
2007-02-15 14:36:49 +01:00
|
|
|
if (sum_holes > 0)
|
2007-05-31 06:39:44 +02:00
|
|
|
printed += fprintf(fp, "\n%.*s/* sum members: %u, holes: %d, "
|
|
|
|
"sum holes: %u */",
|
|
|
|
cconf.indent, tabs,
|
|
|
|
sum, self->nr_holes, sum_holes);
|
2007-02-15 14:36:49 +01:00
|
|
|
if (sum_bit_holes > 0)
|
2007-05-31 06:39:44 +02:00
|
|
|
printed += fprintf(fp, "\n%.*s/* bit holes: %d, sum bit "
|
|
|
|
"holes: %u bits */",
|
|
|
|
cconf.indent, tabs,
|
2007-02-15 15:28:02 +01:00
|
|
|
self->nr_bit_holes, sum_bit_holes);
|
2007-02-15 14:36:49 +01:00
|
|
|
if (self->padding > 0)
|
2007-05-31 06:39:44 +02:00
|
|
|
printed += fprintf(fp, "\n%.*s/* padding: %u */",
|
|
|
|
cconf.indent,
|
2007-02-15 15:28:02 +01:00
|
|
|
tabs, self->padding);
|
2007-02-15 14:36:49 +01:00
|
|
|
if (nr_paddings > 0)
|
2007-05-31 06:39:44 +02:00
|
|
|
printed += fprintf(fp, "\n%.*s/* paddings: %u, sum paddings: "
|
|
|
|
"%u */",
|
|
|
|
cconf.indent, tabs,
|
|
|
|
nr_paddings, sum_paddings);
|
2007-02-15 14:36:49 +01:00
|
|
|
if (self->bit_padding > 0)
|
2007-05-31 06:39:44 +02:00
|
|
|
printed += fprintf(fp, "\n%.*s/* bit_padding: %u bits */",
|
|
|
|
cconf.indent, tabs,
|
|
|
|
self->bit_padding);
|
2007-01-09 13:00:47 +01:00
|
|
|
last_cacheline = tself->size % cacheline_size;
|
2007-02-15 14:36:49 +01:00
|
|
|
if (last_cacheline != 0)
|
2007-05-31 06:39:44 +02:00
|
|
|
printed += fprintf(fp, "\n%.*s/* last cacheline: %u bytes */",
|
|
|
|
cconf.indent, tabs,
|
|
|
|
last_cacheline);
|
2007-01-10 19:39:20 +01:00
|
|
|
|
2007-02-15 14:36:49 +01:00
|
|
|
if (sum + sum_holes != tself->size - self->padding)
|
2007-05-31 06:39:44 +02:00
|
|
|
printed += fprintf(fp, "\n\n%.*s/* BRAIN FART ALERT! %zd != %u "
|
|
|
|
"+ %u(holes), diff = %zd */\n",
|
|
|
|
cconf.indent, tabs,
|
|
|
|
tself->size, sum, sum_holes,
|
2007-02-15 15:28:02 +01:00
|
|
|
tself->size - (sum + sum_holes));
|
2007-11-10 19:27:24 +01:00
|
|
|
fputc('\n', fp);
|
[CLASSES]: Fully support nested classes
Example:
[acme@newtoy pahole]$ pahole net/ipv4/tcp.o flowi
/* include/net/flow.h:13 */
struct flowi {
int oif; /* 0 4 */
int iif; /* 4 4 */
__u32 mark; /* 8 4 */
union {
struct {
__be32 daddr; /* 0 4 */
__be32 saddr; /* 4 4 */
__u8 tos; /* 8 1 */
__u8 scope; /* 9 1 */
} ip4_u; /* 12 */
struct {
struct in6_addr daddr; /* 0 16 */
struct in6_addr saddr; /* 16 16 */
/* --- cacheline 1 boundary (32 bytes) --- */
__be32 flowlabel; /* 32 4 */
} ip6_u; /* 36 */
struct {
__le16 daddr; /* 0 2 */
__le16 saddr; /* 2 2 */
__u8 scope; /* 4 1 */
} dn_u; /* 6 */
} nl_u; /* 12 36 */
/* --- cacheline 1 boundary (32 bytes) was 16 bytes ago --- */
__u8 proto; /* 48 1 */
__u8 flags; /* 49 1 */
/* XXX 2 bytes hole, try to pack */
union {
struct {
__be16 sport; /* 0 2 */
__be16 dport; /* 2 2 */
} ports; /* 4 */
struct {
__u8 type; /* 0 1 */
__u8 code; /* 1 1 */
} icmpt; /* 2 */
struct {
__le16 sport; /* 0 2 */
__le16 dport; /* 2 2 */
} dnports; /* 4 */
__be32 spi; /* 4 */
} uli_u; /* 52 4 */
__u32 secid; /* 56 4 */
}; /* size: 60, cachelines: 2 */
/* sum members: 58, holes: 1, sum holes: 2 */
/* last cacheline: 28 bytes */
Supporting anonymous structs and unions just fine, even combinations of both,
like in struct page, in the Linux kernel:
[acme@newtoy pahole]$ pahole mm/mmap.o page
/* include/linux/mmzone.h:391 */
struct page {
long unsigned int flags; /* 0 4 */
atomic_t _count; /* 4 4 */
atomic_t _mapcount; /* 8 4 */
union {
struct {
long unsigned int private; /* 0 4 */
struct address_space * mapping; /* 4 4 */
}; /* 8 */
}; /* 12 8 */
long unsigned int index; /* 20 4 */
struct list_head lru; /* 24 8 */
/* --- cacheline 1 boundary (32 bytes) --- */
}; /* size: 32, cachelines: 1 */
Or struct freebsd_sys_getdents_args in the OpenBSD kernel:
/* /usr/home/leonardo/openbsd/src/sys/compat/freebsd/freebsd_syscallargs.h:231 */
struct freebsd_sys_getdents_args {
union {
register_t pad; /* 4 */
struct {
int datum; /* 0 4 */
} le; /* 4 */
struct {
int8_t pad[0]; /* 0 0 */
int datum; /* 0 4 */
} be; /* 4 */
} fd; /* 0 4 */
union {
register_t pad; /* 4 */
struct {
void * datum; /* 0 4 */
} le; /* 4 */
struct {
int8_t pad[0]; /* 0 0 */
void * datum; /* 0 4 */
} be; /* 4 */
} dirent; /* 4 4 */
union {
register_t pad; /* 4 */
struct {
unsigned int datum; /* 0 4 */
} le; /* 4 */
struct {
int8_t pad[0]; /* 0 0 */
unsigned int datum; /* 0 4 */
} be; /* 4 */
} count; /* 8 4 */
}; /* size: 12, cachelines: 1 */
/* last cacheline: 12 bytes */
/* definitions: 7 */
One more from the OpenBSD kernel:
/* /usr/home/leonardo/openbsd/src/sys/nfs/nfs.h:344 */
struct nfssvc_sock {
struct {
struct nfssvc_sock * tqe_next; /* 0 4 */
struct nfssvc_sock * * tqe_prev; /* 4 4 */
} ns_chain; /* 0 8 */
struct {
struct nfsuid * tqh_first; /* 0 4 */
struct nfsuid * * tqh_last; /* 4 4 */
} ns_uidlruhead; /* 8 8 */
struct file * ns_fp; /* 16 4 */
struct socket * ns_so; /* 20 4 */
struct mbuf * ns_nam; /* 24 4 */
struct mbuf * ns_raw; /* 28 4 */
/* --- cacheline 1 boundary (32 bytes) --- */
struct mbuf * ns_rawend; /* 32 4 */
struct mbuf * ns_rec; /* 36 4 */
struct mbuf * ns_recend; /* 40 4 */
struct mbuf * ns_frag; /* 44 4 */
int ns_flag; /* 48 4 */
int ns_solock; /* 52 4 */
int ns_cc; /* 56 4 */
int ns_reclen; /* 60 4 */
/* --- cacheline 2 boundary (64 bytes) --- */
int ns_numuids; /* 64 4 */
u_int32_t ns_sref; /* 68 4 */
struct {
struct nfsrv_descript * lh_first; /* 0 4 */
} ns_tq; /* 72 4 */
struct ns_uidhashtbl[29]; /* 76 116 */
/* --- cacheline 6 boundary (192 bytes) --- */
struct nfsrvw_delayhash ns_wdelayhashtbl[16]; /* 192 64 */
/* --- cacheline 8 boundary (256 bytes) --- */
}; /* size: 256, cachelines: 8 */
/* definitions: 12 */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2007-01-10 22:46:47 +01:00
|
|
|
out:
|
2007-06-22 21:43:29 +02:00
|
|
|
return printed + fprintf(fp, "%.*s}%s%s", indent, tabs,
|
2007-05-31 06:39:44 +02:00
|
|
|
cconf.suffix ? " ": "", cconf.suffix ?: "");
|
2006-10-28 23:22:42 +02:00
|
|
|
}
|
|
|
|
|
2007-02-15 14:36:49 +01:00
|
|
|
static size_t variable__fprintf(const struct tag *tag, const struct cu *cu,
|
2007-04-28 21:13:35 +02:00
|
|
|
const struct conf_fprintf *conf, FILE *fp)
|
2007-02-02 14:56:53 +01:00
|
|
|
{
|
|
|
|
const struct variable *var = tag__variable(tag);
|
|
|
|
const char *name = variable__name(var, cu);
|
2007-02-15 15:28:02 +01:00
|
|
|
size_t printed = 0;
|
2007-02-02 14:56:53 +01:00
|
|
|
|
|
|
|
if (name != NULL) {
|
|
|
|
struct tag *type = variable__type(var, cu);
|
|
|
|
if (type != NULL) {
|
|
|
|
const char *varprefix = variable__prefix(var);
|
|
|
|
|
|
|
|
if (varprefix != NULL)
|
2007-02-15 15:28:02 +01:00
|
|
|
printed += fprintf(fp, "%s", varprefix);
|
2007-04-28 21:13:35 +02:00
|
|
|
printed += type__fprintf(type, cu, name, conf, fp);
|
2007-02-02 14:56:53 +01:00
|
|
|
}
|
|
|
|
}
|
2007-02-15 15:28:02 +01:00
|
|
|
return printed;
|
2007-02-02 14:56:53 +01:00
|
|
|
}
|
|
|
|
|
2007-05-24 18:18:38 +02:00
|
|
|
static size_t namespace__fprintf(const struct tag *tself, const struct cu *cu,
|
|
|
|
const struct conf_fprintf *conf, FILE *fp)
|
|
|
|
{
|
|
|
|
struct namespace *self = tag__namespace(tself);
|
|
|
|
struct conf_fprintf cconf = *conf;
|
|
|
|
size_t printed = fprintf(fp, "namespace %s {\n", self->name);
|
|
|
|
struct tag *pos;
|
|
|
|
|
|
|
|
++cconf.indent;
|
2007-05-31 06:39:44 +02:00
|
|
|
cconf.no_semicolon = 0;
|
2007-05-24 18:18:38 +02:00
|
|
|
|
|
|
|
namespace__for_each_tag(self, pos) {
|
|
|
|
printed += tag__fprintf(pos, cu, &cconf, fp);
|
2007-05-31 06:39:44 +02:00
|
|
|
printed += fprintf(fp, "\n\n");
|
2007-05-24 18:18:38 +02:00
|
|
|
}
|
|
|
|
|
2007-05-31 06:39:44 +02:00
|
|
|
return printed + fprintf(fp, "}");
|
2007-05-24 18:18:38 +02:00
|
|
|
}
|
|
|
|
|
2007-07-05 01:36:28 +02:00
|
|
|
size_t tag__fprintf(struct tag *self, const struct cu *cu,
|
2007-04-28 21:13:35 +02:00
|
|
|
const struct conf_fprintf *conf, FILE *fp)
|
2006-10-28 23:22:42 +02:00
|
|
|
{
|
2007-05-24 17:45:45 +02:00
|
|
|
size_t printed = 0;
|
2007-04-28 21:13:35 +02:00
|
|
|
struct conf_fprintf tconf;
|
|
|
|
const struct conf_fprintf *pconf = conf;
|
|
|
|
|
|
|
|
if (conf == NULL) {
|
|
|
|
tconf = conf_fprintf__defaults;
|
|
|
|
pconf = &tconf;
|
|
|
|
|
|
|
|
if (tconf.expand_types)
|
|
|
|
tconf.name_spacing = 55;
|
2007-05-31 07:21:36 +02:00
|
|
|
else if (tag__is_union(self))
|
2007-04-28 21:13:35 +02:00
|
|
|
tconf.name_spacing = 21;
|
|
|
|
} else if (conf->name_spacing == 0 || conf->type_spacing == 0) {
|
|
|
|
tconf = *conf;
|
|
|
|
pconf = &tconf;
|
|
|
|
|
|
|
|
if (tconf.name_spacing == 0) {
|
|
|
|
if (tconf.expand_types)
|
|
|
|
tconf.name_spacing = 55;
|
|
|
|
else
|
|
|
|
tconf.name_spacing =
|
2007-05-31 07:21:36 +02:00
|
|
|
tag__is_union(self) ? 21 : 23;
|
2007-04-28 21:13:35 +02:00
|
|
|
}
|
|
|
|
if (tconf.type_spacing == 0)
|
|
|
|
tconf.type_spacing = 26;
|
|
|
|
}
|
2006-10-29 00:13:27 +02:00
|
|
|
|
2007-07-05 01:36:28 +02:00
|
|
|
if (pconf->expand_types)
|
|
|
|
++self->recursivity_level;
|
|
|
|
|
2007-05-24 17:45:45 +02:00
|
|
|
if (pconf->show_decl_info) {
|
|
|
|
printed += fprintf(fp, "%.*s", pconf->indent, tabs);
|
|
|
|
printed += tag__fprintf_decl_info(self, fp);
|
|
|
|
}
|
2007-05-24 05:16:23 +02:00
|
|
|
printed += fprintf(fp, "%.*s", pconf->indent, tabs);
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
switch (self->tag) {
|
2007-01-12 18:24:41 +01:00
|
|
|
case DW_TAG_enumeration_type:
|
2007-05-24 23:45:34 +02:00
|
|
|
printed += enumeration__fprintf(self, cu, pconf, fp);
|
2007-01-12 18:24:41 +01:00
|
|
|
break;
|
2007-01-12 18:13:38 +01:00
|
|
|
case DW_TAG_typedef:
|
2007-07-02 01:04:19 +02:00
|
|
|
printed += typedef__fprintf(self, cu, pconf, fp);
|
2007-01-12 18:13:38 +01:00
|
|
|
break;
|
2006-10-28 23:22:42 +02:00
|
|
|
case DW_TAG_structure_type:
|
2007-04-28 21:13:35 +02:00
|
|
|
printed += class__fprintf(tag__class(self), cu, pconf, fp);
|
2006-10-28 23:22:42 +02:00
|
|
|
break;
|
2007-05-24 18:18:38 +02:00
|
|
|
case DW_TAG_namespace:
|
|
|
|
printed += namespace__fprintf(self, cu, pconf, fp);
|
|
|
|
break;
|
2007-01-12 19:19:13 +01:00
|
|
|
case DW_TAG_subprogram:
|
2007-02-15 15:03:47 +01:00
|
|
|
printed += function__fprintf(self, cu, fp);
|
2007-01-12 19:19:13 +01:00
|
|
|
break;
|
2007-01-12 21:00:32 +01:00
|
|
|
case DW_TAG_union_type:
|
2007-04-28 21:13:35 +02:00
|
|
|
printed += union__fprintf(tag__type(self), cu, pconf, fp);
|
2007-01-12 21:00:32 +01:00
|
|
|
break;
|
2007-02-02 14:56:53 +01:00
|
|
|
case DW_TAG_variable:
|
2007-04-28 21:13:35 +02:00
|
|
|
printed += variable__fprintf(self, cu, pconf, fp);
|
2007-02-02 14:56:53 +01:00
|
|
|
break;
|
2007-05-26 17:39:16 +02:00
|
|
|
case DW_TAG_imported_declaration:
|
|
|
|
printed += imported_declaration__fprintf(self, cu, fp);
|
|
|
|
break;
|
2007-05-26 15:54:27 +02:00
|
|
|
case DW_TAG_imported_module:
|
|
|
|
printed += imported_module__fprintf(self, cu, fp);
|
|
|
|
break;
|
2006-10-28 23:22:42 +02:00
|
|
|
default:
|
2007-05-24 05:16:23 +02:00
|
|
|
printed += fprintf(fp, "/* %s: %s tag not supported! */", __func__,
|
2007-02-15 15:03:47 +01:00
|
|
|
dwarf_tag_name(self->tag));
|
2006-10-28 23:22:42 +02:00
|
|
|
break;
|
|
|
|
}
|
2007-02-15 15:03:47 +01:00
|
|
|
|
2007-05-31 06:39:44 +02:00
|
|
|
if (!pconf->no_semicolon) {
|
|
|
|
fputc(';', fp);
|
|
|
|
++printed;
|
|
|
|
}
|
|
|
|
|
2007-07-09 00:47:26 +02:00
|
|
|
if (self->tag == DW_TAG_subprogram &&
|
|
|
|
!pconf->suppress_comments) {
|
|
|
|
const struct function *fself = tag__function(self);
|
|
|
|
|
|
|
|
if (fself->linkage_name != NULL)
|
|
|
|
printed += fprintf(fp, " /* linkage=%s */", fself->linkage_name);
|
|
|
|
}
|
|
|
|
|
2007-07-05 01:36:28 +02:00
|
|
|
if (pconf->expand_types)
|
|
|
|
--self->recursivity_level;
|
|
|
|
|
2007-02-15 15:03:47 +01:00
|
|
|
return printed;
|
2006-10-28 23:22:42 +02:00
|
|
|
}
|
|
|
|
|
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",
|
2007-03-28 16:38:32 +02:00
|
|
|
fn, dwarf_tag_name(dwarf_tag(die)),
|
|
|
|
(unsigned long long)dwarf_dieoffset(die));
|
2007-01-08 02:57:32 +01:00
|
|
|
}
|
|
|
|
|
2007-01-09 15:55:45 +01:00
|
|
|
#define cu__tag_not_handled(die) __cu__tag_not_handled(die, __FUNCTION__)
|
|
|
|
|
2007-05-24 04:19:35 +02:00
|
|
|
static struct tag *__die__process_tag(Dwarf_Die *die, struct cu *cu,
|
|
|
|
const char *fn);
|
2007-01-09 15:55:45 +01:00
|
|
|
|
|
|
|
#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
|
|
|
|
2007-05-24 17:16:59 +02:00
|
|
|
return &class->type.namespace.tag;
|
2006-12-06 14:35:21 +01:00
|
|
|
}
|
|
|
|
|
2007-05-24 17:30:33 +02:00
|
|
|
static void die__process_namespace(Dwarf_Die *die,
|
|
|
|
struct namespace *namespace, struct cu *cu);
|
|
|
|
|
|
|
|
static struct tag *die__create_new_namespace(Dwarf_Die *die, struct cu *cu)
|
|
|
|
{
|
|
|
|
Dwarf_Die child;
|
|
|
|
struct namespace *namespace = namespace__new(die);
|
|
|
|
|
|
|
|
if (namespace == NULL)
|
|
|
|
oom("namespace__new");
|
|
|
|
|
|
|
|
if (dwarf_haschildren(die) != 0 && dwarf_child(die, &child) == 0)
|
|
|
|
die__process_namespace(&child, namespace, cu);
|
|
|
|
|
|
|
|
return &namespace->tag;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2007-05-24 17:16:59 +02:00
|
|
|
return &utype->namespace.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-05-24 17:16:59 +02:00
|
|
|
return &tdef->namespace.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__);
|
2007-01-29 13:42:03 +01:00
|
|
|
return NULL;
|
2006-12-08 15:58:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
2007-01-26 03:29:53 +01:00
|
|
|
struct lexblock *lexblock)
|
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);
|
2007-01-26 03:29:53 +01:00
|
|
|
else {
|
|
|
|
/*
|
|
|
|
* DW_TAG_formal_parameters on a non DW_TAG_subprogram nor
|
|
|
|
* DW_TAG_subroutine_type tag happens sometimes, likely due to
|
|
|
|
* compiler optimizing away a inline expansion (at least this
|
|
|
|
* was observed in some cases, such as in the Linux kernel
|
|
|
|
* current_kernel_time function circa 2.6.20-rc5), keep it in
|
|
|
|
* the lexblock tag list because it can be referenced as an
|
|
|
|
* DW_AT_abstract_origin in another DW_TAG_formal_parameter.
|
|
|
|
*/
|
|
|
|
lexblock__add_tag(lexblock, &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-02-02 14:56:53 +01:00
|
|
|
static struct tag *die__create_new_variable(Dwarf_Die *die)
|
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");
|
|
|
|
|
2007-02-02 14:56:53 +01:00
|
|
|
return &var->tag;
|
2007-01-03 12:49:20 +01:00
|
|
|
}
|
|
|
|
|
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__);
|
2007-01-29 13:42:03 +01:00
|
|
|
return NULL;
|
2007-01-09 01:06:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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-05-24 17:16:59 +02:00
|
|
|
return &enumeration->namespace.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-05-24 04:19:35 +02:00
|
|
|
default: {
|
|
|
|
struct tag *tag = die__process_tag(die, cu);
|
|
|
|
|
2007-07-09 01:57:23 +02:00
|
|
|
if (tag != NULL) {
|
2007-05-24 17:16:59 +02:00
|
|
|
namespace__add_tag(&class->namespace, tag);
|
2007-07-09 01:57:23 +02:00
|
|
|
if (tag->tag == DW_TAG_subprogram) {
|
|
|
|
struct function *fself = tag__function(tag);
|
|
|
|
|
|
|
|
if (fself->vtable_entry != -1)
|
|
|
|
class__add_vtable_entry(type__class(class), fself);
|
|
|
|
}
|
|
|
|
}
|
2007-01-09 15:04:12 +01:00
|
|
|
continue;
|
2007-01-06 17:07:28 +01:00
|
|
|
}
|
2007-05-24 04:19:35 +02:00
|
|
|
}
|
2007-01-06 17:07:28 +01:00
|
|
|
} while (dwarf_siblingof(die, die) == 0);
|
2006-11-19 00:06:03 +01:00
|
|
|
}
|
|
|
|
|
2007-05-24 17:30:33 +02:00
|
|
|
static void die__process_namespace(Dwarf_Die *die,
|
|
|
|
struct namespace *namespace, struct cu *cu)
|
|
|
|
{
|
|
|
|
do {
|
|
|
|
struct tag *tag = die__process_tag(die, cu);
|
|
|
|
|
|
|
|
if (tag != NULL)
|
|
|
|
namespace__add_tag(namespace, tag);
|
|
|
|
} while (dwarf_siblingof(die, die) == 0);
|
|
|
|
}
|
|
|
|
|
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-26 03:29:53 +01:00
|
|
|
die__create_new_parameter(die, ftype, lexblock);
|
2007-01-09 15:04:12 +01:00
|
|
|
continue;
|
2007-02-02 14:56:53 +01:00
|
|
|
case DW_TAG_variable: {
|
|
|
|
struct tag *tag = die__create_new_variable(die);
|
|
|
|
lexblock__add_variable(lexblock, tag__variable(tag));
|
|
|
|
}
|
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-05-24 04:19:35 +02:00
|
|
|
default: {
|
|
|
|
struct tag *tag = die__process_tag(die, cu);
|
|
|
|
if (tag != NULL)
|
|
|
|
cu__add_tag(cu, tag);
|
|
|
|
}
|
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-05-24 04:19:35 +02:00
|
|
|
static struct tag *__die__process_tag(Dwarf_Die *die, struct cu *cu,
|
|
|
|
const char *fn)
|
2007-01-09 15:55:45 +01:00
|
|
|
{
|
|
|
|
switch (dwarf_tag(die)) {
|
|
|
|
case DW_TAG_array_type:
|
2007-05-24 04:19:35 +02:00
|
|
|
return die__create_new_array(die);
|
2007-01-09 15:55:45 +01:00
|
|
|
case DW_TAG_base_type:
|
2007-05-24 04:19:35 +02:00
|
|
|
return die__create_new_base_type(die);
|
2007-01-09 15:55:45 +01:00
|
|
|
case DW_TAG_const_type:
|
2007-05-26 17:39:16 +02:00
|
|
|
case DW_TAG_imported_declaration:
|
2007-05-26 15:54:27 +02:00
|
|
|
case DW_TAG_imported_module:
|
2007-01-09 15:55:45 +01:00
|
|
|
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:
|
2007-05-24 04:19:35 +02:00
|
|
|
return die__create_new_tag(die);
|
2007-01-09 15:55:45 +01:00
|
|
|
case DW_TAG_enumeration_type:
|
2007-05-24 04:19:35 +02:00
|
|
|
return die__create_new_enumeration(die);
|
2007-05-24 17:30:33 +02:00
|
|
|
case DW_TAG_namespace:
|
|
|
|
return die__create_new_namespace(die, cu);
|
2007-01-09 15:55:45 +01:00
|
|
|
case DW_TAG_structure_type:
|
2007-05-24 04:19:35 +02:00
|
|
|
return die__create_new_class(die, cu);
|
2007-01-09 15:55:45 +01:00
|
|
|
case DW_TAG_subprogram:
|
2007-05-24 04:19:35 +02:00
|
|
|
return die__create_new_function(die, cu);
|
2007-01-09 15:55:45 +01:00
|
|
|
case DW_TAG_subroutine_type:
|
2007-05-24 04:19:35 +02:00
|
|
|
return die__create_new_subroutine_type(die);
|
2007-01-09 15:55:45 +01:00
|
|
|
case DW_TAG_typedef:
|
2007-05-24 04:19:35 +02:00
|
|
|
return die__create_new_typedef(die);
|
2007-01-09 15:55:45 +01:00
|
|
|
case DW_TAG_union_type:
|
2007-05-24 04:19:35 +02:00
|
|
|
return die__create_new_union(die, cu);
|
2007-02-02 14:56:53 +01:00
|
|
|
case DW_TAG_variable:
|
2007-05-24 04:19:35 +02:00
|
|
|
return die__create_new_variable(die);
|
2007-01-09 15:55:45 +01:00
|
|
|
default:
|
2007-05-24 04:19:35 +02:00
|
|
|
__cu__tag_not_handled(die, fn);
|
2007-01-09 15:55:45 +01:00
|
|
|
}
|
|
|
|
|
2007-05-24 04:19:35 +02:00
|
|
|
return NULL;
|
2007-01-09 15:55:45 +01:00
|
|
|
}
|
|
|
|
|
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-05-24 04:19:35 +02:00
|
|
|
struct tag *tag = die__process_tag(die, cu);
|
|
|
|
if (tag != NULL)
|
|
|
|
cu__add_tag(cu, tag);
|
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;
|
|
|
|
size_t hdr_size;
|
|
|
|
Dwarf *dwarf;
|
2006-12-20 15:35:45 +01:00
|
|
|
int fd = open(filename, O_RDONLY);
|
2007-03-28 17:54:46 +02:00
|
|
|
int err;
|
2006-10-28 23:22:42 +02:00
|
|
|
|
2007-03-28 17:54:46 +02:00
|
|
|
if (fd < 0) {
|
|
|
|
err = errno;
|
2006-10-28 23:22:42 +02:00
|
|
|
goto out;
|
2007-03-28 17:54:46 +02:00
|
|
|
}
|
2006-10-28 23:22:42 +02:00
|
|
|
|
2007-03-28 17:54:46 +02:00
|
|
|
err = -EINVAL;
|
2006-10-28 23:22:42 +02:00
|
|
|
dwarf = dwarf_begin(fd, DWARF_C_READ);
|
|
|
|
if (dwarf == NULL)
|
|
|
|
goto out_close;
|
|
|
|
|
|
|
|
offset = last_offset = 0;
|
|
|
|
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) {
|
2007-01-29 13:42:03 +01:00
|
|
|
struct cu *cu = cu__new(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");
|
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
|
|
|
|
2007-05-08 16:29:23 +02:00
|
|
|
static int with_executable_option(int argc, char *argv[])
|
2007-04-24 21:09:34 +02:00
|
|
|
{
|
2007-05-08 16:29:23 +02:00
|
|
|
while (--argc != 0)
|
2007-05-08 17:11:04 +02:00
|
|
|
if (strcmp(argv[argc], "--help") == 0 ||
|
|
|
|
strcmp(argv[argc], "-?") == 0 ||
|
|
|
|
strcmp(argv[argc], "-h") == 0 ||
|
|
|
|
strcmp(argv[argc], "--usage") == 0 ||
|
|
|
|
strcmp(argv[argc], "--executable") == 0 ||
|
2007-05-08 16:38:06 +02:00
|
|
|
(argv[argc][0] == '-' && argv[argc][1] != '-' &&
|
|
|
|
strchr(argv[argc] + 1, 'e') != NULL))
|
2007-05-08 16:29:23 +02:00
|
|
|
return 1;
|
2007-04-24 21:09:34 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int cus__loadfl(struct cus *self, struct argp *argp, int argc, char *argv[])
|
2007-03-30 18:22:28 +02:00
|
|
|
{
|
|
|
|
Dwfl *dwfl = NULL;
|
|
|
|
Dwarf_Die *cu_die = NULL;
|
|
|
|
Dwarf_Addr dwbias;
|
2007-04-24 21:09:34 +02:00
|
|
|
char **new_argv = NULL;
|
|
|
|
int err = -1;
|
|
|
|
|
|
|
|
if (argc == 1) {
|
|
|
|
argp_help(argp ? : dwfl_standard_argp(), stderr,
|
|
|
|
ARGP_HELP_SEE, argv[0]);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-05-08 16:29:23 +02:00
|
|
|
if (!with_executable_option(argc, argv)) {
|
2007-04-24 21:09:34 +02:00
|
|
|
new_argv = malloc((argc + 2) * sizeof(char *));
|
|
|
|
if (new_argv == NULL) {
|
|
|
|
fprintf(stderr, "%s: not enough memory!\n", __func__);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
memcpy(new_argv, argv, (argc - 1) * sizeof(char *));
|
|
|
|
new_argv[argc - 1] = "-e";
|
|
|
|
new_argv[argc] = argv[argc - 1];
|
|
|
|
new_argv[argc + 1] = NULL;
|
|
|
|
argv = new_argv;
|
|
|
|
argc++;
|
|
|
|
}
|
2007-03-30 18:22:28 +02:00
|
|
|
|
2007-03-30 18:54:14 +02:00
|
|
|
if (argp != NULL) {
|
|
|
|
const struct argp_child argp_children[] = {
|
|
|
|
{ .argp = dwfl_standard_argp(), },
|
|
|
|
{ .argp = NULL }
|
|
|
|
};
|
|
|
|
argp->children = argp_children;
|
2007-04-24 21:09:34 +02:00
|
|
|
argp_parse(argp, argc, argv, 0, NULL, &dwfl);
|
2007-03-30 18:54:14 +02:00
|
|
|
} else
|
2007-04-24 21:09:34 +02:00
|
|
|
argp_parse(dwfl_standard_argp(), argc, argv, 0, NULL, &dwfl);
|
2007-03-30 18:54:14 +02:00
|
|
|
|
2007-03-30 18:22:28 +02:00
|
|
|
if (dwfl == NULL)
|
2007-04-24 21:09:34 +02:00
|
|
|
goto out;
|
2007-03-30 18:22:28 +02:00
|
|
|
|
|
|
|
while ((cu_die = dwfl_nextcu(dwfl, cu_die, &dwbias)) != NULL) {
|
|
|
|
Dwarf_Die tmp;
|
|
|
|
struct cu *cu;
|
|
|
|
uint8_t pointer_size, offset_size;
|
|
|
|
|
|
|
|
dwarf_diecu(cu_die, &tmp, &pointer_size, &offset_size);
|
|
|
|
|
|
|
|
cu = cu__new(attr_string(cu_die, DW_AT_name), pointer_size);
|
|
|
|
if (cu == NULL)
|
|
|
|
oom("cu__new");
|
|
|
|
die__process(cu_die, cu);
|
|
|
|
cus__add(self, cu);
|
|
|
|
}
|
|
|
|
|
|
|
|
dwfl_end(dwfl);
|
2007-04-24 21:09:34 +02:00
|
|
|
err = 0;
|
|
|
|
out:
|
|
|
|
free(new_argv);
|
|
|
|
return err;
|
2007-03-30 18:22:28 +02:00
|
|
|
}
|
|
|
|
|
2007-03-28 17:54:46 +02:00
|
|
|
void cus__print_error_msg(const char *progname, const char *filename,
|
|
|
|
const int err)
|
|
|
|
{
|
|
|
|
if (err == -EINVAL)
|
|
|
|
fprintf(stderr, "%s: couldn't load DWARF info from %s\n",
|
|
|
|
progname, filename);
|
|
|
|
else
|
|
|
|
fprintf(stderr, "%s: %s\n", progname, strerror(err));
|
|
|
|
}
|
|
|
|
|
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-19 00:41:25 +01:00
|
|
|
void dwarves__init(size_t user_cacheline_size)
|
|
|
|
{
|
|
|
|
if (user_cacheline_size == 0) {
|
|
|
|
long sys_cacheline_size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
|
|
|
|
|
|
|
|
if (sys_cacheline_size > 0)
|
|
|
|
cacheline_size = sys_cacheline_size;
|
|
|
|
else
|
|
|
|
cacheline_size = 64; /* Fall back to a sane value */
|
|
|
|
} else
|
|
|
|
cacheline_size = user_cacheline_size;
|
|
|
|
}
|