2006-12-14 16:18:07 +01:00
|
|
|
/*
|
2006-10-28 23:22:42 +02:00
|
|
|
Copyright (C) 2006 Mandriva Conectiva S.A.
|
|
|
|
Copyright (C) 2006 Arnaldo Carvalho de Melo <acme@mandriva.com>
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it
|
|
|
|
under the terms of version 2 of the GNU General Public License as
|
|
|
|
published by the Free Software Foundation.
|
|
|
|
*/
|
|
|
|
|
2006-11-20 18:43:39 +01:00
|
|
|
#define _GNU_SOURCE
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
#include <assert.h>
|
2006-12-27 17:57:19 +01:00
|
|
|
#include <dirent.h>
|
2006-10-28 23:22:42 +02:00
|
|
|
#include <dwarf.h>
|
|
|
|
#include <fcntl.h>
|
2006-12-27 17:57:19 +01:00
|
|
|
#include <fnmatch.h>
|
2006-10-28 23:22:42 +02:00
|
|
|
#include <libelf.h>
|
2006-11-04 21:37:23 +01:00
|
|
|
#include <search.h>
|
2006-10-28 23:22:42 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include "list.h"
|
|
|
|
#include "classes.h"
|
|
|
|
|
2006-11-18 19:32:05 +01:00
|
|
|
static const char *dwarf_tag_names[] = {
|
|
|
|
[DW_TAG_array_type] = "array_type",
|
|
|
|
[DW_TAG_class_type] = "class_type",
|
|
|
|
[DW_TAG_entry_point] = "entry_point",
|
|
|
|
[DW_TAG_enumeration_type] = "enumeration_type",
|
|
|
|
[DW_TAG_formal_parameter] = "formal_parameter",
|
|
|
|
[DW_TAG_imported_declaration] = "imported_declaration",
|
|
|
|
[DW_TAG_label] = "label",
|
|
|
|
[DW_TAG_lexical_block] = "lexical_block",
|
|
|
|
[DW_TAG_member] = "member",
|
|
|
|
[DW_TAG_pointer_type] = "pointer_type",
|
|
|
|
[DW_TAG_reference_type] = "reference_type",
|
|
|
|
[DW_TAG_compile_unit] = "compile_unit",
|
|
|
|
[DW_TAG_string_type] = "string_type",
|
|
|
|
[DW_TAG_structure_type] = "structure_type",
|
|
|
|
[DW_TAG_subroutine_type] = "subroutine_type",
|
|
|
|
[DW_TAG_typedef] = "typedef",
|
|
|
|
[DW_TAG_union_type] = "union_type",
|
|
|
|
[DW_TAG_unspecified_parameters] = "unspecified_parameters",
|
|
|
|
[DW_TAG_variant] = "variant",
|
|
|
|
[DW_TAG_common_block] = "common_block",
|
|
|
|
[DW_TAG_common_inclusion] = "common_inclusion",
|
|
|
|
[DW_TAG_inheritance] = "inheritance",
|
|
|
|
[DW_TAG_inlined_subroutine] = "inlined_subroutine",
|
|
|
|
[DW_TAG_module] = "module",
|
|
|
|
[DW_TAG_ptr_to_member_type] = "ptr_to_member_type",
|
|
|
|
[DW_TAG_set_type] = "set_type",
|
|
|
|
[DW_TAG_subrange_type] = "subrange_type",
|
|
|
|
[DW_TAG_with_stmt] = "with_stmt",
|
|
|
|
[DW_TAG_access_declaration] = "access_declaration",
|
|
|
|
[DW_TAG_base_type] = "base_type",
|
|
|
|
[DW_TAG_catch_block] = "catch_block",
|
|
|
|
[DW_TAG_const_type] = "const_type",
|
|
|
|
[DW_TAG_constant] = "constant",
|
|
|
|
[DW_TAG_enumerator] = "enumerator",
|
|
|
|
[DW_TAG_file_type] = "file_type",
|
|
|
|
[DW_TAG_friend] = "friend",
|
|
|
|
[DW_TAG_namelist] = "namelist",
|
|
|
|
[DW_TAG_namelist_item] = "namelist_item",
|
|
|
|
[DW_TAG_packed_type] = "packed_type",
|
|
|
|
[DW_TAG_subprogram] = "subprogram",
|
|
|
|
[DW_TAG_template_type_parameter] = "template_type_parameter",
|
|
|
|
[DW_TAG_template_value_parameter] = "template_value_parameter",
|
|
|
|
[DW_TAG_thrown_type] = "thrown_type",
|
|
|
|
[DW_TAG_try_block] = "try_block",
|
|
|
|
[DW_TAG_variant_part] = "variant_part",
|
|
|
|
[DW_TAG_variable] = "variable",
|
|
|
|
[DW_TAG_volatile_type] = "volatile_type",
|
|
|
|
[DW_TAG_dwarf_procedure] = "dwarf_procedure",
|
|
|
|
[DW_TAG_restrict_type] = "restrict_type",
|
|
|
|
[DW_TAG_interface_type] = "interface_type",
|
|
|
|
[DW_TAG_namespace] = "namespace",
|
|
|
|
[DW_TAG_imported_module] = "imported_module",
|
|
|
|
[DW_TAG_unspecified_type] = "unspecified_type",
|
|
|
|
[DW_TAG_partial_unit] = "partial_unit",
|
|
|
|
[DW_TAG_imported_unit] = "imported_unit",
|
|
|
|
[DW_TAG_mutable_type] = "mutable_type",
|
|
|
|
[DW_TAG_condition] = "condition",
|
|
|
|
[DW_TAG_shared_type] = "shared_type",
|
|
|
|
};
|
|
|
|
|
2006-12-28 14:18:43 +01:00
|
|
|
const char *dwarf_tag_name(const uint32_t tag)
|
2006-11-18 19:32:05 +01:00
|
|
|
{
|
|
|
|
if (tag >= DW_TAG_array_type && tag <= DW_TAG_shared_type)
|
|
|
|
return dwarf_tag_names[tag];
|
|
|
|
return "INVALID";
|
|
|
|
}
|
|
|
|
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
static const char tabs[] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
|
|
|
|
|
2006-12-25 01:27:22 +01:00
|
|
|
size_t cacheline_size = DEFAULT_CACHELINE_SIZE;
|
2006-11-05 18:34:54 +01:00
|
|
|
|
2006-10-28 23:22:42 +02:00
|
|
|
static void *zalloc(const size_t size)
|
|
|
|
{
|
|
|
|
void *s = malloc(size);
|
|
|
|
if (s != NULL)
|
|
|
|
memset(s, 0, size);
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2006-12-08 15:58:46 +01:00
|
|
|
void *memdup(const void *src, size_t len)
|
|
|
|
{
|
|
|
|
void *s = malloc(len);
|
|
|
|
if (s != NULL)
|
|
|
|
memcpy(s, src, len);
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2006-11-04 21:37:23 +01:00
|
|
|
static void *strings;
|
|
|
|
|
|
|
|
static int strings__compare(const void *a, const void *b)
|
|
|
|
{
|
|
|
|
return strcmp(a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *strings__add(const char *str)
|
|
|
|
{
|
|
|
|
char **s;
|
|
|
|
|
|
|
|
if (str == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
s = tsearch(str, &strings, strings__compare);
|
|
|
|
if (s != NULL) {
|
|
|
|
if (*s == str) {
|
|
|
|
char *dup = strdup(str);
|
|
|
|
if (dup != NULL)
|
|
|
|
*s = dup;
|
|
|
|
else {
|
|
|
|
tdelete(str, &strings, strings__compare);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return *s;
|
|
|
|
}
|
|
|
|
|
2006-11-18 14:54:02 +01:00
|
|
|
static void tag__init(struct tag *self, uint16_t tag,
|
2006-12-24 15:18:14 +01:00
|
|
|
Dwarf_Off id, Dwarf_Off type,
|
2006-11-18 14:54:02 +01:00
|
|
|
const char *decl_file, uint32_t decl_line)
|
|
|
|
{
|
|
|
|
self->tag = tag;
|
|
|
|
self->id = id;
|
|
|
|
self->type = type;
|
|
|
|
self->decl_file = strings__add(decl_file);
|
|
|
|
self->decl_line = decl_line;
|
|
|
|
}
|
|
|
|
|
2006-12-29 19:34:11 +01:00
|
|
|
static struct tag *tag__new(uint16_t tag, Dwarf_Off id, Dwarf_Off type,
|
|
|
|
const char *decl_file, uint32_t decl_line)
|
|
|
|
{
|
|
|
|
struct tag *self = malloc(sizeof(*self));
|
|
|
|
|
|
|
|
if (self != NULL)
|
|
|
|
tag__init(self, tag, id, type, decl_file, decl_line);
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2006-12-29 23:58:03 +01:00
|
|
|
static struct base_type *base_type__new(const char *name, size_t size,
|
|
|
|
Dwarf_Off id, Dwarf_Off type,
|
|
|
|
const char *decl_file,
|
|
|
|
uint32_t decl_line)
|
|
|
|
{
|
|
|
|
struct base_type *self = zalloc(sizeof(*self));
|
|
|
|
|
|
|
|
if (self != NULL) {
|
|
|
|
tag__init(&self->tag, DW_TAG_base_type, id, type,
|
|
|
|
decl_file, decl_line);
|
|
|
|
self->name = strings__add(name);
|
|
|
|
self->size = size;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 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
|
|
|
static size_t enumeration__snprintf(const struct class *self,
|
|
|
|
char *bf, size_t len,
|
|
|
|
const char *suffix, uint8_t ntabs)
|
|
|
|
{
|
|
|
|
struct enumerator *pos;
|
|
|
|
char *s = bf;
|
|
|
|
size_t printed = 0, n;
|
|
|
|
|
|
|
|
if (ntabs >= sizeof(tabs))
|
|
|
|
ntabs = sizeof(tabs) - 1;
|
|
|
|
|
|
|
|
n = snprintf(s, len, "enum%s%s {\n",
|
|
|
|
self->name ? " " : "", self->name ?: "");
|
|
|
|
s += n;
|
|
|
|
len -= n;
|
|
|
|
printed += n;
|
|
|
|
list_for_each_entry(pos, &self->members, tag.node) {
|
|
|
|
n = snprintf(s, len, "%.*s\t%s = %u,\n", ntabs, tabs,
|
|
|
|
pos->name, pos->value);
|
|
|
|
s += n;
|
|
|
|
len -= n;
|
|
|
|
printed += n;
|
|
|
|
}
|
|
|
|
|
|
|
|
n = snprintf(s, len, "%.*s}%s%s;", ntabs, tabs,
|
|
|
|
suffix ? " " : "", suffix ?: "");
|
|
|
|
return printed + n;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void enumeration__print(const struct class *self, const char *suffix,
|
|
|
|
uint8_t ntabs)
|
|
|
|
{
|
|
|
|
char bf[4096];
|
|
|
|
|
|
|
|
if (ntabs >= sizeof(tabs))
|
|
|
|
ntabs = sizeof(tabs) - 1;
|
|
|
|
|
|
|
|
printf("%.*s/* %s:%u */\n", ntabs, tabs,
|
|
|
|
self->tag.decl_file, self->tag.decl_line);
|
|
|
|
enumeration__snprintf(self, bf, sizeof(bf), suffix, ntabs);
|
|
|
|
printf("%s\n", bf);
|
|
|
|
}
|
|
|
|
|
2006-12-24 15:18:14 +01:00
|
|
|
static struct enumerator *enumerator__new(Dwarf_Off id, Dwarf_Off type,
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
const char *decl_file,
|
|
|
|
uint32_t decl_line,
|
|
|
|
const char *name, uint32_t value)
|
|
|
|
{
|
|
|
|
struct enumerator *self = zalloc(sizeof(*self));
|
|
|
|
|
|
|
|
if (self != NULL) {
|
|
|
|
tag__init(&self->tag, DW_TAG_enumerator,
|
|
|
|
id, type, decl_file, decl_line);
|
|
|
|
|
|
|
|
self->name = strings__add(name);
|
|
|
|
self->value = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2006-12-24 15:07:41 +01:00
|
|
|
static struct variable *variable__new(const char *name, Dwarf_Off id,
|
2006-12-24 15:18:14 +01:00
|
|
|
Dwarf_Off type,
|
2006-11-18 14:54:02 +01:00
|
|
|
const char *decl_file,
|
|
|
|
uint32_t decl_line,
|
2006-12-28 12:38:40 +01:00
|
|
|
Dwarf_Off abstract_origin)
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
{
|
|
|
|
struct variable *self = malloc(sizeof(*self));
|
|
|
|
|
|
|
|
if (self != NULL) {
|
2006-11-18 14:54:02 +01:00
|
|
|
tag__init(&self->tag, DW_TAG_variable, id, type,
|
|
|
|
decl_file, decl_line);
|
[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
|
|
|
self->name = strings__add(name);
|
|
|
|
self->abstract_origin = abstract_origin;
|
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2006-12-26 23:44:03 +01:00
|
|
|
static size_t union__snprintf(const struct class *self,
|
|
|
|
char *bf, size_t len,
|
|
|
|
const char *suffix, uint8_t ntabs)
|
|
|
|
{
|
|
|
|
char class_name[4096];
|
|
|
|
char member_name[128];
|
|
|
|
struct class_member *pos;
|
|
|
|
char *s = bf;
|
|
|
|
size_t printed = 0, n;
|
|
|
|
|
|
|
|
if (ntabs >= sizeof(tabs))
|
|
|
|
ntabs = sizeof(tabs) - 1;
|
|
|
|
|
|
|
|
n = snprintf(s, len, "union%s%s {\n",
|
|
|
|
self->name ? " " : "", self->name ?: "");
|
|
|
|
s += n;
|
|
|
|
len -= n;
|
|
|
|
printed += n;
|
|
|
|
list_for_each_entry(pos, &self->members, tag.node) {
|
|
|
|
const size_t size = class_member__names(NULL, pos, class_name,
|
|
|
|
sizeof(class_name),
|
|
|
|
member_name,
|
|
|
|
sizeof(member_name));
|
|
|
|
n = snprintf(s, len, "%.*s\t%-18s %-21s /* %11u */\n",
|
|
|
|
ntabs, tabs, class_name, member_name, size);
|
|
|
|
s += n;
|
|
|
|
len -= n;
|
|
|
|
printed += n;
|
|
|
|
}
|
|
|
|
|
|
|
|
n = snprintf(s, len, "%.*s}%s%s;", ntabs, tabs,
|
|
|
|
suffix ? " " : "", suffix ?: "");
|
|
|
|
return printed + n;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void union__print(const struct class *self, const char *suffix,
|
|
|
|
uint8_t ntabs)
|
|
|
|
{
|
|
|
|
struct enumerator *pos;
|
|
|
|
char bf[4096];
|
|
|
|
|
|
|
|
if (ntabs >= sizeof(tabs))
|
|
|
|
ntabs = sizeof(tabs) - 1;
|
|
|
|
|
|
|
|
printf("%.*s/* %s:%u */\n", ntabs, tabs,
|
|
|
|
self->tag.decl_file, self->tag.decl_line);
|
|
|
|
union__snprintf(self, bf, sizeof(bf), suffix, ntabs);
|
|
|
|
printf("%s\n", bf);
|
|
|
|
}
|
|
|
|
|
2006-11-11 19:31:04 +01:00
|
|
|
static void cus__add(struct cus *self, struct cu *cu)
|
2006-10-31 20:12:42 +01:00
|
|
|
{
|
2006-11-11 19:31:04 +01:00
|
|
|
list_add_tail(&cu->node, &self->cus);
|
2006-10-31 20:12:42 +01:00
|
|
|
}
|
|
|
|
|
2006-12-29 19:34:11 +01:00
|
|
|
static struct cu *cu__new(uint32_t cu, const char *name, uint8_t addr_size)
|
2006-10-31 20:12:42 +01:00
|
|
|
{
|
|
|
|
struct cu *self = malloc(sizeof(*self));
|
|
|
|
|
2006-11-03 18:38:43 +01:00
|
|
|
if (self != NULL) {
|
2006-10-31 20:12:42 +01:00
|
|
|
INIT_LIST_HEAD(&self->classes);
|
2006-11-18 17:33:48 +01:00
|
|
|
INIT_LIST_HEAD(&self->functions);
|
[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
|
|
|
INIT_LIST_HEAD(&self->variables);
|
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
|
|
|
{
|
2006-12-29 18:28:58 +01:00
|
|
|
list_add_tail(&tag->node, &self->classes);
|
2006-10-31 20:12:42 +01:00
|
|
|
}
|
2006-10-28 23:22:42 +02:00
|
|
|
|
2006-11-18 17:33:48 +01:00
|
|
|
static void cu__add_function(struct cu *self, struct function *function)
|
|
|
|
{
|
|
|
|
function->cu = self;
|
2006-12-30 19:34:20 +01:00
|
|
|
list_add_tail(&function->proto.tag.node, &self->functions);
|
2006-11-18 17:33:48 +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
|
|
|
static void cu__add_variable(struct cu *self, struct variable *variable)
|
|
|
|
{
|
2006-11-12 20:33:37 +01:00
|
|
|
variable->cu = self;
|
[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
|
|
|
list_add_tail(&variable->cu_node, &self->variables);
|
|
|
|
}
|
|
|
|
|
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 " *";
|
|
|
|
}
|
|
|
|
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
struct tag *cu__find_tag_by_id(const struct cu *self, const Dwarf_Off id)
|
2006-12-20 17:10:07 +01:00
|
|
|
{
|
2006-12-29 18:28:58 +01:00
|
|
|
struct tag *pos;
|
2006-12-20 17:10:07 +01:00
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
if (id == 0)
|
|
|
|
return NULL;
|
2006-12-20 17:10:07 +01:00
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
list_for_each_entry(pos, &self->classes, node)
|
|
|
|
if (pos->id == id)
|
|
|
|
return pos;
|
2006-12-20 17:10:07 +01:00
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
return NULL;
|
2006-12-20 17:10:07 +01:00
|
|
|
}
|
|
|
|
|
2006-11-13 03:31:48 +01:00
|
|
|
struct class *cu__find_class_by_name(const struct cu *self, const char *name)
|
2006-10-28 23:22:42 +02:00
|
|
|
{
|
2006-12-29 18:28:58 +01:00
|
|
|
struct tag *pos;
|
2006-10-28 23:22:42 +02:00
|
|
|
|
2006-11-11 19:31:04 +01:00
|
|
|
if (name == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
list_for_each_entry(pos, &self->classes, node) {
|
2006-12-29 23:58:03 +01:00
|
|
|
struct class *class;
|
|
|
|
|
|
|
|
if (pos->tag != DW_TAG_structure_type)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
class = tag__class(pos);
|
|
|
|
if (class->name != NULL && strcmp(class->name, name) == 0)
|
|
|
|
return class;
|
2006-12-29 18:28:58 +01:00
|
|
|
}
|
2006-10-28 23:22:42 +02:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2006-11-13 03:31:48 +01:00
|
|
|
struct class *cus__find_class_by_name(const struct cus *self, const char *name)
|
2006-10-28 23:22:42 +02:00
|
|
|
{
|
2006-11-12 20:33:37 +01:00
|
|
|
struct cu *pos;
|
2006-10-28 23:22:42 +02:00
|
|
|
|
2006-11-12 20:33:37 +01:00
|
|
|
list_for_each_entry(pos, &self->cus, node) {
|
|
|
|
struct class *class = cu__find_class_by_name(pos, name);
|
2006-10-31 21:23:16 +01:00
|
|
|
|
2006-11-12 20:33:37 +01:00
|
|
|
if (class != NULL)
|
2006-10-31 21:23:16 +01:00
|
|
|
return class;
|
|
|
|
}
|
2006-10-31 20:12:42 +01:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2006-12-23 21:46:05 +01:00
|
|
|
struct function *cus__find_function_by_name(const struct cus *self,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
struct cu *pos;
|
|
|
|
|
|
|
|
list_for_each_entry(pos, &self->cus, node) {
|
|
|
|
struct function *function = cu__find_function_by_name(pos, name);
|
|
|
|
|
|
|
|
if (function != NULL)
|
|
|
|
return function;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2006-12-23 21:53:25 +01:00
|
|
|
struct class *cus__find_definition(const struct cus *self, const char *name)
|
|
|
|
{
|
|
|
|
struct class *pos;
|
|
|
|
|
2006-12-24 01:35:38 +01:00
|
|
|
if (name == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2006-12-27 17:39:37 +01:00
|
|
|
list_for_each_entry(pos, self->definitions, node)
|
2006-12-24 01:35:38 +01:00
|
|
|
if (pos->name != NULL && strcmp(pos->name, name) == 0)
|
2006-12-23 21:53:25 +01:00
|
|
|
return pos;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct class *cus__find_fwd_decl(const struct cus *self, const char *name)
|
|
|
|
{
|
|
|
|
struct class *pos;
|
|
|
|
|
2006-12-27 17:39:37 +01:00
|
|
|
list_for_each_entry(pos, self->fwd_decls, node)
|
2006-12-23 21:53:25 +01:00
|
|
|
if (strcmp(pos->name, name) == 0)
|
|
|
|
return pos;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void cus__add_definition(struct cus *self, struct class *class)
|
|
|
|
{
|
2006-12-24 00:44:55 +01:00
|
|
|
class->visited = 1;
|
2006-12-24 01:28:40 +01:00
|
|
|
if (!list_empty(&class->node))
|
|
|
|
list_del(&class->node);
|
2006-12-27 17:39:37 +01:00
|
|
|
list_add_tail(&class->node, self->definitions);
|
2006-12-23 21:53:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void cus__add_fwd_decl(struct cus *self, struct class *class)
|
|
|
|
{
|
2006-12-24 00:44:55 +01:00
|
|
|
class->fwd_decl_emitted = 1;
|
2006-12-24 01:28:40 +01:00
|
|
|
if (list_empty(&class->node))
|
2006-12-27 17:39:37 +01:00
|
|
|
list_add_tail(&class->node, self->fwd_decls);
|
2006-12-23 21:53:25 +01:00
|
|
|
}
|
|
|
|
|
2006-11-18 17:33:48 +01:00
|
|
|
struct function *cu__find_function_by_name(const struct cu *self,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
struct function *pos;
|
|
|
|
|
|
|
|
if (name == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2006-12-30 19:34:20 +01:00
|
|
|
list_for_each_entry(pos, &self->functions, proto.tag.node)
|
2006-11-18 17:33:48 +01:00
|
|
|
if (pos->name != NULL && strcmp(pos->name, name) == 0)
|
|
|
|
return pos;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct function *cu__find_function_by_id(const struct cu *self,
|
2006-12-24 15:07:41 +01:00
|
|
|
const Dwarf_Off id)
|
2006-11-18 17:33:48 +01:00
|
|
|
{
|
|
|
|
struct function *pos;
|
|
|
|
|
2006-12-30 19:34:20 +01:00
|
|
|
list_for_each_entry(pos, &self->functions, proto.tag.node)
|
|
|
|
if (pos->proto.tag.id == id)
|
2006-11-18 17:33:48 +01:00
|
|
|
return pos;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2006-12-24 15:07:41 +01:00
|
|
|
struct variable *cu__find_variable_by_id(const struct cu *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
|
|
|
{
|
|
|
|
struct variable *pos;
|
|
|
|
|
|
|
|
list_for_each_entry(pos, &self->variables, cu_node)
|
2006-11-18 14:54:02 +01:00
|
|
|
if (pos->tag.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;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
int tag__is_struct(const struct tag *self, struct tag **typedef_alias,
|
|
|
|
const struct cu *cu)
|
2006-11-05 05:17:19 +01:00
|
|
|
{
|
|
|
|
*typedef_alias = NULL;
|
2006-12-29 18:28:58 +01:00
|
|
|
if (self->tag == DW_TAG_typedef) {
|
|
|
|
*typedef_alias = cu__find_tag_by_id(cu, self->type);
|
2006-11-05 05:17:19 +01:00
|
|
|
if (*typedef_alias == NULL)
|
|
|
|
return 0;
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
return (*typedef_alias)->tag == DW_TAG_structure_type;
|
2006-11-05 05:17:19 +01:00
|
|
|
}
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
return self->tag == DW_TAG_structure_type;
|
2006-11-05 05:17:19 +01:00
|
|
|
}
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
static size_t array_type__nr_entries(const struct array_type *self)
|
2006-12-08 15:58:46 +01:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
size_t nr_entries = 1;
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
for (i = 0; i < self->dimensions; ++i)
|
|
|
|
nr_entries *= self->nr_entries[i];
|
2006-12-08 15:58:46 +01:00
|
|
|
|
|
|
|
return nr_entries;
|
|
|
|
}
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
static 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) {
|
|
|
|
case DW_TAG_pointer_type: return cu->addr_size;
|
|
|
|
case DW_TAG_base_type: return tag__base_type(self)->size;
|
|
|
|
}
|
2006-12-29 19:34:11 +01:00
|
|
|
|
2006-12-29 23:58:03 +01:00
|
|
|
if (self->type == 0) /* struct class: enums, unions, structs */
|
2006-12-29 18:28:58 +01:00
|
|
|
size = tag__class(self)->size;
|
2006-12-29 19:34:11 +01:00
|
|
|
else {
|
|
|
|
const struct tag *type = cu__find_tag_by_id(cu, self->type);
|
|
|
|
|
|
|
|
assert(type != NULL);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
char tmpbf[128];
|
|
|
|
|
2006-12-19 12:20:52 +01:00
|
|
|
if (self == NULL)
|
|
|
|
strncpy(bf, "void", len);
|
2006-12-29 23:58:03 +01:00
|
|
|
else if (self->tag == DW_TAG_base_type)
|
|
|
|
strncpy(bf, tag__base_type(self)->name, len);
|
2006-12-29 18:28:58 +01:00
|
|
|
else if (self->tag == DW_TAG_pointer_type) {
|
|
|
|
if (self->type == 0) /* No type == void */
|
2006-10-28 23:22:42 +02:00
|
|
|
strncpy(bf, "void *", len);
|
|
|
|
else {
|
2006-12-29 18:28:58 +01:00
|
|
|
type = cu__find_tag_by_id(cu, self->type);
|
|
|
|
snprintf(bf, len, "%s *", tag__name(type, cu, tmpbf,
|
|
|
|
sizeof(tmpbf)));
|
2006-10-28 23:22:42 +02:00
|
|
|
}
|
2006-12-29 18:28:58 +01:00
|
|
|
} else if (self->tag == DW_TAG_volatile_type ||
|
|
|
|
self->tag == DW_TAG_const_type) {
|
|
|
|
type = cu__find_tag_by_id(cu, self->type);
|
2006-12-19 12:20:52 +01:00
|
|
|
snprintf(bf, len, "%s %s ",
|
2006-12-29 18:28:58 +01:00
|
|
|
self->tag == DW_TAG_volatile_type ? "volatile" :
|
|
|
|
"const",
|
|
|
|
tag__name(type, cu, tmpbf, sizeof(tmpbf)));
|
|
|
|
} else if (self->tag == DW_TAG_array_type) {
|
|
|
|
type = cu__find_tag_by_id(cu, self->type);
|
|
|
|
return tag__name(type, cu, bf, len);
|
2006-10-28 23:22:42 +02:00
|
|
|
} else
|
2006-12-29 18:28:58 +01:00
|
|
|
snprintf(bf, len, "%s%s", tag__prefix(cu, self->tag),
|
|
|
|
tag__class(self)->name ?: "");
|
2006-10-28 23:22:42 +02:00
|
|
|
return bf;
|
|
|
|
}
|
|
|
|
|
2006-11-20 18:43:39 +01:00
|
|
|
const char *variable__type_name(const struct variable *self,
|
|
|
|
char *bf, size_t len)
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
{
|
2006-11-18 14:54:02 +01:00
|
|
|
if (self->tag.type != 0) {
|
2006-12-29 18:28:58 +01:00
|
|
|
struct tag *tag = cu__find_tag_by_id(self->cu, self->tag.type);
|
|
|
|
return tag__name(tag, self->cu, bf, len);
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
} else if (self->abstract_origin != 0) {
|
|
|
|
struct variable *var;
|
|
|
|
|
2006-11-18 14:54:02 +01:00
|
|
|
var = cu__find_variable_by_id(self->cu,
|
|
|
|
self->abstract_origin);
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
if (var != NULL)
|
2006-11-12 20:33:37 +01:00
|
|
|
return variable__type_name(var, bf, len);
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2006-11-20 18:43:39 +01:00
|
|
|
const char *variable__name(const struct variable *self)
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
{
|
|
|
|
if (self->name == NULL) {
|
|
|
|
if (self->abstract_origin == 0)
|
|
|
|
return NULL;
|
|
|
|
else {
|
|
|
|
struct variable *var;
|
|
|
|
|
2006-11-18 14:54:02 +01:00
|
|
|
var = cu__find_variable_by_id(self->cu,
|
|
|
|
self->abstract_origin);
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
return var == NULL ? NULL : var->name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return self->name;
|
|
|
|
}
|
|
|
|
|
2006-12-24 15:07:41 +01:00
|
|
|
static struct class_member *class_member__new(Dwarf_Off id,
|
2006-12-07 23:00:45 +01:00
|
|
|
uint16_t tag,
|
2006-12-24 15:18:14 +01:00
|
|
|
Dwarf_Off type,
|
2006-11-18 14:54:02 +01:00
|
|
|
const char *decl_file,
|
|
|
|
uint32_t decl_line,
|
2006-10-28 23:22:42 +02:00
|
|
|
const char *name,
|
2006-12-28 13:09:18 +01:00
|
|
|
Dwarf_Off offset,
|
2006-12-25 01:27:22 +01:00
|
|
|
size_t bit_size,
|
2006-12-28 13:09:18 +01:00
|
|
|
uint8_t bit_offset)
|
2006-10-28 23:22:42 +02:00
|
|
|
{
|
|
|
|
struct class_member *self = zalloc(sizeof(*self));
|
|
|
|
|
2006-12-28 13:10:07 +01:00
|
|
|
/* Be paranoid */
|
|
|
|
assert(offset == (typeof(self->offset))offset);
|
|
|
|
assert(bit_size == (typeof(self->bit_size))bit_size);
|
|
|
|
|
2006-10-28 23:22:42 +02:00
|
|
|
if (self != NULL) {
|
2006-12-07 23:00:45 +01:00
|
|
|
tag__init(&self->tag, tag, id, type,
|
2006-11-18 17:33:48 +01:00
|
|
|
decl_file, decl_line);
|
2006-10-28 23:22:42 +02:00
|
|
|
self->offset = offset;
|
|
|
|
self->bit_size = bit_size;
|
|
|
|
self->bit_offset = bit_offset;
|
2006-11-04 21:37:23 +01:00
|
|
|
self->name = strings__add(name);
|
2006-10-28 23:22:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2006-12-25 01:27:22 +01:00
|
|
|
static size_t class_member__size(const struct class_member *self)
|
2006-10-28 23:22:42 +02:00
|
|
|
{
|
2006-12-29 18:28:58 +01:00
|
|
|
struct tag *type = cu__find_tag_by_id(self->class->cu, self->tag.type);
|
|
|
|
assert(type != NULL);
|
|
|
|
return tag__size(type, self->class->cu);
|
2006-10-28 23:22:42 +02:00
|
|
|
}
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
const char *tag__subroutine_mask(const struct tag *self,
|
|
|
|
const struct cu *cu,
|
|
|
|
char *bf, size_t len, int is_pointer)
|
2006-12-23 23:39:24 +01:00
|
|
|
{
|
|
|
|
char ret_type_name[128];
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
if (self->type == 0)
|
2006-12-23 23:39:24 +01:00
|
|
|
snprintf(ret_type_name, sizeof(ret_type_name), "void");
|
|
|
|
else {
|
2006-12-29 18:28:58 +01:00
|
|
|
struct tag *ret_type = cu__find_tag_by_id(cu, self->type);
|
|
|
|
tag__name(ret_type, cu, ret_type_name, sizeof(ret_type_name));
|
2006-12-23 23:39:24 +01:00
|
|
|
}
|
2006-12-24 17:00:16 +01:00
|
|
|
snprintf(bf, len, "%s (%s%%s)(void /* FIXME: add parm list */)",
|
|
|
|
ret_type_name, is_pointer ? "*" : "");
|
2006-12-23 23:39:24 +01:00
|
|
|
return bf;
|
|
|
|
}
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
size_t class_member__names(const struct tag *type,
|
2006-12-25 01:27:22 +01:00
|
|
|
const struct class_member *self,
|
|
|
|
char *class_name, size_t class_name_size,
|
|
|
|
char *member_name, size_t member_name_size)
|
2006-10-28 23:22:42 +02:00
|
|
|
{
|
2006-12-25 01:27:22 +01:00
|
|
|
size_t size = -1;
|
2006-10-28 23:22:42 +02:00
|
|
|
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
if (type == NULL)
|
2006-12-29 18:28:58 +01:00
|
|
|
type = cu__find_tag_by_id(self->class->cu, self->tag.type);
|
[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
|
|
|
snprintf(member_name, member_name_size, "%s;", self->name ?: "");
|
2006-10-28 23:22:42 +02:00
|
|
|
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
if (type == NULL)
|
[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
|
|
|
snprintf(class_name, class_name_size, "<%llx>",
|
2006-11-18 14:54:02 +01:00
|
|
|
self->tag.type);
|
2006-10-28 23:22:42 +02:00
|
|
|
else {
|
2006-12-29 18:28:58 +01:00
|
|
|
if (type->tag == DW_TAG_const_type)
|
|
|
|
type = cu__find_tag_by_id(self->class->cu, type->type);
|
|
|
|
size = tag__size(type, self->class->cu);
|
2006-10-28 23:22:42 +02:00
|
|
|
|
|
|
|
/* Is it a function pointer? */
|
2006-12-29 18:28:58 +01:00
|
|
|
if (type->tag == DW_TAG_pointer_type) {
|
|
|
|
struct tag *ptype =
|
|
|
|
cu__find_tag_by_id(self->class->cu, type->type);
|
2006-10-28 23:22:42 +02:00
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
if (ptype != NULL &&
|
|
|
|
ptype->tag == DW_TAG_subroutine_type) {
|
2006-10-28 23:22:42 +02:00
|
|
|
/* function has no return value (void) */
|
2006-12-29 18:28:58 +01:00
|
|
|
if (ptype->type == 0)
|
[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
|
|
|
snprintf(class_name,
|
|
|
|
class_name_size, "void");
|
2006-10-28 23:22:42 +02:00
|
|
|
else {
|
2006-12-29 18:28:58 +01:00
|
|
|
struct tag *ret_type =
|
|
|
|
cu__find_tag_by_id(self->class->cu,
|
|
|
|
ptype->type);
|
2006-10-28 23:22:42 +02:00
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
tag__name(ret_type, self->class->cu,
|
|
|
|
class_name,
|
|
|
|
class_name_size);
|
2006-10-28 23:22:42 +02:00
|
|
|
}
|
[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
|
|
|
snprintf(member_name, member_name_size,
|
2006-12-24 17:06:48 +01:00
|
|
|
"(*%s)(void /* FIXME: add parm list */);",
|
|
|
|
self->name ?: "");
|
2006-10-28 23:22:42 +02:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
tag__name(type, self->class->cu, class_name, class_name_size);
|
|
|
|
if (type->tag == DW_TAG_array_type) {
|
|
|
|
struct array_type *array = tag__array_type(type);
|
2006-12-08 15:58:46 +01:00
|
|
|
int i = 0;
|
|
|
|
size_t n = snprintf(member_name, member_name_size,
|
|
|
|
"%s", self->name);
|
|
|
|
member_name += n;
|
|
|
|
member_name_size -= n;
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
for (i = 0; i < array->dimensions; ++i) {
|
2006-12-08 15:58:46 +01:00
|
|
|
n = snprintf(member_name, member_name_size,
|
2006-12-29 18:28:58 +01:00
|
|
|
"[%u]", array->nr_entries[i]);
|
2006-12-08 15:58:46 +01:00
|
|
|
member_name += n;
|
|
|
|
member_name_size -= n;
|
|
|
|
}
|
|
|
|
strncat(member_name, ";", member_name_size);
|
|
|
|
} else if (self->bit_size != 0)
|
[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
|
|
|
snprintf(member_name, member_name_size,
|
2006-11-02 17:48:35 +01:00
|
|
|
"%s:%d;", self->name ?: "",
|
|
|
|
self->bit_size);
|
2006-10-28 23:22:42 +02:00
|
|
|
}
|
|
|
|
out:
|
[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 size;
|
|
|
|
}
|
|
|
|
|
2006-12-30 19:34:20 +01:00
|
|
|
size_t parameter__names(const struct parameter *self, const struct cu *cu,
|
2006-12-20 23:40:13 +01:00
|
|
|
char *class_name, size_t class_name_size,
|
|
|
|
char *parameter_name, size_t parameter_name_size)
|
|
|
|
{
|
2006-12-30 19:34:20 +01:00
|
|
|
struct tag *type = cu__find_tag_by_id(cu, self->tag.type);
|
2006-12-20 23:40:13 +01:00
|
|
|
size_t size = -1;
|
|
|
|
|
|
|
|
snprintf(parameter_name, parameter_name_size, "%s", self->name ?: "");
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
if (type == NULL)
|
2006-12-20 23:40:13 +01:00
|
|
|
snprintf(class_name, class_name_size, "<%llx>",
|
|
|
|
self->tag.type);
|
|
|
|
else {
|
2006-12-29 18:28:58 +01:00
|
|
|
if (type->tag == DW_TAG_const_type)
|
2006-12-30 19:34:20 +01:00
|
|
|
type = cu__find_tag_by_id(cu, type->type);
|
|
|
|
size = tag__size(type, cu);
|
2006-12-20 23:40:13 +01:00
|
|
|
|
|
|
|
/* Is it a function pointer? */
|
2006-12-29 18:28:58 +01:00
|
|
|
if (type->tag == DW_TAG_pointer_type) {
|
2006-12-30 19:34:20 +01:00
|
|
|
struct tag *ptype = cu__find_tag_by_id(cu, type->type);
|
2006-12-20 23:40:13 +01:00
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
if (ptype != NULL &&
|
|
|
|
ptype->tag == DW_TAG_subroutine_type) {
|
2006-12-20 23:40:13 +01:00
|
|
|
/* function has no return value (void) */
|
2006-12-29 18:28:58 +01:00
|
|
|
if (ptype->type == 0)
|
2006-12-20 23:40:13 +01:00
|
|
|
snprintf(class_name,
|
|
|
|
class_name_size, "void");
|
|
|
|
else {
|
2006-12-29 18:28:58 +01:00
|
|
|
struct tag *ret_type =
|
2006-12-30 19:34:20 +01:00
|
|
|
cu__find_tag_by_id(cu, ptype->type);
|
2006-12-20 23:40:13 +01:00
|
|
|
|
2006-12-30 19:34:20 +01:00
|
|
|
tag__name(ret_type, cu,
|
2006-12-29 18:28:58 +01:00
|
|
|
class_name, class_name_size);
|
2006-12-20 23:40:13 +01:00
|
|
|
}
|
|
|
|
snprintf(parameter_name, parameter_name_size,
|
|
|
|
"(*%s)(void /* FIXME: add "
|
|
|
|
"parameter list */)",
|
|
|
|
self->name ?: "");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-30 19:34:20 +01:00
|
|
|
tag__name(type, cu, class_name, class_name_size);
|
2006-12-29 18:28:58 +01:00
|
|
|
if (type->tag == DW_TAG_array_type) {
|
|
|
|
struct array_type *array = tag__array_type(type);
|
2006-12-20 23:40:13 +01:00
|
|
|
int i = 0;
|
|
|
|
size_t n = snprintf(parameter_name,
|
|
|
|
parameter_name_size,
|
|
|
|
"%s", self->name);
|
|
|
|
parameter_name += n;
|
|
|
|
parameter_name_size -= n;
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
for (i = 0; i < array->dimensions; ++i) {
|
2006-12-20 23:40:13 +01:00
|
|
|
n = snprintf(parameter_name,
|
|
|
|
parameter_name_size, "[%u]",
|
2006-12-29 18:28:58 +01:00
|
|
|
array->nr_entries[i]);
|
2006-12-20 23:40:13 +01:00
|
|
|
parameter_name += n;
|
|
|
|
parameter_name_size -= n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
out:
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2006-12-25 01:27:22 +01:00
|
|
|
static size_t class_member__print(struct class_member *self)
|
[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
|
|
|
{
|
2006-12-25 01:27:22 +01:00
|
|
|
size_t size;
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
char class_name[4096];
|
[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
|
|
|
char member_name[128];
|
2006-12-29 18:28:58 +01:00
|
|
|
struct tag *type = cu__find_tag_by_id(self->class->cu, self->tag.type);
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
|
|
|
|
assert(type != NULL);
|
2006-12-29 18:28:58 +01:00
|
|
|
if (type->tag == DW_TAG_enumeration_type) {
|
|
|
|
const struct class *ctype = tag__class(type);
|
|
|
|
size = ctype->size;
|
[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
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
if (ctype->name != NULL) {
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
snprintf(class_name, sizeof(class_name), "enum %s",
|
2006-12-29 18:28:58 +01:00
|
|
|
ctype->name);
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
snprintf(member_name, sizeof(member_name), "%s;",
|
|
|
|
self->name);
|
|
|
|
} else {
|
|
|
|
const size_t spacing = 45 - strlen(self->name);
|
2006-12-29 18:28:58 +01:00
|
|
|
enumeration__snprintf(ctype, class_name,
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
sizeof(class_name),
|
|
|
|
self->name, 1);
|
|
|
|
|
2006-12-28 13:09:18 +01:00
|
|
|
printf("%s %*.*s/* %5u %5u */",
|
[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
|
|
|
class_name, spacing, spacing, " ",
|
2006-12-26 23:44:03 +01:00
|
|
|
self->offset, size);
|
|
|
|
goto out;
|
|
|
|
}
|
2006-12-29 18:28:58 +01:00
|
|
|
} else if (type->tag == DW_TAG_union_type) {
|
|
|
|
const struct class *ctype = tag__class(type);
|
|
|
|
size = ctype->size;
|
2006-12-26 23:44:03 +01:00
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
if (ctype->name != NULL) {
|
2006-12-26 23:44:03 +01:00
|
|
|
snprintf(class_name, sizeof(class_name), "union %s",
|
2006-12-29 18:28:58 +01:00
|
|
|
ctype->name);
|
2006-12-26 23:44:03 +01:00
|
|
|
snprintf(member_name, sizeof(member_name), "%s;",
|
|
|
|
self->name);
|
|
|
|
} else {
|
|
|
|
const size_t spacing = 45 - (self->name ?
|
|
|
|
strlen(self->name) : -1);
|
2006-12-29 18:28:58 +01:00
|
|
|
union__snprintf(ctype, class_name, sizeof(class_name),
|
2006-12-26 23:44:03 +01:00
|
|
|
self->name, 1);
|
2006-12-28 13:09:18 +01:00
|
|
|
printf("%s %*.*s/* %5u %5u */",
|
2006-12-26 23:44:03 +01:00
|
|
|
class_name, spacing, spacing, " ",
|
[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->offset, size);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
size = class_member__names(type, self, class_name,
|
|
|
|
sizeof(class_name),
|
|
|
|
member_name, sizeof(member_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
|
|
|
|
2006-12-07 23:00:45 +01:00
|
|
|
if (self->tag.tag == DW_TAG_inheritance) {
|
|
|
|
snprintf(member_name, sizeof(member_name),
|
|
|
|
"/* ancestor class */");
|
|
|
|
strncat(class_name, ";", sizeof(class_name));
|
|
|
|
}
|
|
|
|
|
2006-12-28 13:09:18 +01:00
|
|
|
printf("%-26s %-21s /* %5u %5u */",
|
[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
|
|
|
class_name, member_name, self->offset, size);
|
[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
|
|
|
out:
|
2006-10-28 23:22:42 +02:00
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2006-12-24 15:18:14 +01:00
|
|
|
static struct parameter *parameter__new(Dwarf_Off id, Dwarf_Off type,
|
2006-11-18 17:33:48 +01:00
|
|
|
const char *decl_file,
|
|
|
|
uint32_t decl_line,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
struct parameter *self = zalloc(sizeof(*self));
|
|
|
|
|
|
|
|
if (self != NULL) {
|
|
|
|
tag__init(&self->tag, DW_TAG_formal_parameter, id, type,
|
|
|
|
decl_file, decl_line);
|
|
|
|
self->name = strings__add(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2006-12-24 15:07:41 +01:00
|
|
|
static struct inline_expansion *inline_expansion__new(Dwarf_Off id,
|
2006-12-24 15:18:14 +01:00
|
|
|
Dwarf_Off type,
|
2006-11-18 14:54:02 +01:00
|
|
|
const char *decl_file,
|
|
|
|
uint32_t decl_line,
|
2006-12-26 14:44:05 +01:00
|
|
|
size_t size,
|
|
|
|
Dwarf_Addr low_pc,
|
|
|
|
Dwarf_Addr high_pc)
|
2006-11-03 16:41:19 +01:00
|
|
|
{
|
|
|
|
struct inline_expansion *self = zalloc(sizeof(*self));
|
|
|
|
|
|
|
|
if (self != NULL) {
|
2006-11-18 14:54:02 +01:00
|
|
|
tag__init(&self->tag, DW_TAG_inlined_subroutine, id, type,
|
|
|
|
decl_file, decl_line);
|
2006-12-26 14:44:05 +01:00
|
|
|
self->size = size;
|
|
|
|
self->low_pc = low_pc;
|
|
|
|
self->high_pc = high_pc;
|
2006-11-03 16:41:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2006-12-24 15:18:14 +01:00
|
|
|
static struct label *label__new(Dwarf_Off id, Dwarf_Off type,
|
2006-11-20 19:17:42 +01:00
|
|
|
const char *decl_file, uint32_t decl_line,
|
2006-12-28 12:36:39 +01:00
|
|
|
const char *name, Dwarf_Addr low_pc)
|
2006-11-20 19:17:42 +01:00
|
|
|
{
|
|
|
|
struct label *self = malloc(sizeof(*self));
|
|
|
|
|
|
|
|
if (self != NULL) {
|
|
|
|
tag__init(&self->tag, DW_TAG_label, id, type,
|
|
|
|
decl_file, decl_line);
|
|
|
|
self->name = strings__add(name);
|
|
|
|
self->low_pc = low_pc;
|
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
static struct array_type *array_type__new(Dwarf_Off id, Dwarf_Off type,
|
|
|
|
const char *decl_file,
|
|
|
|
uint32_t decl_line)
|
|
|
|
{
|
|
|
|
struct array_type *self = zalloc(sizeof(*self));
|
|
|
|
|
|
|
|
if (self != NULL)
|
|
|
|
tag__init(&self->tag, DW_TAG_array_type, id, type,
|
|
|
|
decl_file, decl_line);
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2006-12-28 14:18:43 +01:00
|
|
|
static struct class *class__new(const uint32_t tag,
|
2006-12-24 15:18:14 +01:00
|
|
|
Dwarf_Off id, Dwarf_Off type,
|
2006-12-25 01:27:22 +01:00
|
|
|
const char *name, size_t size,
|
2006-12-28 14:18:43 +01:00
|
|
|
const char *decl_file, uint32_t decl_line,
|
|
|
|
uint8_t declaration)
|
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
|
|
|
|
|
|
|
if (self != NULL) {
|
2006-11-18 14:54:02 +01:00
|
|
|
tag__init(&self->tag, tag, id, type, decl_file, decl_line);
|
2006-10-28 23:22:42 +02:00
|
|
|
INIT_LIST_HEAD(&self->members);
|
2006-12-24 01:28:40 +01:00
|
|
|
INIT_LIST_HEAD(&self->node);
|
2006-11-18 17:33:48 +01:00
|
|
|
self->size = size;
|
|
|
|
self->name = strings__add(name);
|
2006-12-07 23:54:45 +01:00
|
|
|
self->declaration = declaration;
|
2006-10-28 23:22:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void class__add_member(struct class *self, struct class_member *member)
|
|
|
|
{
|
2006-11-01 14:34:42 +01:00
|
|
|
++self->nr_members;
|
2006-11-12 20:52:03 +01:00
|
|
|
member->class = self;
|
2006-11-18 14:54:02 +01:00
|
|
|
list_add_tail(&member->tag.node, &self->members);
|
2006-10-28 23:22:42 +02:00
|
|
|
}
|
|
|
|
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
static void enumeration__add(struct class *self,
|
|
|
|
struct enumerator *enumerator)
|
|
|
|
{
|
|
|
|
++self->nr_members;
|
|
|
|
list_add_tail(&enumerator->tag.node, &self->members);
|
|
|
|
}
|
|
|
|
|
2006-11-20 19:54:39 +01:00
|
|
|
static void lexblock__init(struct lexblock *self)
|
|
|
|
{
|
|
|
|
INIT_LIST_HEAD(&self->labels);
|
|
|
|
INIT_LIST_HEAD(&self->variables);
|
|
|
|
INIT_LIST_HEAD(&self->inline_expansions);
|
|
|
|
|
|
|
|
self->nr_labels =
|
|
|
|
self->nr_variables =
|
|
|
|
self->nr_inline_expansions = 0;
|
|
|
|
}
|
|
|
|
|
2006-12-30 19:34:20 +01:00
|
|
|
static ftype__init(struct ftype *self, uint16_t tag,
|
|
|
|
Dwarf_Off id, Dwarf_Off type,
|
|
|
|
const char *decl_file, uint32_t decl_line)
|
|
|
|
{
|
|
|
|
assert(tag == DW_TAG_subprogram || tag == DW_TAG_subroutine_type);
|
|
|
|
|
|
|
|
tag__init(&self->tag, tag, id, type, decl_file, decl_line);
|
|
|
|
INIT_LIST_HEAD(&self->parms);
|
|
|
|
}
|
|
|
|
|
2006-12-24 15:18:14 +01:00
|
|
|
static struct function *function__new(Dwarf_Off id, Dwarf_Off type,
|
2006-11-18 17:33:48 +01:00
|
|
|
const char *decl_file,
|
2006-12-28 14:18:43 +01:00
|
|
|
uint32_t decl_line, const char *name,
|
|
|
|
uint16_t inlined, char external,
|
2006-12-28 12:36:39 +01:00
|
|
|
Dwarf_Addr low_pc, Dwarf_Addr high_pc)
|
2006-11-18 17:33:48 +01:00
|
|
|
{
|
|
|
|
struct function *self = zalloc(sizeof(*self));
|
|
|
|
|
|
|
|
if (self != NULL) {
|
2006-12-30 19:34:20 +01:00
|
|
|
ftype__init(&self->proto, DW_TAG_subprogram, id, type,
|
|
|
|
decl_file, decl_line);
|
2006-11-20 19:54:39 +01:00
|
|
|
lexblock__init(&self->lexblock);
|
2006-11-18 17:33:48 +01:00
|
|
|
self->name = strings__add(name);
|
|
|
|
self->inlined = inlined;
|
|
|
|
self->external = external;
|
|
|
|
self->low_pc = low_pc;
|
|
|
|
self->high_pc = high_pc;
|
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2006-12-30 19:34:20 +01:00
|
|
|
int ftype__has_parm_of_type(const struct ftype *self, const struct tag *target,
|
|
|
|
const struct cu *cu)
|
2006-12-20 15:03:12 +01:00
|
|
|
{
|
2006-12-30 19:34:20 +01:00
|
|
|
struct parameter *pos;
|
2006-12-20 15:03:12 +01:00
|
|
|
|
2006-12-30 19:34:20 +01:00
|
|
|
list_for_each_entry(pos, &self->parms, tag.node) {
|
|
|
|
struct tag *type = cu__find_tag_by_id(cu, pos->tag.type);
|
2006-12-20 15:03:12 +01:00
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
if (type != NULL && type->tag == DW_TAG_pointer_type) {
|
2006-12-30 19:34:20 +01:00
|
|
|
type = cu__find_tag_by_id(cu, type->type);
|
2006-12-29 18:28:58 +01:00
|
|
|
if (type != NULL && type->id == target->id)
|
2006-12-20 15:03:12 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-12-30 19:34:20 +01:00
|
|
|
static void ftype__add_parameter(struct ftype *self, struct parameter *parm)
|
2006-11-18 17:33:48 +01:00
|
|
|
{
|
2006-12-30 19:34:20 +01:00
|
|
|
++self->nr_parms;
|
|
|
|
list_add_tail(&parm->tag.node, &self->parms);
|
2006-11-18 17:33:48 +01:00
|
|
|
}
|
|
|
|
|
2006-11-20 19:51:42 +01:00
|
|
|
static void lexblock__add_inline_expansion(struct lexblock *self,
|
2006-11-18 17:33:48 +01:00
|
|
|
struct inline_expansion *exp)
|
2006-11-03 16:41:19 +01:00
|
|
|
{
|
2006-11-20 19:51:42 +01:00
|
|
|
++self->nr_inline_expansions;
|
2006-11-03 16:41:19 +01:00
|
|
|
self->size_inline_expansions += exp->size;
|
2006-11-20 19:51:42 +01:00
|
|
|
list_add_tail(&exp->tag.node, &self->inline_expansions);
|
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;
|
|
|
|
list_add_tail(&var->tag.node, &self->variables);
|
[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;
|
|
|
|
list_add_tail(&label->tag.node, &self->labels);
|
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;
|
|
|
|
|
|
|
|
list_for_each_entry(pos, &self->members, tag.node)
|
|
|
|
if (pos == trailer)
|
|
|
|
break;
|
|
|
|
else if (pos->hole >= byte_hole_size ||
|
|
|
|
pos->bit_hole >= bit_hole_size)
|
|
|
|
return pos;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2006-11-12 20:33:37 +01:00
|
|
|
void class__find_holes(struct class *self)
|
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
|
|
|
|
2006-11-18 14:54:02 +01:00
|
|
|
list_for_each_entry(pos, &self->members, tag.node) {
|
2006-12-14 16:18:07 +01:00
|
|
|
if (last != NULL) {
|
2006-12-25 01:27:22 +01:00
|
|
|
const ssize_t cc_last_size = pos->offset - last->offset;
|
2006-12-14 16:18:07 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If the offset is the same this better be a bitfield
|
|
|
|
* or an empty struct (see rwlock_t in the Linux kernel
|
|
|
|
* sources when compiled for UP) or...
|
|
|
|
*/
|
|
|
|
if (cc_last_size > 0) {
|
2006-12-14 19:49:06 +01:00
|
|
|
/*
|
|
|
|
* Check if the DWARF byte_size info is smaller
|
|
|
|
* than the size used by the compiler, i.e.
|
|
|
|
* when combining small bitfields with the next
|
|
|
|
* member.
|
|
|
|
*/
|
|
|
|
if (cc_last_size < last_size)
|
|
|
|
last_size = cc_last_size;
|
|
|
|
|
2006-12-14 16:18:07 +01:00
|
|
|
last->hole = cc_last_size - last_size;
|
|
|
|
if (last->hole > 0)
|
|
|
|
++self->nr_holes;
|
2006-10-28 23:22:42 +02:00
|
|
|
|
2006-12-14 16:13:14 +01:00
|
|
|
if (bit_sum != 0) {
|
|
|
|
last->bit_hole = (last_size * 8) -
|
|
|
|
bit_sum;
|
|
|
|
if (last->bit_hole != 0)
|
|
|
|
++self->nr_bit_holes;
|
[CLASSES]: Find bit holes
An example is worth a thousand words, look for "XXX ... bit hole, try to pack"
and the stats at the bottom:
[acme@newtoy net-2.6]$ pahole ../OUTPUT/qemu/net-2.6/fs/inode.o task_struct
/* include2/asm/system.h:11 */
struct task_struct {
volatile long int state; /* 0 4 */
struct thread_info * thread_info; /* 4 4 */
atomic_t usage; /* 8 4 */
long unsigned int flags; /* 12 4 */
long unsigned int ptrace; /* 16 4 */
int lock_depth; /* 20 4 */
int load_weight; /* 24 4 */
int prio; /* 28 4 */
/* --- cacheline 1 boundary (32 bytes) --- */
int static_prio; /* 32 4 */
int normal_prio; /* 36 4 */
struct list_head run_list; /* 40 8 */
struct prio_array * array; /* 48 4 */
short unsigned int ioprio; /* 52 2 */
/* XXX 2 bytes hole, try to pack */
long unsigned int sleep_avg; /* 56 4 */
long long unsigned int timestamp; /* 60 8 */
/* --- cacheline 2 boundary (64 bytes) was 4 bytes ago --- */
long long unsigned int last_ran; /* 68 8 */
long long unsigned int sched_time; /* 76 8 */
enum sleep_type sleep_type; /* 84 4 */
long unsigned int policy; /* 88 4 */
cpumask_t cpus_allowed; /* 92 4 */
/* --- cacheline 3 boundary (96 bytes) --- */
unsigned int time_slice; /* 96 4 */
unsigned int first_time_slice; /* 100 4 */
struct list_head tasks; /* 104 8 */
struct list_head ptrace_children; /* 112 8 */
struct list_head ptrace_list; /* 120 8 */
/* --- cacheline 4 boundary (128 bytes) --- */
struct mm_struct * mm; /* 128 4 */
struct mm_struct * active_mm; /* 132 4 */
struct linux_binfmt * binfmt; /* 136 4 */
long int exit_state; /* 140 4 */
int exit_code; /* 144 4 */
int exit_signal; /* 148 4 */
int pdeath_signal; /* 152 4 */
long unsigned int personality; /* 156 4 */
/* --- cacheline 5 boundary (160 bytes) --- */
unsigned int did_exec:1; /* 160 4 */
/* XXX 31 bits hole, try to pack */
pid_t pid; /* 164 4 */
pid_t tgid; /* 168 4 */
struct task_struct * real_parent; /* 172 4 */
struct task_struct * parent; /* 176 4 */
struct list_head children; /* 180 8 */
struct list_head sibling; /* 188 8 */
/* --- cacheline 6 boundary (192 bytes) was 4 bytes ago --- */
struct task_struct * group_leader; /* 196 4 */
struct pid_link pids[3]; /* 200 36 */
/* --- cacheline 7 boundary (224 bytes) was 12 bytes ago --- */
struct list_head thread_group; /* 236 8 */
struct completion * vfork_done; /* 244 4 */
int * set_child_tid; /* 248 4 */
int * clear_child_tid; /* 252 4 */
/* --- cacheline 8 boundary (256 bytes) --- */
long unsigned int rt_priority; /* 256 4 */
cputime_t utime; /* 260 4 */
cputime_t stime; /* 264 4 */
long unsigned int nvcsw; /* 268 4 */
long unsigned int nivcsw; /* 272 4 */
struct timespec start_time; /* 276 8 */
long unsigned int min_flt; /* 284 4 */
/* --- cacheline 9 boundary (288 bytes) --- */
long unsigned int maj_flt; /* 288 4 */
cputime_t it_prof_expires; /* 292 4 */
cputime_t it_virt_expires; /* 296 4 */
long long unsigned int it_sched_expires; /* 300 8 */
struct list_head cpu_timers[3]; /* 308 24 */
/* --- cacheline 10 boundary (320 bytes) was 12 bytes ago --- */
uid_t uid; /* 332 4 */
uid_t euid; /* 336 4 */
uid_t suid; /* 340 4 */
uid_t fsuid; /* 344 4 */
gid_t gid; /* 348 4 */
/* --- cacheline 11 boundary (352 bytes) --- */
gid_t egid; /* 352 4 */
gid_t sgid; /* 356 4 */
gid_t fsgid; /* 360 4 */
struct group_info * group_info; /* 364 4 */
kernel_cap_t cap_effective; /* 368 4 */
kernel_cap_t cap_inheritable; /* 372 4 */
kernel_cap_t cap_permitted; /* 376 4 */
unsigned int keep_capabilities:1; /* 380 4 */
/* XXX 31 bits hole, try to pack */
/* --- cacheline 12 boundary (384 bytes) --- */
struct user_struct * user; /* 384 4 */
struct key * request_key_auth; /* 388 4 */
struct key * thread_keyring; /* 392 4 */
unsigned char jit_keyring; /* 396 1 */
unsigned char fpu_counter; /* 397 1 */
/* XXX 2 bytes hole, try to pack */
int oomkilladj; /* 400 4 */
char comm[16]; /* 404 16 */
/* --- cacheline 13 boundary (416 bytes) was 4 bytes ago --- */
int link_count; /* 420 4 */
int total_link_count; /* 424 4 */
struct sysv_sem sysvsem; /* 428 4 */
struct thread_struct thread; /* 432 656 */
/* --- cacheline 34 boundary (1088 bytes) --- */
struct fs_struct * fs; /* 1088 4 */
struct files_struct * files; /* 1092 4 */
struct nsproxy * nsproxy; /* 1096 4 */
struct signal_struct * signal; /* 1100 4 */
struct sighand_struct * sighand; /* 1104 4 */
sigset_t blocked; /* 1108 8 */
sigset_t real_blocked; /* 1116 8 */
/* --- cacheline 35 boundary (1120 bytes) was 4 bytes ago --- */
sigset_t saved_sigmask; /* 1124 8 */
struct sigpending pending; /* 1132 16 */
long unsigned int sas_ss_sp; /* 1148 4 */
/* --- cacheline 36 boundary (1152 bytes) --- */
size_t sas_ss_size; /* 1152 4 */
int (*notifier)(); /* 1156 4 */
void * notifier_data; /* 1160 4 */
sigset_t * notifier_mask; /* 1164 4 */
void * security; /* 1168 4 */
struct audit_context * audit_context; /* 1172 4 */
seccomp_t seccomp; /* 1176 0 */
u32 parent_exec_id; /* 1176 4 */
u32 self_exec_id; /* 1180 4 */
/* --- cacheline 37 boundary (1184 bytes) --- */
spinlock_t alloc_lock; /* 1184 40 */
/* --- cacheline 38 boundary (1216 bytes) was 8 bytes ago --- */
spinlock_t pi_lock; /* 1224 40 */
/* --- cacheline 39 boundary (1248 bytes) was 16 bytes ago --- */
struct plist_head pi_waiters; /* 1264 20 */
/* --- cacheline 40 boundary (1280 bytes) was 4 bytes ago --- */
struct rt_mutex_waiter * pi_blocked_on; /* 1284 4 */
struct mutex_waiter * blocked_on; /* 1288 4 */
unsigned int irq_events; /* 1292 4 */
int hardirqs_enabled; /* 1296 4 */
long unsigned int hardirq_enable_ip; /* 1300 4 */
unsigned int hardirq_enable_event; /* 1304 4 */
long unsigned int hardirq_disable_ip; /* 1308 4 */
/* --- cacheline 41 boundary (1312 bytes) --- */
unsigned int hardirq_disable_event; /* 1312 4 */
int softirqs_enabled; /* 1316 4 */
long unsigned int softirq_disable_ip; /* 1320 4 */
unsigned int softirq_disable_event; /* 1324 4 */
long unsigned int softirq_enable_ip; /* 1328 4 */
unsigned int softirq_enable_event; /* 1332 4 */
int hardirq_context; /* 1336 4 */
int softirq_context; /* 1340 4 */
/* --- cacheline 42 boundary (1344 bytes) --- */
u64 curr_chain_key; /* 1344 8 */
int lockdep_depth; /* 1352 4 */
struct held_lock held_locks[30]; /* 1356 1200 */
/* --- cacheline 79 boundary (2528 bytes) was 28 bytes ago --- */
unsigned int lockdep_recursion; /* 2556 4 */
/* --- cacheline 80 boundary (2560 bytes) --- */
void * journal_info; /* 2560 4 */
struct reclaim_state * reclaim_state; /* 2564 4 */
struct backing_dev_info * backing_dev_info; /* 2568 4 */
struct io_context * io_context; /* 2572 4 */
long unsigned int ptrace_message; /* 2576 4 */
siginfo_t * last_siginfo; /* 2580 4 */
wait_queue_t * io_wait; /* 2584 4 */
u64 rchar; /* 2588 8 */
/* --- cacheline 81 boundary (2592 bytes) was 4 bytes ago --- */
u64 wchar; /* 2596 8 */
u64 syscr; /* 2604 8 */
u64 syscw; /* 2612 8 */
struct robust_list_head * robust_list; /* 2620 4 */
/* --- cacheline 82 boundary (2624 bytes) --- */
struct list_head pi_state_list; /* 2624 8 */
struct futex_pi_state * pi_state_cache; /* 2632 4 */
atomic_t fs_excl; /* 2636 4 */
struct rcu_head rcu; /* 2640 8 */
struct pipe_inode_info * splice_pipe; /* 2648 4 */
}; /* size: 2656, cachelines: 83 */
/* sum members: 2648, holes: 2, sum holes: 4 */
/* bit holes: 2, sum bit holes: 62 bits */
/* padding: 4 */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-07 15:26:50 +01:00
|
|
|
|
2006-12-14 16:13:14 +01:00
|
|
|
bit_sum = 0;
|
|
|
|
}
|
2006-12-14 16:18:07 +01:00
|
|
|
}
|
|
|
|
}
|
[CLASSES]: Find bit holes
An example is worth a thousand words, look for "XXX ... bit hole, try to pack"
and the stats at the bottom:
[acme@newtoy net-2.6]$ pahole ../OUTPUT/qemu/net-2.6/fs/inode.o task_struct
/* include2/asm/system.h:11 */
struct task_struct {
volatile long int state; /* 0 4 */
struct thread_info * thread_info; /* 4 4 */
atomic_t usage; /* 8 4 */
long unsigned int flags; /* 12 4 */
long unsigned int ptrace; /* 16 4 */
int lock_depth; /* 20 4 */
int load_weight; /* 24 4 */
int prio; /* 28 4 */
/* --- cacheline 1 boundary (32 bytes) --- */
int static_prio; /* 32 4 */
int normal_prio; /* 36 4 */
struct list_head run_list; /* 40 8 */
struct prio_array * array; /* 48 4 */
short unsigned int ioprio; /* 52 2 */
/* XXX 2 bytes hole, try to pack */
long unsigned int sleep_avg; /* 56 4 */
long long unsigned int timestamp; /* 60 8 */
/* --- cacheline 2 boundary (64 bytes) was 4 bytes ago --- */
long long unsigned int last_ran; /* 68 8 */
long long unsigned int sched_time; /* 76 8 */
enum sleep_type sleep_type; /* 84 4 */
long unsigned int policy; /* 88 4 */
cpumask_t cpus_allowed; /* 92 4 */
/* --- cacheline 3 boundary (96 bytes) --- */
unsigned int time_slice; /* 96 4 */
unsigned int first_time_slice; /* 100 4 */
struct list_head tasks; /* 104 8 */
struct list_head ptrace_children; /* 112 8 */
struct list_head ptrace_list; /* 120 8 */
/* --- cacheline 4 boundary (128 bytes) --- */
struct mm_struct * mm; /* 128 4 */
struct mm_struct * active_mm; /* 132 4 */
struct linux_binfmt * binfmt; /* 136 4 */
long int exit_state; /* 140 4 */
int exit_code; /* 144 4 */
int exit_signal; /* 148 4 */
int pdeath_signal; /* 152 4 */
long unsigned int personality; /* 156 4 */
/* --- cacheline 5 boundary (160 bytes) --- */
unsigned int did_exec:1; /* 160 4 */
/* XXX 31 bits hole, try to pack */
pid_t pid; /* 164 4 */
pid_t tgid; /* 168 4 */
struct task_struct * real_parent; /* 172 4 */
struct task_struct * parent; /* 176 4 */
struct list_head children; /* 180 8 */
struct list_head sibling; /* 188 8 */
/* --- cacheline 6 boundary (192 bytes) was 4 bytes ago --- */
struct task_struct * group_leader; /* 196 4 */
struct pid_link pids[3]; /* 200 36 */
/* --- cacheline 7 boundary (224 bytes) was 12 bytes ago --- */
struct list_head thread_group; /* 236 8 */
struct completion * vfork_done; /* 244 4 */
int * set_child_tid; /* 248 4 */
int * clear_child_tid; /* 252 4 */
/* --- cacheline 8 boundary (256 bytes) --- */
long unsigned int rt_priority; /* 256 4 */
cputime_t utime; /* 260 4 */
cputime_t stime; /* 264 4 */
long unsigned int nvcsw; /* 268 4 */
long unsigned int nivcsw; /* 272 4 */
struct timespec start_time; /* 276 8 */
long unsigned int min_flt; /* 284 4 */
/* --- cacheline 9 boundary (288 bytes) --- */
long unsigned int maj_flt; /* 288 4 */
cputime_t it_prof_expires; /* 292 4 */
cputime_t it_virt_expires; /* 296 4 */
long long unsigned int it_sched_expires; /* 300 8 */
struct list_head cpu_timers[3]; /* 308 24 */
/* --- cacheline 10 boundary (320 bytes) was 12 bytes ago --- */
uid_t uid; /* 332 4 */
uid_t euid; /* 336 4 */
uid_t suid; /* 340 4 */
uid_t fsuid; /* 344 4 */
gid_t gid; /* 348 4 */
/* --- cacheline 11 boundary (352 bytes) --- */
gid_t egid; /* 352 4 */
gid_t sgid; /* 356 4 */
gid_t fsgid; /* 360 4 */
struct group_info * group_info; /* 364 4 */
kernel_cap_t cap_effective; /* 368 4 */
kernel_cap_t cap_inheritable; /* 372 4 */
kernel_cap_t cap_permitted; /* 376 4 */
unsigned int keep_capabilities:1; /* 380 4 */
/* XXX 31 bits hole, try to pack */
/* --- cacheline 12 boundary (384 bytes) --- */
struct user_struct * user; /* 384 4 */
struct key * request_key_auth; /* 388 4 */
struct key * thread_keyring; /* 392 4 */
unsigned char jit_keyring; /* 396 1 */
unsigned char fpu_counter; /* 397 1 */
/* XXX 2 bytes hole, try to pack */
int oomkilladj; /* 400 4 */
char comm[16]; /* 404 16 */
/* --- cacheline 13 boundary (416 bytes) was 4 bytes ago --- */
int link_count; /* 420 4 */
int total_link_count; /* 424 4 */
struct sysv_sem sysvsem; /* 428 4 */
struct thread_struct thread; /* 432 656 */
/* --- cacheline 34 boundary (1088 bytes) --- */
struct fs_struct * fs; /* 1088 4 */
struct files_struct * files; /* 1092 4 */
struct nsproxy * nsproxy; /* 1096 4 */
struct signal_struct * signal; /* 1100 4 */
struct sighand_struct * sighand; /* 1104 4 */
sigset_t blocked; /* 1108 8 */
sigset_t real_blocked; /* 1116 8 */
/* --- cacheline 35 boundary (1120 bytes) was 4 bytes ago --- */
sigset_t saved_sigmask; /* 1124 8 */
struct sigpending pending; /* 1132 16 */
long unsigned int sas_ss_sp; /* 1148 4 */
/* --- cacheline 36 boundary (1152 bytes) --- */
size_t sas_ss_size; /* 1152 4 */
int (*notifier)(); /* 1156 4 */
void * notifier_data; /* 1160 4 */
sigset_t * notifier_mask; /* 1164 4 */
void * security; /* 1168 4 */
struct audit_context * audit_context; /* 1172 4 */
seccomp_t seccomp; /* 1176 0 */
u32 parent_exec_id; /* 1176 4 */
u32 self_exec_id; /* 1180 4 */
/* --- cacheline 37 boundary (1184 bytes) --- */
spinlock_t alloc_lock; /* 1184 40 */
/* --- cacheline 38 boundary (1216 bytes) was 8 bytes ago --- */
spinlock_t pi_lock; /* 1224 40 */
/* --- cacheline 39 boundary (1248 bytes) was 16 bytes ago --- */
struct plist_head pi_waiters; /* 1264 20 */
/* --- cacheline 40 boundary (1280 bytes) was 4 bytes ago --- */
struct rt_mutex_waiter * pi_blocked_on; /* 1284 4 */
struct mutex_waiter * blocked_on; /* 1288 4 */
unsigned int irq_events; /* 1292 4 */
int hardirqs_enabled; /* 1296 4 */
long unsigned int hardirq_enable_ip; /* 1300 4 */
unsigned int hardirq_enable_event; /* 1304 4 */
long unsigned int hardirq_disable_ip; /* 1308 4 */
/* --- cacheline 41 boundary (1312 bytes) --- */
unsigned int hardirq_disable_event; /* 1312 4 */
int softirqs_enabled; /* 1316 4 */
long unsigned int softirq_disable_ip; /* 1320 4 */
unsigned int softirq_disable_event; /* 1324 4 */
long unsigned int softirq_enable_ip; /* 1328 4 */
unsigned int softirq_enable_event; /* 1332 4 */
int hardirq_context; /* 1336 4 */
int softirq_context; /* 1340 4 */
/* --- cacheline 42 boundary (1344 bytes) --- */
u64 curr_chain_key; /* 1344 8 */
int lockdep_depth; /* 1352 4 */
struct held_lock held_locks[30]; /* 1356 1200 */
/* --- cacheline 79 boundary (2528 bytes) was 28 bytes ago --- */
unsigned int lockdep_recursion; /* 2556 4 */
/* --- cacheline 80 boundary (2560 bytes) --- */
void * journal_info; /* 2560 4 */
struct reclaim_state * reclaim_state; /* 2564 4 */
struct backing_dev_info * backing_dev_info; /* 2568 4 */
struct io_context * io_context; /* 2572 4 */
long unsigned int ptrace_message; /* 2576 4 */
siginfo_t * last_siginfo; /* 2580 4 */
wait_queue_t * io_wait; /* 2584 4 */
u64 rchar; /* 2588 8 */
/* --- cacheline 81 boundary (2592 bytes) was 4 bytes ago --- */
u64 wchar; /* 2596 8 */
u64 syscr; /* 2604 8 */
u64 syscw; /* 2612 8 */
struct robust_list_head * robust_list; /* 2620 4 */
/* --- cacheline 82 boundary (2624 bytes) --- */
struct list_head pi_state_list; /* 2624 8 */
struct futex_pi_state * pi_state_cache; /* 2632 4 */
atomic_t fs_excl; /* 2636 4 */
struct rcu_head rcu; /* 2640 8 */
struct pipe_inode_info * splice_pipe; /* 2648 4 */
}; /* size: 2656, cachelines: 83 */
/* sum members: 2648, holes: 2, sum holes: 4 */
/* bit holes: 2, sum bit holes: 62 bits */
/* padding: 4 */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-07 15:26:50 +01:00
|
|
|
|
2006-12-14 16:13:14 +01:00
|
|
|
bit_sum += pos->bit_size;
|
2006-12-14 16:18:07 +01:00
|
|
|
size = class_member__size(pos);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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) {
|
|
|
|
if (last->offset + last_size != self->size)
|
|
|
|
self->padding = self->size - (last->offset + last_size);
|
|
|
|
if (last->bit_size != 0)
|
|
|
|
self->bit_padding = (last_size * 8) - bit_sum;
|
|
|
|
}
|
2006-10-28 23:22:42 +02:00
|
|
|
}
|
|
|
|
|
[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
|
|
|
struct class_member *class__find_member_by_name(const struct class *self,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
struct class_member *pos;
|
|
|
|
|
2006-11-12 18:43:28 +01:00
|
|
|
if (name == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2006-11-18 14:54:02 +01:00
|
|
|
list_for_each_entry(pos, &self->members, tag.node)
|
[CODIFF]: Detect and print all sorts of changes in structs
[acme@newtoy examples]$ cat struct.c
static struct foo {
char a:2;
unsigned int b;
unsigned long c;
unsigned long d;
unsigned long e;
} bar;
int main(int argc, char *argv[])
{
printf("%d", bar.a);
}
[acme@newtoy examples]$
Then change "a:2" to "a:4":
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
1 struct changed
Now, on top of that move a after b:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 4(4) 1(4) */
b;
from: unsigned int /* 4(0) 4(0) */
to: unsigned int /* 0(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Move it back a to before b and change the type of e without changing its size,
i.e. from unsigned long to long:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 16(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Now on top of this lets delete the c member:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | -4
nr_members: -1
-long unsigned int c; /* 8 4 */
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
d;
from: long unsigned int /* 12(0) 4(0) */
to: long unsigned int /* 8(0) 4(0) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 12(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
WOW, many changes, what an ABI breakage, no? :-)
It started as:
[acme@newtoy examples]$ pahole old_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:2; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int c; /* 8 4 */
long unsigned int d; /* 12 4 */
long unsigned int e; /* 16 4 */
}; /* size: 20, sum members: 17, holes: 1, sum holes: 3 */
And ended up as:
[acme@newtoy examples]$ pahole new_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:4; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int d; /* 8 4 */
long int e; /* 12 4 */
}; /* size: 16, sum members: 13, holes: 1, sum holes: 3 */
[acme@newtoy examples]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 18:07:21 +01:00
|
|
|
if (pos->name != NULL && strcmp(pos->name, name) == 0)
|
|
|
|
return pos;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2006-11-18 17:33:48 +01:00
|
|
|
static void function__account_inline_expansions(struct function *self)
|
[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-18 17:33:48 +01:00
|
|
|
struct function *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
|
|
|
struct inline_expansion *pos;
|
|
|
|
|
2006-11-20 19:38:47 +01:00
|
|
|
if (self->lexblock.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;
|
|
|
|
|
2006-11-20 19:38:47 +01:00
|
|
|
list_for_each_entry(pos, &self->lexblock.inline_expansions, tag.node) {
|
2006-11-18 17:33:48 +01:00
|
|
|
type = cu__find_function_by_id(self->cu, pos->tag.type);
|
|
|
|
if (type != NULL) {
|
|
|
|
type->cu_total_nr_inline_expansions++;
|
|
|
|
type->cu_total_size_inline_expansions += 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)
|
|
|
|
{
|
2006-11-18 17:33:48 +01:00
|
|
|
struct function *pos;
|
2006-11-03 18:38:43 +01:00
|
|
|
|
2006-12-30 19:34:20 +01:00
|
|
|
list_for_each_entry(pos, &self->functions, proto.tag.node) {
|
2006-11-18 17:33:48 +01:00
|
|
|
function__account_inline_expansions(pos);
|
2006-11-20 19:38:47 +01:00
|
|
|
self->nr_inline_expansions += pos->lexblock.nr_inline_expansions;
|
2006-11-20 19:51:42 +01:00
|
|
|
self->size_inline_expansions += pos->lexblock.size_inline_expansions;
|
2006-11-03 18:38:43 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-11-20 18:43:39 +01:00
|
|
|
static int tags__compare(const void *a, const void *b)
|
2006-11-03 16:41:19 +01:00
|
|
|
{
|
2006-11-20 18:43:39 +01:00
|
|
|
const struct tag *ta = a, *tb = b;
|
2006-11-03 16:41:19 +01:00
|
|
|
|
2006-11-20 18:43:39 +01:00
|
|
|
if (a == b)
|
|
|
|
return 0;
|
|
|
|
if (ta->decl_line < tb->decl_line)
|
2006-12-14 16:18:07 +01:00
|
|
|
return -1;
|
2006-11-20 18:43:39 +01:00
|
|
|
if (ta->decl_line > tb->decl_line)
|
|
|
|
return 1;
|
|
|
|
if (ta->tag == DW_TAG_inlined_subroutine)
|
|
|
|
return -1;
|
|
|
|
return 1;
|
|
|
|
}
|
2006-11-03 16:41:19 +01:00
|
|
|
|
2006-11-20 18:43:39 +01:00
|
|
|
static void tags__free(void *a)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void tags__add(void *tags, const struct tag *tag)
|
|
|
|
{
|
|
|
|
tsearch(tag, tags, tags__compare);
|
|
|
|
}
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
static void function__tag_print(const struct tag *tag)
|
2006-11-20 18:43:39 +01:00
|
|
|
{
|
|
|
|
char bf[512];
|
|
|
|
const void *vtag = tag;
|
2006-11-20 19:17:42 +01:00
|
|
|
int c = 8;
|
2006-11-20 18:43:39 +01:00
|
|
|
|
|
|
|
switch (tag->tag) {
|
|
|
|
case DW_TAG_inlined_subroutine: {
|
|
|
|
const struct inline_expansion *exp = vtag;
|
2006-11-18 23:30:45 +01:00
|
|
|
const struct function *alias =
|
2006-11-20 18:43:39 +01:00
|
|
|
cu__find_function_by_id(exp->function->cu,
|
|
|
|
exp->tag.type);
|
2006-11-20 19:17:42 +01:00
|
|
|
|
2006-12-26 14:44:05 +01:00
|
|
|
assert(alias != NULL);
|
2006-11-20 19:17:42 +01:00
|
|
|
fputs(" ", stdout);
|
2006-12-26 14:44:05 +01:00
|
|
|
c += printf("%s(); /* low_pc=%#llx */",
|
|
|
|
alias->name, exp->low_pc);
|
2006-11-20 18:43:39 +01:00
|
|
|
}
|
|
|
|
break;
|
2006-11-20 19:17:42 +01:00
|
|
|
case DW_TAG_variable:
|
|
|
|
fputs(" ", stdout);
|
|
|
|
c += printf("%s %s;", variable__type_name(vtag, bf, sizeof(bf)),
|
|
|
|
variable__name(vtag));
|
|
|
|
break;
|
|
|
|
case DW_TAG_label: {
|
|
|
|
const struct label *label = vtag;
|
|
|
|
putchar('\n');
|
|
|
|
c = printf("%s:", label->name);
|
2006-11-03 16:41:19 +01:00
|
|
|
}
|
2006-11-20 18:43:39 +01:00
|
|
|
break;
|
|
|
|
default:
|
2006-11-20 19:17:42 +01:00
|
|
|
fputs(" ", stdout);
|
|
|
|
c += printf("%s <%llx>", dwarf_tag_name(tag->tag), tag->id);
|
2006-11-20 18:43:39 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2006-11-20 19:17:42 +01:00
|
|
|
printf("%-*.*s// %5u\n", 70 - c, 70 - c, " ", tag->decl_line);
|
2006-11-03 16:41:19 +01:00
|
|
|
}
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
static void function__tags_action(const void *nodep, const VISIT which,
|
|
|
|
const int depth)
|
[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 18:43:39 +01:00
|
|
|
if (which == postorder || which == leaf) {
|
|
|
|
const struct tag *tag = *(struct tag **)nodep;
|
2006-12-29 18:28:58 +01:00
|
|
|
function__tag_print(tag);
|
2006-11-20 18:43:39 +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
|
|
|
|
2006-11-20 18:43:39 +01:00
|
|
|
static void function__print_body(const struct function *self,
|
|
|
|
const int show_variables,
|
2006-11-20 19:17:42 +01:00
|
|
|
const int show_inline_expansions,
|
|
|
|
const int show_labels)
|
2006-11-20 18:43:39 +01:00
|
|
|
{
|
|
|
|
void *tags = NULL;
|
|
|
|
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
|
|
|
|
2006-11-20 18:43:39 +01:00
|
|
|
if (show_variables)
|
2006-11-20 19:38:47 +01:00
|
|
|
list_for_each_entry(pos, &self->lexblock.variables, node) {
|
2006-11-20 18:43:39 +01:00
|
|
|
/* FIXME! this test shouln't be needed at all */
|
2006-12-30 19:34:20 +01:00
|
|
|
if (pos->decl_line >= self->proto.tag.decl_line)
|
2006-11-20 18:43:39 +01:00
|
|
|
tags__add(&tags, pos);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (show_inline_expansions)
|
2006-11-20 19:38:47 +01:00
|
|
|
list_for_each_entry(pos, &self->lexblock.inline_expansions, node) {
|
2006-11-20 18:43:39 +01:00
|
|
|
/* FIXME! this test shouln't be needed at all */
|
2006-12-30 19:34:20 +01:00
|
|
|
if (pos->decl_line >= self->proto.tag.decl_line)
|
2006-11-20 18:43:39 +01:00
|
|
|
tags__add(&tags, pos);
|
|
|
|
}
|
|
|
|
|
2006-11-20 19:17:42 +01:00
|
|
|
if (show_labels)
|
2006-11-20 19:38:47 +01:00
|
|
|
list_for_each_entry(pos, &self->lexblock.labels, node) {
|
2006-11-20 19:17:42 +01:00
|
|
|
/* FIXME! this test shouln't be needed at all */
|
2006-12-30 19:34:20 +01:00
|
|
|
if (pos->decl_line >= self->proto.tag.decl_line)
|
2006-11-20 19:17:42 +01:00
|
|
|
tags__add(&tags, pos);
|
|
|
|
}
|
|
|
|
|
2006-11-20 18:43:39 +01:00
|
|
|
puts("{");
|
2006-12-29 18:28:58 +01:00
|
|
|
twalk(tags, function__tags_action);
|
2006-11-20 18:43:39 +01:00
|
|
|
puts("}\n");
|
|
|
|
|
|
|
|
tdestroy(tags, tags__free);
|
[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-12-30 19:34:20 +01:00
|
|
|
static size_t ftype__snprintf(const struct ftype *self, const struct cu *cu,
|
|
|
|
char *bf, const size_t len,
|
|
|
|
const char *name, const uint8_t inlined)
|
|
|
|
{
|
|
|
|
struct parameter *pos;
|
|
|
|
struct tag *type = cu__find_tag_by_id(cu, self->tag.type);
|
|
|
|
int first_parm = 1;
|
|
|
|
char *s = bf, sbf[128];
|
|
|
|
size_t l = len;
|
|
|
|
const char *stype = tag__name(type, cu, sbf, sizeof(sbf));
|
|
|
|
size_t n = snprintf(s, l, "%s%s %s(", inlined ? "inline " : "",
|
|
|
|
stype, name ?: "");
|
|
|
|
s += n; l -= n;
|
|
|
|
|
|
|
|
list_for_each_entry(pos, &self->parms, tag.node) {
|
|
|
|
if (!first_parm) {
|
|
|
|
n = snprintf(s, l, ", ");
|
|
|
|
s += n; l -= n;
|
|
|
|
} else
|
|
|
|
first_parm = 0;
|
|
|
|
type = cu__find_tag_by_id(cu, pos->tag.type);
|
|
|
|
stype = tag__name(type, cu, sbf, sizeof(sbf));
|
|
|
|
n = snprintf(s, l, "%s %s", stype, pos->name);
|
|
|
|
s += n; l -= n;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No parameters? */
|
|
|
|
if (first_parm) {
|
|
|
|
n = snprintf(s, l, "void");
|
|
|
|
s += n; l -= n;
|
|
|
|
}
|
|
|
|
else if (self->unspec_parms) {
|
|
|
|
n = snprintf(s, l, ", ...");
|
|
|
|
s += n; l -= n;
|
|
|
|
}
|
|
|
|
n = snprintf(s, l, ");\n", stdout);
|
|
|
|
return len - l - n;
|
|
|
|
}
|
|
|
|
|
2006-11-20 18:43:39 +01:00
|
|
|
void function__print(const struct function *self, int show_stats,
|
|
|
|
const int show_variables,
|
|
|
|
const int show_inline_expansions)
|
2006-10-28 23:49:27 +02:00
|
|
|
{
|
2006-12-30 19:34:20 +01:00
|
|
|
char bf[2048];
|
2006-12-29 18:28:58 +01:00
|
|
|
struct tag *class_type;
|
2006-10-29 00:04:40 +02:00
|
|
|
const char *type = "<ERROR>";
|
2006-10-28 23:49:27 +02:00
|
|
|
|
2006-12-30 19:34:20 +01:00
|
|
|
printf("/* %s:%u */\n", self->proto.tag.decl_file,
|
|
|
|
self->proto.tag.decl_line);
|
2006-10-28 23:49:27 +02:00
|
|
|
|
2006-12-30 19:34:20 +01:00
|
|
|
ftype__snprintf(&self->proto, self->cu, bf, sizeof(bf), self->name,
|
|
|
|
function__declared_inline(self));
|
|
|
|
fputs(bf, stdout);
|
2006-11-20 18:43:39 +01:00
|
|
|
|
|
|
|
if (show_variables || show_inline_expansions)
|
|
|
|
function__print_body(self, show_variables,
|
2006-11-20 19:17:42 +01:00
|
|
|
show_inline_expansions, 1);
|
2006-11-20 18:43:39 +01:00
|
|
|
|
|
|
|
if (show_stats) {
|
|
|
|
printf("/* size: %llu", self->high_pc - self->low_pc);
|
2006-11-20 19:38:47 +01:00
|
|
|
if (self->lexblock.nr_variables > 0)
|
|
|
|
printf(", variables: %u", self->lexblock.nr_variables);
|
|
|
|
if (self->lexblock.nr_labels > 0)
|
|
|
|
printf(", goto labels: %u", self->lexblock.nr_labels);
|
|
|
|
if (self->lexblock.nr_inline_expansions > 0)
|
2006-11-20 18:43:39 +01:00
|
|
|
printf(", inline expansions: %u (%u bytes)",
|
2006-11-20 19:51:42 +01:00
|
|
|
self->lexblock.nr_inline_expansions,
|
|
|
|
self->lexblock.size_inline_expansions);
|
2006-12-18 18:35:31 +01:00
|
|
|
fputs(" */\n", stdout);
|
2006-11-20 18:43:39 +01:00
|
|
|
}
|
2006-10-28 23:49:27 +02:00
|
|
|
}
|
|
|
|
|
2006-12-07 22:20:46 +01:00
|
|
|
static int class__print_cacheline_boundary(uint32_t last_cacheline,
|
2006-12-14 19:49:06 +01:00
|
|
|
size_t sum, size_t sum_holes,
|
|
|
|
uint8_t *newline)
|
2006-12-07 22:20:46 +01:00
|
|
|
{
|
2006-12-25 01:27:22 +01:00
|
|
|
const size_t real_sum = sum + sum_holes;
|
|
|
|
const size_t cacheline = real_sum / cacheline_size;
|
2006-12-07 22:20:46 +01:00
|
|
|
|
|
|
|
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) {
|
|
|
|
putchar('\n');
|
|
|
|
*newline = 0;
|
|
|
|
}
|
|
|
|
|
2006-12-07 22:20:46 +01:00
|
|
|
if (cacheline_pos == 0)
|
|
|
|
printf(" /* --- cacheline "
|
|
|
|
"%u boundary (%u bytes) --- */\n",
|
|
|
|
cacheline, cacheline_in_bytes);
|
|
|
|
else
|
|
|
|
printf(" /* --- cacheline "
|
|
|
|
"%u boundary (%u bytes) was %u "
|
|
|
|
"bytes ago --- */\n",
|
|
|
|
cacheline, cacheline_in_bytes,
|
|
|
|
cacheline_pos);
|
|
|
|
}
|
|
|
|
|
|
|
|
return cacheline;
|
|
|
|
}
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
static void class__print_struct(const struct tag *tag,
|
2006-12-23 21:09:47 +01:00
|
|
|
const char *prefix, const char *suffix)
|
2006-10-28 23:22:42 +02:00
|
|
|
{
|
2006-12-29 18:28:58 +01:00
|
|
|
struct class *self = tag__class(tag);
|
2006-12-28 14:18:43 +01:00
|
|
|
uint32_t sum = 0;
|
|
|
|
uint32_t sum_holes = 0;
|
2006-10-28 23:22:42 +02:00
|
|
|
struct class_member *pos;
|
2006-12-25 01:27:22 +01:00
|
|
|
size_t last_size = 0, size;
|
2006-12-28 14:18:43 +01:00
|
|
|
uint32_t last_cacheline = 0;
|
2006-12-25 01:27:22 +01:00
|
|
|
size_t last_bit_size = 0;
|
2006-10-28 23:22:42 +02:00
|
|
|
int last_offset = -1;
|
2006-12-14 19:00:28 +01:00
|
|
|
uint8_t newline = 0;
|
2006-12-28 14:18:43 +01:00
|
|
|
uint32_t sum_bit_holes = 0;
|
2006-10-28 23:22:42 +02:00
|
|
|
|
2006-12-24 22:46:52 +01:00
|
|
|
printf("%s%sstruct%s%s {\n", prefix ?: "", prefix ? " " : "",
|
|
|
|
self->name ? " " : "", self->name ?: "");
|
2006-11-18 14:54:02 +01:00
|
|
|
list_for_each_entry(pos, &self->members, tag.node) {
|
2006-12-25 01:27:22 +01:00
|
|
|
const ssize_t cc_last_size = pos->offset - last_offset;
|
2006-12-14 19:49:06 +01:00
|
|
|
|
2006-12-07 22:20:46 +01:00
|
|
|
last_cacheline = class__print_cacheline_boundary(last_cacheline,
|
|
|
|
sum,
|
2006-12-14 19:49:06 +01:00
|
|
|
sum_holes,
|
|
|
|
&newline);
|
|
|
|
|
|
|
|
if (last_offset != -1) {
|
|
|
|
if (cc_last_size < last_size && cc_last_size > 0) {
|
|
|
|
if (!newline++)
|
|
|
|
putchar('\n');
|
|
|
|
printf(" /* Bitfield WARNING: DWARF "
|
2006-12-25 01:27:22 +01:00
|
|
|
"size=%u, real size=%u */\n",
|
2006-12-14 19:49:06 +01:00
|
|
|
last_size, cc_last_size);
|
|
|
|
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) {
|
|
|
|
putchar('\n');
|
|
|
|
newline = 0;
|
|
|
|
}
|
|
|
|
|
2006-12-06 18:00:48 +01:00
|
|
|
fputs(" ", stdout);
|
2006-12-06 18:09:36 +01:00
|
|
|
size = class_member__print(pos);
|
2006-12-07 16:07:22 +01:00
|
|
|
|
|
|
|
if (pos->bit_hole != 0) {
|
2006-12-14 19:00:28 +01:00
|
|
|
if (!newline++)
|
|
|
|
putchar('\n');
|
|
|
|
printf("\n /* XXX %d bit%s hole, "
|
|
|
|
"try to pack */",
|
2006-12-07 16:24:18 +01:00
|
|
|
pos->bit_hole,
|
|
|
|
pos->bit_hole != 1 ? "s" : "");
|
2006-12-07 16:07:22 +01:00
|
|
|
sum_bit_holes += pos->bit_hole;
|
|
|
|
}
|
|
|
|
|
2006-12-06 18:09:36 +01:00
|
|
|
if (pos->hole > 0) {
|
2006-12-14 19:00:28 +01:00
|
|
|
if (!newline++)
|
2006-12-07 16:07:22 +01:00
|
|
|
putchar('\n');
|
2006-12-07 16:24:18 +01:00
|
|
|
printf("\n /* XXX %d byte%s hole, "
|
2006-12-14 19:00:28 +01:00
|
|
|
"try to pack */",
|
2006-12-07 16:24:18 +01:00
|
|
|
pos->hole, 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
|
|
|
|
|
|
|
putchar('\n');
|
2006-12-06 18:09:36 +01:00
|
|
|
/*
|
|
|
|
* check for bitfields, accounting for only the biggest
|
|
|
|
* of the byte_size in the fields in each bitfield set.
|
|
|
|
*/
|
|
|
|
if (last_offset != pos->offset ||
|
|
|
|
pos->bit_size == 0 || last_bit_size == 0) {
|
|
|
|
last_size = size;
|
|
|
|
sum += last_size;
|
|
|
|
} else if (size > last_size) {
|
2006-10-28 23:22:42 +02:00
|
|
|
sum += size - last_size;
|
|
|
|
last_size = size;
|
2006-12-06 18:09:36 +01:00
|
|
|
}
|
2006-10-28 23:22:42 +02:00
|
|
|
|
2006-12-06 18:09:36 +01:00
|
|
|
last_offset = pos->offset;
|
|
|
|
last_bit_size = pos->bit_size;
|
2006-10-28 23:22:42 +02:00
|
|
|
}
|
|
|
|
|
2006-12-14 19:49:06 +01:00
|
|
|
class__print_cacheline_boundary(last_cacheline, sum, sum_holes,
|
|
|
|
&newline);
|
2006-12-07 22:20:46 +01:00
|
|
|
|
2006-12-25 01:27:22 +01:00
|
|
|
printf("}%s%s; /* size: %u, cachelines: %u */\n",
|
2006-12-24 22:46:52 +01:00
|
|
|
suffix ? " ": "", suffix ?: "", self->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
|
|
|
(self->size + cacheline_size - 1) / cacheline_size);
|
2006-10-28 23:22:42 +02:00
|
|
|
if (sum_holes > 0)
|
[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
|
|
|
printf(" /* sum members: %lu, holes: %d, sum holes: %lu */\n",
|
2006-10-28 23:22:42 +02:00
|
|
|
sum, self->nr_holes, sum_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
|
|
|
if (sum_bit_holes > 0)
|
2006-12-07 16:07:22 +01:00
|
|
|
printf(" /* bit holes: %d, sum bit holes: %u bits */\n",
|
[CLASSES]: Find bit holes
An example is worth a thousand words, look for "XXX ... bit hole, try to pack"
and the stats at the bottom:
[acme@newtoy net-2.6]$ pahole ../OUTPUT/qemu/net-2.6/fs/inode.o task_struct
/* include2/asm/system.h:11 */
struct task_struct {
volatile long int state; /* 0 4 */
struct thread_info * thread_info; /* 4 4 */
atomic_t usage; /* 8 4 */
long unsigned int flags; /* 12 4 */
long unsigned int ptrace; /* 16 4 */
int lock_depth; /* 20 4 */
int load_weight; /* 24 4 */
int prio; /* 28 4 */
/* --- cacheline 1 boundary (32 bytes) --- */
int static_prio; /* 32 4 */
int normal_prio; /* 36 4 */
struct list_head run_list; /* 40 8 */
struct prio_array * array; /* 48 4 */
short unsigned int ioprio; /* 52 2 */
/* XXX 2 bytes hole, try to pack */
long unsigned int sleep_avg; /* 56 4 */
long long unsigned int timestamp; /* 60 8 */
/* --- cacheline 2 boundary (64 bytes) was 4 bytes ago --- */
long long unsigned int last_ran; /* 68 8 */
long long unsigned int sched_time; /* 76 8 */
enum sleep_type sleep_type; /* 84 4 */
long unsigned int policy; /* 88 4 */
cpumask_t cpus_allowed; /* 92 4 */
/* --- cacheline 3 boundary (96 bytes) --- */
unsigned int time_slice; /* 96 4 */
unsigned int first_time_slice; /* 100 4 */
struct list_head tasks; /* 104 8 */
struct list_head ptrace_children; /* 112 8 */
struct list_head ptrace_list; /* 120 8 */
/* --- cacheline 4 boundary (128 bytes) --- */
struct mm_struct * mm; /* 128 4 */
struct mm_struct * active_mm; /* 132 4 */
struct linux_binfmt * binfmt; /* 136 4 */
long int exit_state; /* 140 4 */
int exit_code; /* 144 4 */
int exit_signal; /* 148 4 */
int pdeath_signal; /* 152 4 */
long unsigned int personality; /* 156 4 */
/* --- cacheline 5 boundary (160 bytes) --- */
unsigned int did_exec:1; /* 160 4 */
/* XXX 31 bits hole, try to pack */
pid_t pid; /* 164 4 */
pid_t tgid; /* 168 4 */
struct task_struct * real_parent; /* 172 4 */
struct task_struct * parent; /* 176 4 */
struct list_head children; /* 180 8 */
struct list_head sibling; /* 188 8 */
/* --- cacheline 6 boundary (192 bytes) was 4 bytes ago --- */
struct task_struct * group_leader; /* 196 4 */
struct pid_link pids[3]; /* 200 36 */
/* --- cacheline 7 boundary (224 bytes) was 12 bytes ago --- */
struct list_head thread_group; /* 236 8 */
struct completion * vfork_done; /* 244 4 */
int * set_child_tid; /* 248 4 */
int * clear_child_tid; /* 252 4 */
/* --- cacheline 8 boundary (256 bytes) --- */
long unsigned int rt_priority; /* 256 4 */
cputime_t utime; /* 260 4 */
cputime_t stime; /* 264 4 */
long unsigned int nvcsw; /* 268 4 */
long unsigned int nivcsw; /* 272 4 */
struct timespec start_time; /* 276 8 */
long unsigned int min_flt; /* 284 4 */
/* --- cacheline 9 boundary (288 bytes) --- */
long unsigned int maj_flt; /* 288 4 */
cputime_t it_prof_expires; /* 292 4 */
cputime_t it_virt_expires; /* 296 4 */
long long unsigned int it_sched_expires; /* 300 8 */
struct list_head cpu_timers[3]; /* 308 24 */
/* --- cacheline 10 boundary (320 bytes) was 12 bytes ago --- */
uid_t uid; /* 332 4 */
uid_t euid; /* 336 4 */
uid_t suid; /* 340 4 */
uid_t fsuid; /* 344 4 */
gid_t gid; /* 348 4 */
/* --- cacheline 11 boundary (352 bytes) --- */
gid_t egid; /* 352 4 */
gid_t sgid; /* 356 4 */
gid_t fsgid; /* 360 4 */
struct group_info * group_info; /* 364 4 */
kernel_cap_t cap_effective; /* 368 4 */
kernel_cap_t cap_inheritable; /* 372 4 */
kernel_cap_t cap_permitted; /* 376 4 */
unsigned int keep_capabilities:1; /* 380 4 */
/* XXX 31 bits hole, try to pack */
/* --- cacheline 12 boundary (384 bytes) --- */
struct user_struct * user; /* 384 4 */
struct key * request_key_auth; /* 388 4 */
struct key * thread_keyring; /* 392 4 */
unsigned char jit_keyring; /* 396 1 */
unsigned char fpu_counter; /* 397 1 */
/* XXX 2 bytes hole, try to pack */
int oomkilladj; /* 400 4 */
char comm[16]; /* 404 16 */
/* --- cacheline 13 boundary (416 bytes) was 4 bytes ago --- */
int link_count; /* 420 4 */
int total_link_count; /* 424 4 */
struct sysv_sem sysvsem; /* 428 4 */
struct thread_struct thread; /* 432 656 */
/* --- cacheline 34 boundary (1088 bytes) --- */
struct fs_struct * fs; /* 1088 4 */
struct files_struct * files; /* 1092 4 */
struct nsproxy * nsproxy; /* 1096 4 */
struct signal_struct * signal; /* 1100 4 */
struct sighand_struct * sighand; /* 1104 4 */
sigset_t blocked; /* 1108 8 */
sigset_t real_blocked; /* 1116 8 */
/* --- cacheline 35 boundary (1120 bytes) was 4 bytes ago --- */
sigset_t saved_sigmask; /* 1124 8 */
struct sigpending pending; /* 1132 16 */
long unsigned int sas_ss_sp; /* 1148 4 */
/* --- cacheline 36 boundary (1152 bytes) --- */
size_t sas_ss_size; /* 1152 4 */
int (*notifier)(); /* 1156 4 */
void * notifier_data; /* 1160 4 */
sigset_t * notifier_mask; /* 1164 4 */
void * security; /* 1168 4 */
struct audit_context * audit_context; /* 1172 4 */
seccomp_t seccomp; /* 1176 0 */
u32 parent_exec_id; /* 1176 4 */
u32 self_exec_id; /* 1180 4 */
/* --- cacheline 37 boundary (1184 bytes) --- */
spinlock_t alloc_lock; /* 1184 40 */
/* --- cacheline 38 boundary (1216 bytes) was 8 bytes ago --- */
spinlock_t pi_lock; /* 1224 40 */
/* --- cacheline 39 boundary (1248 bytes) was 16 bytes ago --- */
struct plist_head pi_waiters; /* 1264 20 */
/* --- cacheline 40 boundary (1280 bytes) was 4 bytes ago --- */
struct rt_mutex_waiter * pi_blocked_on; /* 1284 4 */
struct mutex_waiter * blocked_on; /* 1288 4 */
unsigned int irq_events; /* 1292 4 */
int hardirqs_enabled; /* 1296 4 */
long unsigned int hardirq_enable_ip; /* 1300 4 */
unsigned int hardirq_enable_event; /* 1304 4 */
long unsigned int hardirq_disable_ip; /* 1308 4 */
/* --- cacheline 41 boundary (1312 bytes) --- */
unsigned int hardirq_disable_event; /* 1312 4 */
int softirqs_enabled; /* 1316 4 */
long unsigned int softirq_disable_ip; /* 1320 4 */
unsigned int softirq_disable_event; /* 1324 4 */
long unsigned int softirq_enable_ip; /* 1328 4 */
unsigned int softirq_enable_event; /* 1332 4 */
int hardirq_context; /* 1336 4 */
int softirq_context; /* 1340 4 */
/* --- cacheline 42 boundary (1344 bytes) --- */
u64 curr_chain_key; /* 1344 8 */
int lockdep_depth; /* 1352 4 */
struct held_lock held_locks[30]; /* 1356 1200 */
/* --- cacheline 79 boundary (2528 bytes) was 28 bytes ago --- */
unsigned int lockdep_recursion; /* 2556 4 */
/* --- cacheline 80 boundary (2560 bytes) --- */
void * journal_info; /* 2560 4 */
struct reclaim_state * reclaim_state; /* 2564 4 */
struct backing_dev_info * backing_dev_info; /* 2568 4 */
struct io_context * io_context; /* 2572 4 */
long unsigned int ptrace_message; /* 2576 4 */
siginfo_t * last_siginfo; /* 2580 4 */
wait_queue_t * io_wait; /* 2584 4 */
u64 rchar; /* 2588 8 */
/* --- cacheline 81 boundary (2592 bytes) was 4 bytes ago --- */
u64 wchar; /* 2596 8 */
u64 syscr; /* 2604 8 */
u64 syscw; /* 2612 8 */
struct robust_list_head * robust_list; /* 2620 4 */
/* --- cacheline 82 boundary (2624 bytes) --- */
struct list_head pi_state_list; /* 2624 8 */
struct futex_pi_state * pi_state_cache; /* 2632 4 */
atomic_t fs_excl; /* 2636 4 */
struct rcu_head rcu; /* 2640 8 */
struct pipe_inode_info * splice_pipe; /* 2648 4 */
}; /* size: 2656, cachelines: 83 */
/* sum members: 2648, holes: 2, sum holes: 4 */
/* bit holes: 2, sum bit holes: 62 bits */
/* padding: 4 */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-07 15:26:50 +01:00
|
|
|
self->nr_bit_holes, sum_bit_holes);
|
2006-10-28 23:22:42 +02:00
|
|
|
if (self->padding > 0)
|
[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
|
|
|
printf(" /* padding: %u */\n", self->padding);
|
|
|
|
if (self->bit_padding > 0)
|
|
|
|
printf(" /* bit_padding: %u bits */\n", self->bit_padding);
|
2006-12-01 15:22:30 +01:00
|
|
|
last_cacheline = self->size % cacheline_size;
|
|
|
|
if (last_cacheline != 0)
|
[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
|
|
|
printf(" /* last cacheline: %u bytes */\n", last_cacheline);
|
2006-10-28 23:22:42 +02:00
|
|
|
|
|
|
|
if (sum + sum_holes != self->size - self->padding)
|
2006-12-25 01:27:22 +01:00
|
|
|
printf("\n/* BRAIN FART ALERT! %u != "
|
|
|
|
"%u + %u(holes), diff = %u */\n\n",
|
2006-10-28 23:22:42 +02:00
|
|
|
self->size, sum, sum_holes,
|
|
|
|
self->size - (sum + sum_holes));
|
|
|
|
}
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
void tag__print(const struct tag *self, const struct cu *cu,
|
|
|
|
const char *prefix, const char *suffix)
|
2006-10-28 23:22:42 +02:00
|
|
|
{
|
2006-12-29 18:28:58 +01:00
|
|
|
printf("/* %s:%u */\n", self->decl_file, self->decl_line);
|
2006-10-29 00:13:27 +02:00
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
switch (self->tag) {
|
2006-10-28 23:22:42 +02:00
|
|
|
case DW_TAG_structure_type:
|
2006-12-23 21:09:47 +01:00
|
|
|
class__print_struct(self, prefix, suffix);
|
2006-10-28 23:22:42 +02:00
|
|
|
break;
|
|
|
|
default:
|
2006-12-29 18:28:58 +01:00
|
|
|
printf("%s: %s tag not supported!\n", __FUNCTION__,
|
|
|
|
dwarf_tag_name(self->tag));
|
2006-10-28 23:22:42 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
int cu__for_each_tag(struct cu *self,
|
|
|
|
int (*iterator)(struct tag *tag, struct cu *cu,
|
|
|
|
void *cookie),
|
|
|
|
void *cookie,
|
|
|
|
struct tag *(*filter)(struct tag *tag, struct cu *cu))
|
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
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
list_for_each_entry(pos, &self->classes, node) {
|
|
|
|
struct tag *tag = pos;
|
2006-12-01 03:00:24 +01:00
|
|
|
if (filter != NULL) {
|
2006-12-29 18:28:58 +01:00
|
|
|
tag = filter(pos, self);
|
|
|
|
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-18 17:33:48 +01:00
|
|
|
int cu__for_each_function(struct cu *cu,
|
|
|
|
int (*iterator)(struct function *func, void *cookie),
|
2006-12-18 18:35:31 +01:00
|
|
|
void *cookie,
|
2006-12-20 15:05:29 +01:00
|
|
|
struct function *(*filter)(struct function *function,
|
|
|
|
void *cookie))
|
2006-11-18 17:33:48 +01:00
|
|
|
{
|
|
|
|
|
|
|
|
struct function *pos;
|
|
|
|
|
2006-12-30 19:34:20 +01:00
|
|
|
list_for_each_entry(pos, &cu->functions, proto.tag.node) {
|
2006-12-18 18:35:31 +01:00
|
|
|
struct function *function = pos;
|
|
|
|
if (filter != NULL) {
|
2006-12-20 15:05:29 +01:00
|
|
|
function = filter(pos, cookie);
|
2006-12-18 18:35:31 +01:00
|
|
|
if (function == NULL)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (iterator(function, cookie))
|
2006-11-18 17:33:48 +01:00
|
|
|
return 1;
|
2006-12-18 18:35:31 +01:00
|
|
|
}
|
2006-11-18 17:33:48 +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)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "pahole: out of memory(%s)\n", msg);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
2006-12-28 14:18:43 +01:00
|
|
|
static const char *attr_string(Dwarf_Die *die, uint32_t name,
|
2006-10-28 23:22:42 +02:00
|
|
|
Dwarf_Attribute *attr)
|
|
|
|
{
|
|
|
|
if (dwarf_attr(die, name, attr) != NULL)
|
|
|
|
return dwarf_formstring(attr);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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)
|
|
|
|
|
2006-12-28 14:18:43 +01:00
|
|
|
static uint64_t __libdw_get_uleb128(uint64_t acc, uint32_t i,
|
|
|
|
const uint8_t **addrp)
|
2006-10-28 23:22:42 +02:00
|
|
|
{
|
2006-12-28 14:18:43 +01:00
|
|
|
uint8_t __b;
|
2006-10-28 23:22:42 +02:00
|
|
|
get_uleb128_rest_return (acc, i, addrp);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define get_uleb128(var, addr) \
|
|
|
|
do { \
|
2006-12-28 14:18:43 +01:00
|
|
|
uint8_t __b; \
|
2006-10-28 23:22:42 +02:00
|
|
|
var = 0; \
|
|
|
|
get_uleb128_step(var, addr, 0, break); \
|
|
|
|
var = __libdw_get_uleb128 (var, 1, &(addr)); \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
|
2006-12-28 13:09:18 +01:00
|
|
|
static Dwarf_Off attr_offset(Dwarf_Die *die)
|
2006-10-28 23:22:42 +02:00
|
|
|
{
|
|
|
|
Dwarf_Attribute attr;
|
|
|
|
|
|
|
|
if (dwarf_attr(die, DW_AT_data_member_location, &attr) != NULL) {
|
2006-12-14 16:18:07 +01:00
|
|
|
Dwarf_Block block;
|
2006-10-28 23:22:42 +02:00
|
|
|
|
|
|
|
if (dwarf_formblock(&attr, &block) == 0) {
|
2006-11-05 03:46:22 +01:00
|
|
|
uint64_t uleb;
|
2006-12-28 14:18:43 +01:00
|
|
|
const uint8_t *data = block.data + 1;
|
2006-10-28 23:22:42 +02:00
|
|
|
get_uleb128(uleb, data);
|
|
|
|
return uleb;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2006-12-28 14:18:43 +01:00
|
|
|
static uint64_t attr_numeric(Dwarf_Die *die, uint32_t name)
|
2006-10-28 23:22:42 +02:00
|
|
|
{
|
|
|
|
Dwarf_Attribute attr;
|
2006-12-28 14:18:43 +01:00
|
|
|
uint32_t form;
|
2006-10-28 23:22:42 +02:00
|
|
|
|
|
|
|
if (dwarf_attr(die, name, &attr) == NULL)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
form = dwarf_whatform(&attr);
|
|
|
|
|
|
|
|
switch (form) {
|
2006-10-30 18:22:39 +01:00
|
|
|
case DW_FORM_addr: {
|
|
|
|
Dwarf_Addr addr;
|
|
|
|
if (dwarf_formaddr(&attr, &addr) == 0)
|
|
|
|
return addr;
|
|
|
|
}
|
|
|
|
break;
|
2006-10-28 23:22:42 +02:00
|
|
|
case DW_FORM_data1:
|
|
|
|
case DW_FORM_data2:
|
|
|
|
case DW_FORM_data4:
|
|
|
|
case DW_FORM_data8:
|
|
|
|
case DW_FORM_sdata:
|
|
|
|
case DW_FORM_udata: {
|
|
|
|
Dwarf_Word value;
|
|
|
|
if (dwarf_formudata(&attr, &value) == 0)
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case DW_FORM_ref1:
|
|
|
|
case DW_FORM_ref2:
|
|
|
|
case DW_FORM_ref4:
|
|
|
|
case DW_FORM_ref8:
|
|
|
|
case DW_FORM_ref_addr:
|
|
|
|
case DW_FORM_ref_udata: {
|
|
|
|
Dwarf_Off ref;
|
|
|
|
if (dwarf_formref(&attr, &ref) == 0)
|
|
|
|
return (uintmax_t)ref;
|
|
|
|
}
|
2006-12-07 23:54:45 +01:00
|
|
|
case DW_FORM_flag:
|
|
|
|
return 1;
|
2006-10-28 23:22:42 +02:00
|
|
|
default:
|
|
|
|
printf("DW_AT_<0x%x>=0x%x\n", name, form);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-12-29 19:34:11 +01:00
|
|
|
static void cu__create_new_tag(Dwarf *dwarf, Dwarf_Die *die, struct cu *cu,
|
|
|
|
Dwarf_Off cu_offset, Dwarf_Off type, uint32_t tag,
|
|
|
|
const char *decl_file, int decl_line)
|
|
|
|
{
|
|
|
|
struct tag *self = tag__new(tag, cu_offset, type, decl_file, decl_line);
|
|
|
|
|
|
|
|
if (self == NULL)
|
|
|
|
oom("tag__new");
|
|
|
|
|
|
|
|
if (dwarf_haschildren(die))
|
|
|
|
fprintf(stderr, "%s: %s WITH children!\n", __FUNCTION__,
|
|
|
|
dwarf_tag_name(tag));
|
|
|
|
|
|
|
|
cu__add_tag(cu, self);
|
|
|
|
}
|
|
|
|
|
2006-12-06 14:35:21 +01:00
|
|
|
static void cu__process_class(Dwarf *dwarf, Dwarf_Die *die,
|
|
|
|
struct class *class, struct cu *cu);
|
|
|
|
|
|
|
|
static void cu__create_new_class(Dwarf *dwarf, Dwarf_Die *die, struct cu *cu,
|
2006-12-28 14:18:43 +01:00
|
|
|
uint32_t tag, Dwarf_Off cu_offset,
|
2006-12-24 15:18:14 +01:00
|
|
|
const char *name, Dwarf_Off type,
|
2006-12-06 14:35:21 +01:00
|
|
|
const char *decl_file, int decl_line)
|
|
|
|
{
|
|
|
|
Dwarf_Die child;
|
2006-12-25 01:27:22 +01:00
|
|
|
size_t size = attr_numeric(die, DW_AT_byte_size);
|
2006-12-06 14:35:21 +01:00
|
|
|
struct class *class = class__new(tag, cu_offset, type, name, size,
|
2006-12-07 23:54:45 +01:00
|
|
|
decl_file, decl_line,
|
|
|
|
attr_numeric(die, DW_AT_declaration));
|
2006-12-06 14:35:21 +01:00
|
|
|
if (class == NULL)
|
|
|
|
oom("class__new");
|
|
|
|
if (dwarf_haschildren(die) != 0 && dwarf_child(die, &child) == 0)
|
|
|
|
cu__process_class(dwarf, &child, class, cu);
|
2006-12-29 18:28:58 +01:00
|
|
|
class->cu = cu;
|
|
|
|
cu__add_tag(cu, &class->tag);
|
2006-12-06 14:35:21 +01:00
|
|
|
}
|
|
|
|
|
2006-12-29 23:58:03 +01:00
|
|
|
static void cu__create_new_base_type(const char *name, Dwarf *dwarf,
|
|
|
|
Dwarf_Die *die, struct cu *cu,
|
|
|
|
Dwarf_Off cu_offset, Dwarf_Off type,
|
|
|
|
const char *decl_file, int decl_line)
|
|
|
|
{
|
|
|
|
const size_t size = attr_numeric(die, DW_AT_byte_size);
|
|
|
|
struct base_type *base = base_type__new(name, size, cu_offset, type,
|
|
|
|
decl_file, decl_line);
|
|
|
|
if (base == NULL)
|
|
|
|
oom("base_type__new");
|
|
|
|
|
|
|
|
if (dwarf_haschildren(die))
|
|
|
|
fprintf(stderr, "%s: DW_TAG_base_type WITH children!\n",
|
|
|
|
__FUNCTION__);
|
|
|
|
|
|
|
|
cu__add_tag(cu, &base->tag);
|
|
|
|
}
|
|
|
|
|
2006-12-08 15:58:46 +01:00
|
|
|
static void cu__create_new_array(Dwarf *dwarf, Dwarf_Die *die, struct cu *cu,
|
2006-12-24 15:18:14 +01:00
|
|
|
Dwarf_Off cu_offset, Dwarf_Off type,
|
2006-12-08 15:58:46 +01:00
|
|
|
const char *decl_file, int decl_line)
|
|
|
|
{
|
|
|
|
Dwarf_Die child;
|
|
|
|
/* "64 dimensions will be enough for everybody." acme, 2006 */
|
|
|
|
const uint8_t max_dimensions = 64;
|
|
|
|
uint32_t nr_entries[max_dimensions];
|
2006-12-29 18:28:58 +01:00
|
|
|
struct array_type *array = array_type__new(cu_offset, type,
|
|
|
|
decl_file, decl_line);
|
|
|
|
if (array == NULL)
|
|
|
|
oom("array_type__new");
|
2006-12-08 15:58:46 +01:00
|
|
|
|
|
|
|
if (!dwarf_haschildren(die) || dwarf_child(die, &child) != 0) {
|
|
|
|
fprintf(stderr, "%s: DW_TAG_array_type with no children!\n",
|
|
|
|
__FUNCTION__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
die = &child;
|
2006-12-29 18:28:58 +01:00
|
|
|
array->dimensions = 0;
|
2006-12-08 15:58:46 +01:00
|
|
|
do {
|
|
|
|
const uint16_t tag = dwarf_tag(die);
|
|
|
|
|
|
|
|
if (tag == 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
|
|
|
|
fprintf(stderr, "%s: DW_TAG_%s not handled!\n",
|
|
|
|
__FUNCTION__, dwarf_tag_name(tag));
|
|
|
|
} 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)");
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
cu__add_tag(cu, &array->tag);
|
2006-12-08 15:58:46 +01:00
|
|
|
}
|
|
|
|
|
2006-12-06 14:35:21 +01:00
|
|
|
static void cu__process_class(Dwarf *dwarf, Dwarf_Die *die, struct class *class,
|
|
|
|
struct cu *cu)
|
2006-10-28 23:22:42 +02:00
|
|
|
{
|
|
|
|
Dwarf_Die child;
|
|
|
|
Dwarf_Off cu_offset;
|
|
|
|
Dwarf_Attribute attr_name;
|
2006-11-19 00:06:03 +01:00
|
|
|
const char *decl_file, *name;
|
2006-12-24 15:18:14 +01:00
|
|
|
Dwarf_Off type;
|
2006-11-19 00:06:03 +01:00
|
|
|
int decl_line = 0;
|
2006-12-28 14:18:43 +01:00
|
|
|
uint32_t tag = dwarf_tag(die);
|
2006-10-28 23:22:42 +02:00
|
|
|
|
|
|
|
if (tag == DW_TAG_invalid)
|
|
|
|
return;
|
|
|
|
|
2006-10-30 17:37:04 +01:00
|
|
|
cu_offset = dwarf_cuoffset(die);
|
2006-11-18 14:54:02 +01:00
|
|
|
decl_file = dwarf_decl_file(die);
|
2006-11-19 00:06:03 +01:00
|
|
|
type = attr_numeric(die, DW_AT_type);
|
|
|
|
name = attr_string(die, DW_AT_name, &attr_name);
|
2006-11-18 14:54:02 +01:00
|
|
|
|
|
|
|
dwarf_decl_line(die, &decl_line);
|
2006-10-28 23:22:42 +02:00
|
|
|
|
2006-11-19 00:06:03 +01:00
|
|
|
switch (tag) {
|
2006-12-07 23:00:45 +01:00
|
|
|
case DW_TAG_inheritance:
|
2006-11-19 00:06:03 +01:00
|
|
|
case DW_TAG_member: {
|
2006-10-28 23:22:42 +02:00
|
|
|
struct class_member *member;
|
|
|
|
|
2006-12-07 23:00:45 +01:00
|
|
|
member = class_member__new(cu_offset, tag, type,
|
2006-11-18 14:54:02 +01:00
|
|
|
decl_file, decl_line,
|
|
|
|
name, attr_offset(die),
|
2006-10-30 17:37:04 +01:00
|
|
|
attr_numeric(die, DW_AT_bit_size),
|
|
|
|
attr_numeric(die, DW_AT_bit_offset));
|
2006-10-28 23:22:42 +02:00
|
|
|
if (member == NULL)
|
|
|
|
oom("class_member__new");
|
|
|
|
|
2006-11-19 00:06:03 +01:00
|
|
|
class__add_member(class, member);
|
|
|
|
}
|
|
|
|
break;
|
2006-12-28 17:35:44 +01:00
|
|
|
case DW_TAG_formal_parameter:
|
|
|
|
/* Discard for now */
|
|
|
|
goto next_sibling;
|
2006-12-06 17:23:54 +01:00
|
|
|
case DW_TAG_structure_type:
|
|
|
|
/*
|
|
|
|
* structs within structs: C++
|
|
|
|
*
|
|
|
|
* FIXME: For now classes defined within classes are being
|
|
|
|
* visible externally, in a flat namespace. This ins not so
|
|
|
|
* much of a problem as every class has a different id, the
|
|
|
|
* cu_offset, but we need to have namespaces, so that we
|
|
|
|
* can properly print it in class__print_struct and so that
|
|
|
|
* we can specify 'pahole QDebug::Stream' as in the example
|
|
|
|
* that led to supporting classes within classes.
|
|
|
|
*/
|
|
|
|
default: /*
|
|
|
|
* Fall thru, enums, etc can also be defined inside
|
|
|
|
* C++ classes
|
|
|
|
*/
|
|
|
|
cu__create_new_class(dwarf, die, cu, tag, cu_offset,
|
|
|
|
name, type, decl_file, decl_line);
|
|
|
|
goto next_sibling;
|
2006-11-19 00:06:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (dwarf_haschildren(die) != 0 && dwarf_child(die, &child) == 0)
|
2006-12-06 14:35:21 +01:00
|
|
|
cu__process_class(dwarf, &child, class, cu);
|
|
|
|
next_sibling:
|
2006-11-19 00:06:03 +01:00
|
|
|
if (dwarf_siblingof(die, die) == 0)
|
2006-12-06 14:35:21 +01:00
|
|
|
cu__process_class(dwarf, die, class, cu);
|
2006-11-19 00:06:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void cu__process_function(Dwarf *dwarf, Dwarf_Die *die,
|
2006-11-20 19:59:51 +01:00
|
|
|
struct cu *cu, struct function *function,
|
|
|
|
struct lexblock *lexblock)
|
2006-11-19 00:06:03 +01:00
|
|
|
{
|
|
|
|
Dwarf_Die child;
|
|
|
|
Dwarf_Off cu_offset;
|
|
|
|
Dwarf_Attribute attr_name;
|
|
|
|
const char *decl_file;
|
|
|
|
int decl_line = 0;
|
|
|
|
const char *name;
|
2006-12-24 15:18:14 +01:00
|
|
|
Dwarf_Off type;
|
2006-12-28 14:18:43 +01:00
|
|
|
uint32_t tag = dwarf_tag(die);
|
2006-11-19 00:06:03 +01:00
|
|
|
|
|
|
|
if (tag == DW_TAG_invalid)
|
|
|
|
return;
|
|
|
|
|
|
|
|
cu_offset = dwarf_cuoffset(die);
|
|
|
|
name = attr_string(die, DW_AT_name, &attr_name);
|
|
|
|
type = attr_numeric(die, DW_AT_type);
|
|
|
|
decl_file = dwarf_decl_file(die);
|
|
|
|
|
|
|
|
dwarf_decl_line(die, &decl_line);
|
|
|
|
|
|
|
|
switch (tag) {
|
|
|
|
case DW_TAG_formal_parameter: {
|
2006-11-18 17:33:48 +01:00
|
|
|
struct parameter *parameter;
|
|
|
|
|
|
|
|
parameter = parameter__new(cu_offset, type,
|
|
|
|
decl_file, decl_line, name);
|
|
|
|
if (parameter == NULL)
|
|
|
|
oom("parameter__new");
|
|
|
|
|
2007-01-02 05:21:59 +01:00
|
|
|
if (function != NULL)
|
|
|
|
ftype__add_parameter(&function->proto, parameter);
|
2006-11-19 00:06:03 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case DW_TAG_variable: {
|
2006-12-28 12:38:40 +01:00
|
|
|
Dwarf_Off abstract_origin =
|
|
|
|
attr_numeric(die, DW_AT_abstract_origin);
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
struct variable *variable;
|
|
|
|
|
|
|
|
variable = variable__new(name, cu_offset,
|
2006-11-18 14:54:02 +01:00
|
|
|
type, decl_file, decl_line,
|
|
|
|
abstract_origin);
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
if (variable == NULL)
|
|
|
|
oom("variable__new");
|
|
|
|
|
2006-11-20 19:59:51 +01:00
|
|
|
lexblock__add_variable(lexblock, variable);
|
2006-11-19 00:06:03 +01:00
|
|
|
cu__add_variable(cu, variable);
|
|
|
|
}
|
|
|
|
break;
|
2006-11-19 00:15:36 +01:00
|
|
|
case DW_TAG_unspecified_parameters:
|
2007-01-02 05:21:59 +01:00
|
|
|
if (function != NULL)
|
|
|
|
function->proto.unspec_parms = 1;
|
2006-11-19 00:15:36 +01:00
|
|
|
break;
|
2006-11-20 19:17:42 +01:00
|
|
|
case DW_TAG_label: {
|
|
|
|
struct label *label;
|
|
|
|
Dwarf_Addr low_pc;
|
|
|
|
|
|
|
|
if (dwarf_lowpc(die, &low_pc))
|
|
|
|
low_pc = 0;
|
|
|
|
|
|
|
|
label = label__new(cu_offset, type, decl_file, decl_line,
|
|
|
|
name, low_pc);
|
|
|
|
if (label == NULL)
|
|
|
|
oom("label__new");
|
|
|
|
|
2006-11-20 19:59:51 +01:00
|
|
|
lexblock__add_label(lexblock, label);
|
2006-11-20 19:17:42 +01:00
|
|
|
}
|
2006-11-19 00:06:03 +01:00
|
|
|
break;
|
|
|
|
case DW_TAG_inlined_subroutine: {
|
2006-11-03 18:32:32 +01:00
|
|
|
Dwarf_Addr high_pc, low_pc;
|
2006-11-20 03:36:11 +01:00
|
|
|
Dwarf_Attribute attr_call_file;
|
2006-12-24 15:18:14 +01:00
|
|
|
const Dwarf_Off type = attr_numeric(die,
|
|
|
|
DW_AT_abstract_origin);
|
2006-11-03 16:41:19 +01:00
|
|
|
struct inline_expansion *exp;
|
2006-12-25 01:27:22 +01:00
|
|
|
size_t size;
|
2006-11-03 18:32:32 +01:00
|
|
|
|
2006-12-05 17:53:50 +01:00
|
|
|
if (dwarf_highpc(die, &high_pc))
|
|
|
|
high_pc = 0;
|
|
|
|
if (dwarf_lowpc(die, &low_pc))
|
|
|
|
low_pc = 0;
|
|
|
|
|
|
|
|
size = high_pc - low_pc;
|
2006-11-03 16:41:19 +01:00
|
|
|
if (size == 0) {
|
2006-12-26 14:44:05 +01:00
|
|
|
Dwarf_Addr base, start;
|
2006-11-03 16:41:19 +01:00
|
|
|
ptrdiff_t offset = 0;
|
|
|
|
|
|
|
|
while (1) {
|
2006-12-26 14:44:05 +01:00
|
|
|
offset = dwarf_ranges(die, offset,
|
|
|
|
&base, &start, &high_pc);
|
|
|
|
start = (unsigned long)start;
|
|
|
|
high_pc = (unsigned long)high_pc;
|
2006-11-03 16:41:19 +01:00
|
|
|
if (offset <= 0)
|
|
|
|
break;
|
2006-12-26 14:44:05 +01:00
|
|
|
size += high_pc - start;
|
|
|
|
if (low_pc == 0)
|
|
|
|
low_pc = start;
|
2006-11-03 16:41:19 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-11-20 03:36:11 +01:00
|
|
|
decl_file = attr_string(die, DW_AT_call_file, &attr_call_file);
|
|
|
|
decl_line = attr_numeric(die, DW_AT_call_line);
|
|
|
|
|
2006-11-18 14:54:02 +01:00
|
|
|
exp = inline_expansion__new(cu_offset, type,
|
2006-12-26 14:44:05 +01:00
|
|
|
decl_file, decl_line, size,
|
|
|
|
low_pc, high_pc);
|
2006-11-03 16:41:19 +01:00
|
|
|
if (exp == NULL)
|
|
|
|
oom("inline_expansion__new");
|
|
|
|
|
2006-11-20 19:59:51 +01:00
|
|
|
lexblock__add_inline_expansion(lexblock, exp);
|
2006-11-20 19:51:42 +01:00
|
|
|
exp->function = function;
|
2006-11-19 00:06:03 +01:00
|
|
|
}
|
2006-11-03 16:41:19 +01:00
|
|
|
goto next_sibling;
|
2006-11-19 00:06:03 +01:00
|
|
|
case DW_TAG_lexical_block:
|
2006-11-02 19:53:39 +01:00
|
|
|
/*
|
|
|
|
* Not handled right now,
|
|
|
|
* will be used for stack size calculation
|
|
|
|
*/
|
2006-11-19 00:06:03 +01:00
|
|
|
break;
|
2007-01-02 05:17:37 +01:00
|
|
|
case DW_TAG_structure_type:
|
|
|
|
case DW_TAG_union_type:
|
|
|
|
cu__create_new_class(dwarf, die, cu, tag, cu_offset,
|
|
|
|
name, type, decl_file, decl_line);
|
|
|
|
goto next_sibling;
|
2006-11-19 00:06:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (dwarf_haschildren(die) != 0 && dwarf_child(die, &child) == 0)
|
2007-01-02 05:21:59 +01:00
|
|
|
cu__process_function(dwarf, &child, cu, NULL, lexblock);
|
2006-11-19 00:06:03 +01:00
|
|
|
next_sibling:
|
|
|
|
if (dwarf_siblingof(die, die) == 0)
|
2006-11-20 19:59:51 +01:00
|
|
|
cu__process_function(dwarf, die, cu, function, lexblock);
|
2006-11-19 00:06:03 +01:00
|
|
|
}
|
|
|
|
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
static void cu__create_new_enumeration(Dwarf *dwarf, Dwarf_Die *die, struct cu *cu,
|
2006-12-24 15:18:14 +01:00
|
|
|
Dwarf_Off cu_offset, Dwarf_Off type,
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
const char *decl_file, int decl_line,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
Dwarf_Die child;
|
2006-12-25 01:27:22 +01:00
|
|
|
const size_t size = attr_numeric(die, DW_AT_byte_size);
|
[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 class *enumeration = class__new(DW_TAG_enumeration_type,
|
|
|
|
cu_offset, type, name, size,
|
|
|
|
decl_file, decl_line,
|
|
|
|
attr_numeric(die, DW_AT_declaration));
|
|
|
|
if (enumeration == NULL)
|
|
|
|
oom("class__new");
|
|
|
|
|
|
|
|
if (!dwarf_haschildren(die) || dwarf_child(die, &child) != 0) {
|
|
|
|
fprintf(stderr, "%s: DW_TAG_enumeration_type with no "
|
|
|
|
"children!\n", __FUNCTION__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
die = &child;
|
|
|
|
do {
|
|
|
|
Dwarf_Attribute attr_name;
|
|
|
|
struct enumerator *enumerator;
|
|
|
|
uint32_t decl_line;
|
|
|
|
const uint16_t tag = dwarf_tag(die);
|
|
|
|
const Dwarf_Off id = dwarf_cuoffset(die);
|
2006-12-24 15:18:14 +01:00
|
|
|
const Dwarf_Off type = attr_numeric(die, DW_AT_type);
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
const uint32_t value = attr_numeric(die, DW_AT_const_value);
|
|
|
|
const char *decl_file = dwarf_decl_file(die);
|
|
|
|
const char *name = attr_string(die, DW_AT_name,
|
|
|
|
&attr_name);
|
|
|
|
dwarf_decl_line(die, &decl_line);
|
|
|
|
|
|
|
|
if (tag != DW_TAG_enumerator) {
|
|
|
|
fprintf(stderr, "%s: DW_TAG_%s not handled!\n",
|
|
|
|
__FUNCTION__, dwarf_tag_name(tag));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
enumerator = enumerator__new(id, type, decl_file, decl_line,
|
|
|
|
name, value);
|
|
|
|
if (enumerator == NULL)
|
|
|
|
oom("enumerator__new");
|
|
|
|
|
|
|
|
enumeration__add(enumeration, enumerator);
|
|
|
|
} while (dwarf_siblingof(die, die) == 0);
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
enumeration->cu = cu;
|
|
|
|
cu__add_tag(cu, &enumeration->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
|
|
|
}
|
|
|
|
|
2006-11-19 00:06:03 +01:00
|
|
|
static void cu__process_die(Dwarf *dwarf, Dwarf_Die *die, struct cu *cu)
|
|
|
|
{
|
|
|
|
Dwarf_Die child;
|
|
|
|
Dwarf_Off cu_offset;
|
|
|
|
Dwarf_Attribute attr_name;
|
|
|
|
const char *decl_file;
|
|
|
|
int decl_line = 0;
|
|
|
|
const char *name;
|
2006-12-24 15:18:14 +01:00
|
|
|
Dwarf_Off type;
|
2006-12-28 14:18:43 +01:00
|
|
|
uint32_t tag = dwarf_tag(die);
|
2006-11-19 00:06:03 +01:00
|
|
|
|
|
|
|
if (tag == DW_TAG_invalid)
|
|
|
|
return;
|
|
|
|
|
2006-12-07 20:21:52 +01:00
|
|
|
if (tag == DW_TAG_compile_unit) {
|
|
|
|
cu->language = attr_numeric(die, DW_AT_language);
|
2006-11-19 00:06:03 +01:00
|
|
|
goto children;
|
2006-12-07 20:21:52 +01:00
|
|
|
}
|
2006-11-19 00:06:03 +01:00
|
|
|
|
|
|
|
cu_offset = dwarf_cuoffset(die);
|
|
|
|
name = attr_string(die, DW_AT_name, &attr_name);
|
|
|
|
type = attr_numeric(die, DW_AT_type);
|
|
|
|
decl_file = dwarf_decl_file(die);
|
|
|
|
|
|
|
|
dwarf_decl_line(die, &decl_line);
|
|
|
|
|
|
|
|
switch (tag) {
|
|
|
|
case DW_TAG_variable:
|
|
|
|
/* Handle global variables later */
|
|
|
|
break;
|
|
|
|
case DW_TAG_subprogram: {
|
|
|
|
struct function *function;
|
2006-12-28 14:18:43 +01:00
|
|
|
const uint16_t inlined = attr_numeric(die, DW_AT_inline);
|
2006-11-18 02:43:08 +01:00
|
|
|
const char external = dwarf_hasattr(die, DW_AT_external);
|
2006-11-03 18:32:32 +01:00
|
|
|
Dwarf_Addr high_pc, low_pc;
|
2006-11-18 17:33:48 +01:00
|
|
|
|
|
|
|
if (dwarf_highpc(die, &high_pc))
|
|
|
|
high_pc = 0;
|
|
|
|
if (dwarf_lowpc(die, &low_pc))
|
|
|
|
low_pc = 0;
|
|
|
|
|
2006-11-19 00:06:03 +01:00
|
|
|
function = function__new(cu_offset, type,
|
|
|
|
decl_file, decl_line,
|
|
|
|
name, inlined, external,
|
|
|
|
low_pc, high_pc);
|
|
|
|
if (function == NULL)
|
2006-11-18 17:33:48 +01:00
|
|
|
oom("function__new");
|
2006-11-19 00:06:03 +01:00
|
|
|
if (dwarf_haschildren(die) != 0 && dwarf_child(die, &child) == 0)
|
2006-11-20 19:59:51 +01:00
|
|
|
cu__process_function(dwarf, &child, cu, function,
|
|
|
|
&function->lexblock);
|
2006-11-19 00:06:03 +01:00
|
|
|
cu__add_function(cu, function);
|
|
|
|
}
|
|
|
|
goto next_sibling;
|
2006-12-29 19:34:11 +01:00
|
|
|
case DW_TAG_const_type:
|
|
|
|
case DW_TAG_pointer_type:
|
|
|
|
case DW_TAG_volatile_type:
|
|
|
|
cu__create_new_tag(dwarf, die, cu, cu_offset, type, tag,
|
|
|
|
decl_file, decl_line);
|
|
|
|
goto next_sibling;
|
2006-12-29 23:58:03 +01:00
|
|
|
case DW_TAG_base_type:
|
|
|
|
cu__create_new_base_type(name, dwarf, die, cu, cu_offset, type,
|
|
|
|
decl_file, decl_line);
|
|
|
|
goto next_sibling;
|
2006-12-08 15:58:46 +01:00
|
|
|
case DW_TAG_array_type:
|
|
|
|
cu__create_new_array(dwarf, die, cu, cu_offset, type,
|
|
|
|
decl_file, decl_line);
|
|
|
|
goto next_sibling;
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
case DW_TAG_enumeration_type:
|
|
|
|
cu__create_new_enumeration(dwarf, die, cu, cu_offset, type,
|
|
|
|
decl_file, decl_line, name);
|
|
|
|
goto next_sibling;
|
2006-12-06 14:35:21 +01:00
|
|
|
default:
|
|
|
|
cu__create_new_class(dwarf, die, cu, tag, cu_offset,
|
|
|
|
name, type, decl_file, decl_line);
|
2006-11-19 00:06:03 +01:00
|
|
|
goto next_sibling;
|
|
|
|
}
|
2006-10-28 23:22:42 +02:00
|
|
|
|
2006-11-10 22:19:58 +01:00
|
|
|
children:
|
2006-10-28 23:22:42 +02:00
|
|
|
if (dwarf_haschildren(die) != 0 && dwarf_child(die, &child) == 0)
|
2006-11-19 00:06:03 +01:00
|
|
|
cu__process_die(dwarf, &child, cu);
|
2006-11-03 16:41:19 +01:00
|
|
|
next_sibling:
|
2006-11-18 19:32:05 +01:00
|
|
|
if (dwarf_siblingof(die, die) == 0)
|
2006-11-19 00:06:03 +01:00
|
|
|
cu__process_die(dwarf, die, cu);
|
2006-10-28 23:22:42 +02:00
|
|
|
}
|
|
|
|
|
2006-12-27 17:57:19 +01:00
|
|
|
int cus__load_dir(struct cus *self, const char *dirname,
|
|
|
|
const char *filename_mask, const int recursive)
|
|
|
|
{
|
|
|
|
struct dirent *entry;
|
|
|
|
int err = -1;
|
|
|
|
DIR *dir = opendir(dirname);
|
|
|
|
|
|
|
|
if (dir == NULL)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
err = 0;
|
|
|
|
while ((entry = readdir(dir)) != NULL) {
|
|
|
|
char pathname[PATH_MAX];
|
|
|
|
struct stat st;
|
|
|
|
|
|
|
|
if (strcmp(entry->d_name, ".") == 0 ||
|
|
|
|
strcmp(entry->d_name, "..") == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
snprintf(pathname, sizeof(pathname), "%s/%s",
|
|
|
|
dirname, entry->d_name);
|
|
|
|
|
|
|
|
err = lstat(pathname, &st);
|
|
|
|
if (err != 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (S_ISDIR(st.st_mode)) {
|
|
|
|
if (!recursive)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
err = cus__load_dir(self, pathname,
|
|
|
|
filename_mask, recursive);
|
|
|
|
if (err != 0)
|
|
|
|
break;
|
|
|
|
} else if (fnmatch(filename_mask, entry->d_name, 0) == 0) {
|
|
|
|
err = cus__load(self, pathname);
|
|
|
|
if (err != 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err == -1)
|
|
|
|
puts(dirname);
|
|
|
|
closedir(dir);
|
|
|
|
out:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2006-12-20 15:35:45 +01:00
|
|
|
int cus__load(struct cus *self, const char *filename)
|
2006-10-28 23:22:42 +02:00
|
|
|
{
|
|
|
|
Dwarf_Off offset, last_offset, abbrev_offset;
|
|
|
|
uint8_t addr_size, offset_size;
|
2006-12-24 15:00:07 +01:00
|
|
|
uint32_t cu_id;
|
2006-10-28 23:22:42 +02:00
|
|
|
size_t hdr_size;
|
|
|
|
Dwarf *dwarf;
|
|
|
|
int err = -1;
|
2006-12-20 15:35:45 +01:00
|
|
|
int fd = open(filename, O_RDONLY);
|
2006-10-28 23:22:42 +02:00
|
|
|
|
|
|
|
if (fd < 0)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
dwarf = dwarf_begin(fd, DWARF_C_READ);
|
|
|
|
if (dwarf == NULL)
|
|
|
|
goto out_close;
|
|
|
|
|
|
|
|
offset = last_offset = 0;
|
2006-11-19 00:06:03 +01:00
|
|
|
cu_id = 0;
|
2006-10-28 23:22:42 +02:00
|
|
|
while (dwarf_nextcu(dwarf, offset, &offset, &hdr_size,
|
|
|
|
&abbrev_offset, &addr_size, &offset_size) == 0) {
|
|
|
|
Dwarf_Die die;
|
|
|
|
|
|
|
|
if (dwarf_offdie(dwarf, last_offset + hdr_size, &die) != NULL) {
|
2006-11-03 18:38:43 +01:00
|
|
|
Dwarf_Attribute name;
|
2006-11-19 00:06:03 +01:00
|
|
|
struct cu *cu = cu__new(cu_id,
|
|
|
|
attr_string(&die, DW_AT_name,
|
2006-12-29 19:34:11 +01:00
|
|
|
&name),
|
|
|
|
addr_size);
|
2006-11-19 00:06:03 +01:00
|
|
|
if (cu == NULL)
|
2006-10-31 20:12:42 +01:00
|
|
|
oom("cu__new");
|
2006-11-19 00:06:03 +01:00
|
|
|
++cu_id;
|
|
|
|
cu__process_die(dwarf, &die, cu);
|
|
|
|
cus__add(self, cu);
|
2006-10-28 23:22:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
last_offset = offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
dwarf_end(dwarf);
|
|
|
|
err = 0;
|
|
|
|
out_close:
|
|
|
|
close(fd);
|
|
|
|
out:
|
|
|
|
return err;
|
|
|
|
}
|
2006-11-11 19:31:04 +01:00
|
|
|
|
2006-12-27 17:39:37 +01:00
|
|
|
struct cus *cus__new(struct list_head *definitions,
|
|
|
|
struct list_head *fwd_decls)
|
2006-11-11 19:31:04 +01:00
|
|
|
{
|
|
|
|
struct cus *self = malloc(sizeof(*self));
|
|
|
|
|
2006-12-23 21:30:48 +01:00
|
|
|
if (self != NULL) {
|
2006-11-11 19:31:04 +01:00
|
|
|
INIT_LIST_HEAD(&self->cus);
|
2006-12-27 17:39:37 +01:00
|
|
|
INIT_LIST_HEAD(&self->priv_definitions);
|
|
|
|
INIT_LIST_HEAD(&self->priv_fwd_decls);
|
|
|
|
self->definitions = definitions ?: &self->priv_definitions;
|
|
|
|
self->fwd_decls = fwd_decls ?: &self->priv_fwd_decls;
|
2006-12-23 21:30:48 +01:00
|
|
|
}
|
2006-11-11 19:31:04 +01:00
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
2006-12-23 22:29:27 +01:00
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
static int cus__emit_typedef_definitions(struct cus *self, struct tag *tdef)
|
2006-12-23 22:29:27 +01:00
|
|
|
{
|
2006-12-29 18:28:58 +01:00
|
|
|
struct class *class = tag__class(tdef);
|
|
|
|
struct tag *type, *ptr_type;
|
2006-12-24 17:00:16 +01:00
|
|
|
int is_pointer = 0;
|
2006-12-23 22:29:27 +01:00
|
|
|
char bf[512];
|
|
|
|
|
|
|
|
/* Have we already emitted this in this CU? */
|
|
|
|
if (class->visited)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Ok, lets look at the previous CUs: */
|
|
|
|
if (cus__find_definition(self, class->name) != NULL) {
|
|
|
|
/*
|
|
|
|
* Yes, so lets mark it visited on this CU too,
|
|
|
|
* to speed up the lookup.
|
|
|
|
*/
|
|
|
|
class->visited = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
2006-12-29 18:28:58 +01:00
|
|
|
type = cu__find_tag_by_id(class->cu, class->tag.type);
|
2006-12-23 22:29:27 +01:00
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
if (type->tag == DW_TAG_typedef)
|
2006-12-23 22:29:27 +01:00
|
|
|
cus__emit_typedef_definitions(self, type);
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
switch (type->tag) {
|
2006-12-24 17:00:16 +01:00
|
|
|
case DW_TAG_pointer_type:
|
2006-12-29 18:28:58 +01:00
|
|
|
ptr_type = cu__find_tag_by_id(class->cu, type->type);
|
|
|
|
if (ptr_type->tag != DW_TAG_subroutine_type)
|
2006-12-24 17:00:16 +01:00
|
|
|
break;
|
|
|
|
type = ptr_type;
|
|
|
|
is_pointer = 1;
|
|
|
|
/* Fall thru */
|
|
|
|
case DW_TAG_subroutine_type:
|
2006-12-29 18:28:58 +01:00
|
|
|
tag__subroutine_mask(type, class->cu, bf, sizeof(bf),
|
|
|
|
is_pointer);
|
2006-12-24 17:00:16 +01:00
|
|
|
fputs("typedef ", stdout);
|
|
|
|
printf(bf, class->name);
|
|
|
|
puts(";");
|
|
|
|
goto out;
|
2006-12-29 18:28:58 +01:00
|
|
|
case DW_TAG_structure_type: {
|
|
|
|
struct class *ctype = tag__class(type);
|
|
|
|
|
|
|
|
if (ctype->name == NULL)
|
|
|
|
cus__emit_struct_definitions(self, ctype,
|
2006-12-24 22:46:52 +01:00
|
|
|
"typedef", class->name);
|
2006-12-24 17:29:08 +01:00
|
|
|
else
|
|
|
|
printf("typedef struct %s %s;\n",
|
2006-12-29 18:28:58 +01:00
|
|
|
ctype->name, class->name);
|
|
|
|
}
|
2006-12-23 22:29:27 +01:00
|
|
|
goto out;
|
|
|
|
}
|
2006-12-29 18:28:58 +01:00
|
|
|
printf("typedef %s %s;\n", tag__name(type, class->cu, bf, sizeof(bf)),
|
2006-12-23 22:29:27 +01:00
|
|
|
class->name);
|
|
|
|
out:
|
|
|
|
cus__add_definition(self, class);
|
|
|
|
return 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 int cus__emit_enumeration_definitions(struct cus *self,
|
|
|
|
struct class *enumeration)
|
|
|
|
{
|
|
|
|
/* Have we already emitted this in this CU? */
|
|
|
|
if (enumeration->visited)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Ok, lets look at the previous CUs: */
|
|
|
|
if (cus__find_definition(self, enumeration->name) != NULL) {
|
|
|
|
/*
|
|
|
|
* Yes, so lets mark it visited on this CU too,
|
|
|
|
* to speed up the lookup.
|
|
|
|
*/
|
|
|
|
enumeration->visited = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
enumeration__print(enumeration, NULL, 0);
|
|
|
|
enumeration->visited = 1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2006-12-24 02:33:37 +01:00
|
|
|
int cus__emit_fwd_decl(struct cus *self, struct class *class)
|
2006-12-23 22:29:27 +01:00
|
|
|
{
|
|
|
|
struct class *type;
|
|
|
|
char bf[256];
|
|
|
|
|
|
|
|
/* Have we already emitted this in this CU? */
|
|
|
|
if (class->fwd_decl_emitted)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Ok, lets look at the previous CUs: */
|
|
|
|
if (cus__find_fwd_decl(self, class->name) != NULL) {
|
|
|
|
/*
|
|
|
|
* Yes, so lets mark it visited on this CU too,
|
|
|
|
* to speed up the lookup.
|
|
|
|
*/
|
|
|
|
class->fwd_decl_emitted = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
[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
|
|
|
printf("struct %s;\n", class->name);
|
2006-12-23 22:29:27 +01:00
|
|
|
cus__add_fwd_decl(self, class);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cus__emit_tag_definitions(struct cus *self, struct cu *cu,
|
|
|
|
struct tag *tag)
|
|
|
|
{
|
2006-12-29 18:28:58 +01:00
|
|
|
struct tag *type = cu__find_tag_by_id(cu, tag->type);
|
|
|
|
struct class *ctype;
|
2006-12-23 22:29:27 +01:00
|
|
|
int pointer = 0;
|
|
|
|
|
|
|
|
if (type == NULL)
|
|
|
|
return 0;
|
|
|
|
next_indirection:
|
2006-12-29 18:28:58 +01:00
|
|
|
if (type->tag == DW_TAG_pointer_type ||
|
|
|
|
type->tag == DW_TAG_array_type ||
|
|
|
|
type->tag == DW_TAG_const_type ||
|
|
|
|
type->tag == DW_TAG_volatile_type) {
|
2006-12-23 22:29:27 +01:00
|
|
|
pointer = 1;
|
2006-12-29 18:28:58 +01:00
|
|
|
type = cu__find_tag_by_id(cu, type->type);
|
2006-12-23 22:29:27 +01:00
|
|
|
if (type == NULL)
|
|
|
|
return 0;
|
|
|
|
goto next_indirection;
|
|
|
|
}
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
ctype = tag__class(type);
|
|
|
|
|
|
|
|
switch (type->tag) {
|
2006-12-23 22:29:27 +01:00
|
|
|
case DW_TAG_typedef:
|
|
|
|
return cus__emit_typedef_definitions(self, type);
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
case DW_TAG_enumeration_type:
|
2006-12-29 18:28:58 +01:00
|
|
|
if (tag__class(type)->name != NULL)
|
|
|
|
return cus__emit_enumeration_definitions(self, ctype);
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
break;
|
2006-12-23 22:29:27 +01:00
|
|
|
case DW_TAG_structure_type:
|
|
|
|
if (pointer)
|
2006-12-29 18:28:58 +01:00
|
|
|
return cus__emit_fwd_decl(self, ctype);
|
|
|
|
return cus__emit_struct_definitions(self, ctype, NULL, NULL);
|
2006-12-27 13:21:40 +01:00
|
|
|
case DW_TAG_subroutine_type:
|
2006-12-29 18:28:58 +01:00
|
|
|
return cus__emit_tag_definitions(self, cu, type);
|
2006-12-23 22:29:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-12-30 19:34:20 +01:00
|
|
|
int cus__emit_ftype_definitions(struct cus *self, struct cu *cu,
|
|
|
|
struct ftype *ftype)
|
2006-12-23 22:29:27 +01:00
|
|
|
{
|
|
|
|
struct parameter *pos;
|
|
|
|
/* First check the function return type */
|
2006-12-30 19:34:20 +01:00
|
|
|
int printed = cus__emit_tag_definitions(self, cu, &ftype->tag);
|
2006-12-23 22:29:27 +01:00
|
|
|
|
|
|
|
/* Then its parameters */
|
2006-12-30 19:34:20 +01:00
|
|
|
list_for_each_entry(pos, &ftype->parms, tag.node)
|
|
|
|
if (cus__emit_tag_definitions(self, cu, &pos->tag))
|
2006-12-23 22:29:27 +01:00
|
|
|
printed = 1;
|
|
|
|
|
|
|
|
if (printed)
|
|
|
|
putchar('\n');
|
|
|
|
return printed;
|
|
|
|
}
|
|
|
|
|
|
|
|
int cus__emit_struct_definitions(struct cus *self, struct class *class,
|
|
|
|
const char *prefix, const char *suffix)
|
|
|
|
{
|
|
|
|
struct class_member *pos;
|
|
|
|
int printed = 0;
|
|
|
|
|
2006-12-24 02:34:42 +01:00
|
|
|
if (class->visited)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Ok, lets look at the previous CUs: */
|
|
|
|
if (cus__find_definition(self, class->name) != NULL) {
|
|
|
|
class->visited = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
cus__add_definition(self, class);
|
|
|
|
|
2006-12-23 22:29:27 +01:00
|
|
|
list_for_each_entry(pos, &class->members, tag.node)
|
|
|
|
if (cus__emit_tag_definitions(self, class->cu, &pos->tag))
|
|
|
|
printed = 1;
|
|
|
|
|
|
|
|
if (printed)
|
|
|
|
putchar('\n');
|
|
|
|
|
|
|
|
class__find_holes(class);
|
2006-12-29 18:28:58 +01:00
|
|
|
tag__print(&class->tag, class->cu, prefix, suffix);
|
|
|
|
class->visited = 1;
|
2006-12-23 22:29:27 +01:00
|
|
|
putchar('\n');
|
|
|
|
return 1;
|
|
|
|
}
|