2006-12-14 16:18:07 +01:00
|
|
|
/*
|
2019-01-15 18:28:24 +01:00
|
|
|
SPDX-License-Identifier: GPL-2.0-only
|
|
|
|
|
2006-10-28 23:22:42 +02:00
|
|
|
Copyright (C) 2006 Mandriva Conectiva S.A.
|
|
|
|
Copyright (C) 2006 Arnaldo Carvalho de Melo <acme@mandriva.com>
|
2007-02-15 14:36:49 +01:00
|
|
|
Copyright (C) 2007 Red Hat Inc.
|
|
|
|
Copyright (C) 2007 Arnaldo Carvalho de Melo <acme@redhat.com>
|
2006-10-28 23:22:42 +02:00
|
|
|
*/
|
|
|
|
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
#include <assert.h>
|
2006-12-27 17:57:19 +01:00
|
|
|
#include <dirent.h>
|
2006-10-28 23:22:42 +02:00
|
|
|
#include <dwarf.h>
|
2007-03-28 17:54:46 +02:00
|
|
|
#include <errno.h>
|
2006-10-28 23:22:42 +02:00
|
|
|
#include <fcntl.h>
|
2006-12-27 17:57:19 +01:00
|
|
|
#include <fnmatch.h>
|
2006-10-28 23:22:42 +02:00
|
|
|
#include <libelf.h>
|
2006-11-04 21:37:23 +01:00
|
|
|
#include <search.h>
|
2006-10-28 23:22:42 +02:00
|
|
|
#include <stdio.h>
|
2017-11-24 15:24:16 +01:00
|
|
|
#include <stdarg.h>
|
2006-10-28 23:22:42 +02:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
2010-06-04 14:26:13 +02:00
|
|
|
#include <sys/stat.h>
|
2017-11-24 15:24:16 +01:00
|
|
|
#include <sys/utsname.h>
|
2006-10-28 23:22:42 +02:00
|
|
|
|
2008-02-13 00:08:49 +01:00
|
|
|
#include "config.h"
|
2006-10-28 23:22:42 +02:00
|
|
|
#include "list.h"
|
2007-01-11 19:07:05 +01:00
|
|
|
#include "dwarves.h"
|
2007-12-16 17:47:59 +01:00
|
|
|
#include "dutil.h"
|
2008-10-02 19:34:42 +02:00
|
|
|
#include "strings.h"
|
2009-07-08 21:37:37 +02:00
|
|
|
#include <obstack.h>
|
|
|
|
|
|
|
|
#define obstack_chunk_alloc malloc
|
|
|
|
#define obstack_chunk_free free
|
2008-10-02 19:34:42 +02:00
|
|
|
|
dwarves: Revamp bit/byte holes detection logic
This patch rewrites hole detection logic. Now many crazy combinations of
bitfields and normal fields are handled correctly.
This was tested on allyesconfig kernel and differences before/after were
always in favor of new algorithm.
With subsequent change in next patch, there are no more BRAIN FART
ALERTs for allyesconfig and DWARF and BTF outputs have no discrepanies.
Example:
$ cat test.c
struct s {
short : 4; /* this one is not emitted in DWARF/BTF */
short a : 4;
int x;
int : 10;
int y : 4;
short zz;
short zzz : 4;
long z;
short : 4;
};
int main() {
struct s s;
return 0;
}
$ gcc -g test.c -o test
$ ~/pahole/build/pahole -J test
$ ~/pahole/build/pahole -F dwarf test
struct s {
/* XXX 4 bits hole, try to pack */
short int a:4; /* 0: 8 2 */
/* XXX 8 bits hole, try to pack */
/* XXX 2 bytes hole, try to pack */
int x; /* 4 4 */
/* XXX 10 bits hole, try to pack */
int y:4; /* 8:18 4 */
/* Bitfield combined with next fields */
/* XXX 2 bits hole, try to pack */
short int zz; /* 10 2 */
short int zzz:4; /* 12:12 2 */
/* XXX 12 bits hole, try to pack */
/* XXX 2 bytes hole, try to pack */
long int z; /* 16 8 */
/* size: 32, cachelines: 1, members: 6 */
/* sum members (bits): 124, holes: 2, sum holes: 4 */
/* bit holes: 5, sum bit holes: 36 bits */
/* padding: 8 */
/* last cacheline: 32 bytes */
};
No discrepanies between BTF/DWARF:
$ ../btfdiff test
$
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Mark Wielaard <mark@klomp.org>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-03-18 05:23:39 +01:00
|
|
|
#define min(x, y) ((x) < (y) ? (x) : (y))
|
|
|
|
|
2020-06-24 19:14:33 +02:00
|
|
|
int tag__is_base_type(const struct tag *tag, const struct cu *cu)
|
|
|
|
{
|
|
|
|
switch (tag->tag) {
|
|
|
|
case DW_TAG_base_type:
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
case DW_TAG_typedef: {
|
|
|
|
const struct tag *type = cu__type(cu, tag->type);
|
|
|
|
|
|
|
|
if (type == NULL)
|
|
|
|
return 0;
|
|
|
|
return tag__is_base_type(type, cu);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-06-25 13:45:17 +02:00
|
|
|
bool tag__is_array(const struct tag *tag, const struct cu *cu)
|
|
|
|
{
|
|
|
|
switch (tag->tag) {
|
|
|
|
case DW_TAG_array_type:
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case DW_TAG_const_type:
|
|
|
|
case DW_TAG_typedef: {
|
|
|
|
const struct tag *type = cu__type(cu, tag->type);
|
|
|
|
|
|
|
|
if (type == NULL)
|
|
|
|
return 0;
|
|
|
|
return tag__is_array(type, cu);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
const char *cu__string(const struct cu *cu, strings_t s)
|
2008-10-02 19:34:42 +02:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
if (cu->dfops && cu->dfops->strings__ptr)
|
|
|
|
return cu->dfops->strings__ptr(cu, s);
|
2009-04-02 23:46:54 +02:00
|
|
|
return NULL;
|
2009-04-02 22:54:43 +02:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static inline const char *s(const struct cu *cu, strings_t i)
|
2009-04-02 22:54:43 +02:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
return cu__string(cu, i);
|
2008-10-02 19:34:42 +02:00
|
|
|
}
|
2006-10-28 23:22:42 +02:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
int __tag__has_type_loop(const struct tag *tag, const struct tag *type,
|
2009-09-14 22:07:02 +02:00
|
|
|
char *bf, size_t len, FILE *fp,
|
|
|
|
const char *fn, int line)
|
|
|
|
{
|
|
|
|
char bbf[2048], *abf = bbf;
|
|
|
|
|
2009-09-14 22:39:52 +02:00
|
|
|
if (type == NULL)
|
|
|
|
return 0;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
if (tag->type == type->type) {
|
2009-09-14 22:07:02 +02:00
|
|
|
int printed;
|
|
|
|
|
|
|
|
if (bf != NULL)
|
|
|
|
abf = bf;
|
|
|
|
else
|
|
|
|
len = sizeof(bbf);
|
|
|
|
printed = snprintf(abf, len, "<ERROR(%s:%d): detected type loop: type=%d, tag=%s>",
|
2012-08-17 23:47:15 +02:00
|
|
|
fn, line, tag->type, dwarf_tag_name(tag->tag));
|
2009-09-14 22:07:02 +02:00
|
|
|
if (bf == NULL)
|
|
|
|
printed = fprintf(fp ?: stderr, "%s\n", abf);
|
|
|
|
return printed;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void lexblock__delete_tags(struct tag *tag, struct cu *cu)
|
2009-03-25 18:54:02 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
struct lexblock *block = tag__lexblock(tag);
|
2009-03-25 18:54:02 +01:00
|
|
|
struct tag *pos, *n;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
list_for_each_entry_safe_reverse(pos, n, &block->tags, node) {
|
2009-03-25 18:54:02 +01:00
|
|
|
list_del_init(&pos->node);
|
2009-08-18 23:21:20 +02:00
|
|
|
tag__delete(pos, cu);
|
2009-03-25 18:54:02 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
void lexblock__delete(struct lexblock *block, struct cu *cu)
|
2009-03-25 18:54:02 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
lexblock__delete_tags(&block->ip.tag, cu);
|
|
|
|
obstack_free(&cu->obstack, block);
|
2009-03-25 18:54:02 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
void tag__delete(struct tag *tag, struct cu *cu)
|
2008-01-14 23:04:57 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
assert(list_empty(&tag->node));
|
2009-03-25 17:06:29 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
switch (tag->tag) {
|
2009-03-25 17:06:29 +01:00
|
|
|
case DW_TAG_union_type:
|
2012-08-17 23:47:15 +02:00
|
|
|
type__delete(tag__type(tag), cu); break;
|
2009-03-25 17:06:29 +01:00
|
|
|
case DW_TAG_class_type:
|
|
|
|
case DW_TAG_structure_type:
|
2012-08-17 23:47:15 +02:00
|
|
|
class__delete(tag__class(tag), cu); break;
|
2009-03-25 17:06:29 +01:00
|
|
|
case DW_TAG_enumeration_type:
|
2012-08-17 23:47:15 +02:00
|
|
|
enumeration__delete(tag__type(tag), cu); break;
|
2009-03-25 17:06:29 +01:00
|
|
|
case DW_TAG_subroutine_type:
|
2012-08-17 23:47:15 +02:00
|
|
|
ftype__delete(tag__ftype(tag), cu); break;
|
2009-03-25 18:54:02 +01:00
|
|
|
case DW_TAG_subprogram:
|
2012-08-17 23:47:15 +02:00
|
|
|
function__delete(tag__function(tag), cu); break;
|
2009-03-25 18:54:02 +01:00
|
|
|
case DW_TAG_lexical_block:
|
2012-08-17 23:47:15 +02:00
|
|
|
lexblock__delete(tag__lexblock(tag), cu); break;
|
2009-03-25 17:06:29 +01:00
|
|
|
default:
|
2012-08-17 23:47:15 +02:00
|
|
|
obstack_free(&cu->obstack, tag);
|
2009-03-25 17:06:29 +01:00
|
|
|
}
|
2008-01-14 23:04:57 +01:00
|
|
|
}
|
|
|
|
|
2008-04-20 23:56:36 +02:00
|
|
|
void tag__not_found_die(const char *file, int line, const char *func)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "%s::%s(%d): tag not found, please report to "
|
2016-06-28 19:24:41 +02:00
|
|
|
"acme@kernel.org\n", file, func, line);
|
2008-04-20 23:56:36 +02:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2009-03-23 20:30:20 +01:00
|
|
|
struct tag *tag__follow_typedef(const struct tag *tag, const struct cu *cu)
|
2008-01-15 00:36:30 +01:00
|
|
|
{
|
2009-03-18 16:17:07 +01:00
|
|
|
struct tag *type = cu__type(cu, tag->type);
|
2008-01-15 00:36:30 +01:00
|
|
|
|
2008-09-30 19:21:03 +02:00
|
|
|
if (type != NULL && tag__is_typedef(type))
|
2008-01-15 00:36:30 +01:00
|
|
|
return tag__follow_typedef(type, cu);
|
|
|
|
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
loaders: Strip away volatile/const/restrict when fixing bitfields
btf_loader and ctf_loader didn't remove const/volatile/restrict, so
bitfields using modifiers were not adjusted properly.
This patch abstracts logic of stripping aways typedefs and access
modifiers into tag__strip_typedefs_and_modifiers, which handles any
interleaving of typedefs and modifiers. dwarf_loader was adapter to
reuse this function as well, instead of custom goto loop.
REPRO:
$ cat vc_map.c
typedef unsigned int u32;
typedef volatile u32 vu32;
typedef vu32 vu32_t;
typedef struct vc_map {
volatile unsigned int tx: 1;
vu32_t rx: 1;
void *x1, *x2;
} vc_map;
int main() {
struct vc_map s;
return 0;
}
BEFORE:
$ ~/pahole/build/pahole -F btf vc_map
struct vc_map {
volatile unsigned int tx:1; /* 0: 0 4 */
vu32_t rx:1; /* 0: 0 4 */
/* XXX 30 bits hole, try to pack */
/* XXX 4 bytes hole, try to pack */
void * x1; /* 8 8 */
void * x2; /* 16 8 */
/* size: 24, cachelines: 1, members: 4 */
/* sum members: 20, holes: 1, sum holes: 4 */
/* bit holes: 1, sum bit holes: 30 bits */
/* last cacheline: 24 bytes */
};
AFTER:
$ ~/pahole/build/pahole -F btf vc_map
struct vc_map {
volatile unsigned int tx:1; /* 0:31 4 */
vu32_t rx:1; /* 0:30 4 */
/* XXX 30 bits hole, try to pack */
/* XXX 4 bytes hole, try to pack */
void * x1; /* 8 8 */
void * x2; /* 16 8 */
/* size: 24, cachelines: 1, members: 4 */
/* sum members: 20, holes: 1, sum holes: 4 */
/* bit holes: 1, sum bit holes: 30 bits */
/* last cacheline: 24 bytes */
};
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-03-13 17:53:01 +01:00
|
|
|
struct tag *tag__strip_typedefs_and_modifiers(const struct tag *tag, const struct cu *cu)
|
|
|
|
{
|
|
|
|
struct tag *type = cu__type(cu, tag->type);
|
|
|
|
|
|
|
|
while (type != NULL && (tag__is_typedef(type) || tag__is_modifier(type)))
|
|
|
|
type = cu__type(cu, type->type);
|
|
|
|
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
2019-03-07 22:04:20 +01:00
|
|
|
size_t __tag__id_not_found_fprintf(FILE *fp, type_id_t id,
|
2009-09-11 20:10:43 +02:00
|
|
|
const char *fn, int line)
|
2007-01-12 19:11:37 +01:00
|
|
|
{
|
2009-09-14 22:55:20 +02:00
|
|
|
return fprintf(fp, "<ERROR(%s:%d): %d not found!>\n", fn, line, id);
|
2007-01-12 19:11:37 +01:00
|
|
|
}
|
|
|
|
|
2009-03-18 15:48:40 +01:00
|
|
|
static struct base_type_name_to_size {
|
|
|
|
const char *name;
|
|
|
|
strings_t sname;
|
|
|
|
size_t size;
|
|
|
|
} base_type_name_to_size_table[] = {
|
|
|
|
{ .name = "unsigned", .size = 32, },
|
|
|
|
{ .name = "signed int", .size = 32, },
|
|
|
|
{ .name = "unsigned int", .size = 32, },
|
|
|
|
{ .name = "int", .size = 32, },
|
|
|
|
{ .name = "short unsigned int", .size = 16, },
|
|
|
|
{ .name = "signed short", .size = 16, },
|
|
|
|
{ .name = "unsigned short", .size = 16, },
|
|
|
|
{ .name = "short int", .size = 16, },
|
pahole: Complete list of base type names
clang seems to generate base type with name "short", instead of "short
in", but it also isn't inconceivable to imagine other compilers
generating just "long" and/or "long long". This patch adds all those
short forms to a list of base type names.
$ cat type_test.c
struct s {
short x1;
long x2;
long long x3;
};
int main() {
struct s s;
return 0;
}
$ clang -g type_test.c -o type_test && ~/local/pahole/build/pahole -JV type_test
File type_test:
[1] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
[2] STRUCT s kind_flag=0 size=24 vlen=3
x1 type_id=3 bits_offset=0
x2 type_id=4 bits_offset=64
x3 type_id=5 bits_offset=128
[3] INT short size=2 bit_offset=0 nr_bits=16 encoding=SIGNED
[4] INT long int size=8 bit_offset=0 nr_bits=64 encoding=SIGNED
[5] INT long long int size=8 bit_offset=0 nr_bits=64 encoding=SIGNED
Before:
$ ~/local/pahole/build/pahole -F btf type_test
base_type__name_to_size: base_type short
class__fixup_btf_bitfields: unknown base type name "short"!
struct s {
short x1; /* 0 0 */
/* XXX 8 bytes hole, try to pack */
long int x2; /* 8 8 */
long long int x3; /* 16 8 */
/* size: 24, cachelines: 1, members: 3 */
/* sum members: 16, holes: 1, sum holes: 8 */
/* last cacheline: 24 bytes */
};
After:
$ ~/local/pahole/build/pahole -F btf type_test
struct s {
short x1; /* 0 2 */
/* XXX 6 bytes hole, try to pack */
long int x2; /* 8 8 */
long long int x3; /* 16 8 */
/* size: 24, cachelines: 1, members: 3 */
/* sum members: 18, holes: 1, sum holes: 6 */
/* last cacheline: 24 bytes */
};
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-02-20 21:57:31 +01:00
|
|
|
{ .name = "short", .size = 16, },
|
2009-03-18 15:48:40 +01:00
|
|
|
{ .name = "char", .size = 8, },
|
|
|
|
{ .name = "signed char", .size = 8, },
|
|
|
|
{ .name = "unsigned char", .size = 8, },
|
|
|
|
{ .name = "signed long", .size = 0, },
|
|
|
|
{ .name = "long int", .size = 0, },
|
pahole: Complete list of base type names
clang seems to generate base type with name "short", instead of "short
in", but it also isn't inconceivable to imagine other compilers
generating just "long" and/or "long long". This patch adds all those
short forms to a list of base type names.
$ cat type_test.c
struct s {
short x1;
long x2;
long long x3;
};
int main() {
struct s s;
return 0;
}
$ clang -g type_test.c -o type_test && ~/local/pahole/build/pahole -JV type_test
File type_test:
[1] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
[2] STRUCT s kind_flag=0 size=24 vlen=3
x1 type_id=3 bits_offset=0
x2 type_id=4 bits_offset=64
x3 type_id=5 bits_offset=128
[3] INT short size=2 bit_offset=0 nr_bits=16 encoding=SIGNED
[4] INT long int size=8 bit_offset=0 nr_bits=64 encoding=SIGNED
[5] INT long long int size=8 bit_offset=0 nr_bits=64 encoding=SIGNED
Before:
$ ~/local/pahole/build/pahole -F btf type_test
base_type__name_to_size: base_type short
class__fixup_btf_bitfields: unknown base type name "short"!
struct s {
short x1; /* 0 0 */
/* XXX 8 bytes hole, try to pack */
long int x2; /* 8 8 */
long long int x3; /* 16 8 */
/* size: 24, cachelines: 1, members: 3 */
/* sum members: 16, holes: 1, sum holes: 8 */
/* last cacheline: 24 bytes */
};
After:
$ ~/local/pahole/build/pahole -F btf type_test
struct s {
short x1; /* 0 2 */
/* XXX 6 bytes hole, try to pack */
long int x2; /* 8 8 */
long long int x3; /* 16 8 */
/* size: 24, cachelines: 1, members: 3 */
/* sum members: 18, holes: 1, sum holes: 6 */
/* last cacheline: 24 bytes */
};
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-02-20 21:57:31 +01:00
|
|
|
{ .name = "long", .size = 0, },
|
2009-03-18 15:48:40 +01:00
|
|
|
{ .name = "signed long", .size = 0, },
|
|
|
|
{ .name = "unsigned long", .size = 0, },
|
|
|
|
{ .name = "long unsigned int", .size = 0, },
|
|
|
|
{ .name = "bool", .size = 8, },
|
|
|
|
{ .name = "_Bool", .size = 8, },
|
|
|
|
{ .name = "long long unsigned int", .size = 64, },
|
|
|
|
{ .name = "long long int", .size = 64, },
|
pahole: Complete list of base type names
clang seems to generate base type with name "short", instead of "short
in", but it also isn't inconceivable to imagine other compilers
generating just "long" and/or "long long". This patch adds all those
short forms to a list of base type names.
$ cat type_test.c
struct s {
short x1;
long x2;
long long x3;
};
int main() {
struct s s;
return 0;
}
$ clang -g type_test.c -o type_test && ~/local/pahole/build/pahole -JV type_test
File type_test:
[1] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
[2] STRUCT s kind_flag=0 size=24 vlen=3
x1 type_id=3 bits_offset=0
x2 type_id=4 bits_offset=64
x3 type_id=5 bits_offset=128
[3] INT short size=2 bit_offset=0 nr_bits=16 encoding=SIGNED
[4] INT long int size=8 bit_offset=0 nr_bits=64 encoding=SIGNED
[5] INT long long int size=8 bit_offset=0 nr_bits=64 encoding=SIGNED
Before:
$ ~/local/pahole/build/pahole -F btf type_test
base_type__name_to_size: base_type short
class__fixup_btf_bitfields: unknown base type name "short"!
struct s {
short x1; /* 0 0 */
/* XXX 8 bytes hole, try to pack */
long int x2; /* 8 8 */
long long int x3; /* 16 8 */
/* size: 24, cachelines: 1, members: 3 */
/* sum members: 16, holes: 1, sum holes: 8 */
/* last cacheline: 24 bytes */
};
After:
$ ~/local/pahole/build/pahole -F btf type_test
struct s {
short x1; /* 0 2 */
/* XXX 6 bytes hole, try to pack */
long int x2; /* 8 8 */
long long int x3; /* 16 8 */
/* size: 24, cachelines: 1, members: 3 */
/* sum members: 18, holes: 1, sum holes: 6 */
/* last cacheline: 24 bytes */
};
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-02-20 21:57:31 +01:00
|
|
|
{ .name = "long long", .size = 64, },
|
2009-03-18 15:48:40 +01:00
|
|
|
{ .name = "signed long long", .size = 64, },
|
|
|
|
{ .name = "unsigned long long", .size = 64, },
|
|
|
|
{ .name = "double", .size = 64, },
|
|
|
|
{ .name = "double double", .size = 64, },
|
2009-03-20 17:38:03 +01:00
|
|
|
{ .name = "single float", .size = 32, },
|
|
|
|
{ .name = "float", .size = 32, },
|
dwarves: Fixup sizeof(long double) in bits in base_type_name_to_size table
We were erroneously setting it to 64 bits everywhere, i.e. 8 bytes, when
it in fact is 16 bytes, 128 bits, as we can see with:
$ btfdiff libc-2.28.so.debug
--- /tmp/btfdiff.dwarf.RuqA9q 2019-02-26 10:25:49.828150761 -0300
+++ /tmp/btfdiff.btf.t3XqV6 2019-02-26 10:25:49.835150835 -0300
@@ -461,9 +461,15 @@ struct La_x86_64_retval {
uint64_t lrv_rdx; /* 8 8 */
La_x86_64_xmm lrv_xmm0; /* 16 16 */
La_x86_64_xmm lrv_xmm1; /* 32 16 */
- long double lrv_st0; /* 48 16 */
+ long double lrv_st0; /* 48 8 */
+
+ /* XXX 8 bytes hole, try to pack */
+
/* --- cacheline 1 boundary (64 bytes) --- */
- long double lrv_st1; /* 64 16 */
+ long double lrv_st1; /* 64 8 */
+
+ /* XXX 8 bytes hole, try to pack */
+
La_x86_64_vector lrv_vector0; /* 80 64 */
/* --- cacheline 2 boundary (128 bytes) was 16 bytes ago --- */
La_x86_64_vector lrv_vector1; /* 144 64 */
And:
$ cat long_double.c
#include <stdio.h>
int main(void)
{
return printf("sizeof(long double)=%zd\n", sizeof(long double));
}
$ ./long_double
sizeof(long double)=16
$ file long_double
long_double: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=c876603879d49905fbd7fc5907dc65ad3bca422f, not stripped
$
So use sizeof to at least match the running machine, this is
insufficient for cross-platform analysis, so a new fix is needed to
cover those cases, this at least improves the current situation a bit.
Reported-by: Andrii Nakryiko <andriin@fb.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Yonghong Song <yhs@fb.com>
link: https://lore.kernel.org/bpf/20190226131156.GA26786@kernel.org/
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-02-26 14:26:14 +01:00
|
|
|
{ .name = "long double", .size = sizeof(long double) * 8, },
|
|
|
|
{ .name = "long double long double", .size = sizeof(long double) * 8, },
|
dwarves: add __int128 types in base_type_name_to_size
Added int128 types to dwarf base_type_name_to_size table
so that the correct base type size can be retrieved in certain
cases. Note that for type "unsigned __int128", the dwarf in gcc
has type name "__int128 unsigned" while clang has
"unsigned __int128".
-bash-4.4$ cat t.c
struct t {
__int128 si128a;
__int128 si128b;
unsigned __int128 bits3:3;
unsigned __int128 bits80:80;
unsigned __int128 ui128;
} g;
-bash-4.4$ clang -O2 -c -g -target bpf -Xclang -target-feature -Xclang +dwarfris t.c
-bash-4.4$ pahole -F dwarf t.o
struct t {
__int128 si128a; /* 0 16 */
__int128 si128b; /* 16 16 */
unsigned __int128 bits3:3; /* 32:125 16 */
unsigned __int128 bits80:80; /* 32:45 16 */
/* XXX 45 bits hole, try to pack */
unsigned __int128 ui128; /* 48 16 */
/* size: 64, cachelines: 1, members: 5 */
/* bit holes: 1, sum bit holes: 45 bits */
};
-bash-4.4$ pahole -F btf t.o
struct t {
__int128 si128a; /* 0 16 */
__int128 si128b; /* 16 16 */
unsigned __int128 bits3:3; /* 32:125 16 */
unsigned __int128 bits80:80; /* 32:45 16 */
/* XXX 45 bits hole, try to pack */
unsigned __int128 ui128; /* 48 16 */
/* size: 64, cachelines: 1, members: 5 */
/* bit holes: 1, sum bit holes: 45 bits */
};
-bash-4.4$ pahole -JV t.o
File t.o:
[1] STRUCT t kind_flag=1 size=64 vlen=5
si128a type_id=2 bitfield_size=0 bits_offset=0
si128b type_id=2 bitfield_size=0 bits_offset=128
bits3 type_id=3 bitfield_size=3 bits_offset=256
bits80 type_id=3 bitfield_size=80 bits_offset=259
ui128 type_id=3 bitfield_size=0 bits_offset=384
[2] INT __int128 size=16 bit_offset=0 nr_bits=128 encoding=SIGNED
[3] INT unsigned __int128 size=16 bit_offset=0 nr_bits=128 encoding=(none)
[4] INT (anon) size=4 bit_offset=0 nr_bits=32 encoding=(none)
-bash-4.4$
Committer testing:
Before:
$ cat __int128.c
struct t {
__int128 si128a;
__int128 si128b;
unsigned __int128 bits3:3;
unsigned __int128 bits80:80;
unsigned __int128 ui128;
} g;
$ clang -O2 -c -g -target bpf -Xclang -target-feature -Xclang +dwarfris __int128.c
$ pahole __int128.o
base_type__name_to_size: base_type unsigned __int128
base_type__name_to_size: base_type unsigned __int128
struct t {
__int128 si128a; /* 0 16 */
__int128 si128b; /* 16 16 */
unsigned __int128 bits3:3; /* 32:125 0 */
unsigned __int128 bits80:80; /* 32:45 0 */
/* XXX 173 bits hole, try to pack */
/* XXX 16 bytes hole, try to pack */
unsigned __int128 ui128; /* 48 16 */
/* size: 64, cachelines: 1, members: 5 */
/* sum members: 48, holes: 1, sum holes: 16 */
/* bit holes: 1, sum bit holes: 173 bits */
};
$ pahole -J __int128.o
base_type__name_to_size: base_type unsigned __int128
base_type__name_to_size: base_type unsigned __int128
After:
$ pahole -F dwarf __int128.o
struct t {
__int128 si128a; /* 0 16 */
__int128 si128b; /* 16 16 */
unsigned __int128 bits3:3; /* 32:125 16 */
unsigned __int128 bits80:80; /* 32:45 16 */
/* XXX 45 bits hole, try to pack */
unsigned __int128 ui128; /* 48 16 */
/* size: 64, cachelines: 1, members: 5 */
/* bit holes: 1, sum bit holes: 45 bits */
};
$
$ pahole -J __int128.o
$ pahole -F btf __int128.o
struct t {
__int128 si128a; /* 0 16 */
__int128 si128b; /* 16 16 */
unsigned __int128 bits3:3; /* 32:125 16 */
unsigned __int128 bits80:80; /* 32:45 16 */
/* XXX 45 bits hole, try to pack */
unsigned __int128 ui128; /* 48 16 */
/* size: 64, cachelines: 1, members: 5 */
/* bit holes: 1, sum bit holes: 45 bits */
};
$
Signed-off-by: Yonghong Song <yhs@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-01-10 20:39:06 +01:00
|
|
|
{ .name = "__int128", .size = 128, },
|
|
|
|
{ .name = "unsigned __int128", .size = 128, },
|
|
|
|
{ .name = "__int128 unsigned", .size = 128, },
|
2019-02-26 14:15:17 +01:00
|
|
|
{ .name = "_Float128", .size = 128, },
|
2009-03-18 15:48:40 +01:00
|
|
|
{ .name = NULL },
|
|
|
|
};
|
|
|
|
|
2009-04-02 23:46:54 +02:00
|
|
|
void base_type_name_to_size_table__init(struct strings *strings)
|
2009-03-18 15:48:40 +01:00
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
while (base_type_name_to_size_table[i].name != NULL) {
|
|
|
|
if (base_type_name_to_size_table[i].sname == 0)
|
|
|
|
base_type_name_to_size_table[i].sname =
|
|
|
|
strings__find(strings,
|
|
|
|
base_type_name_to_size_table[i].name);
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
size_t base_type__name_to_size(struct base_type *bt, struct cu *cu)
|
2009-03-18 15:48:40 +01:00
|
|
|
{
|
|
|
|
int i = 0;
|
2009-04-02 21:12:36 +02:00
|
|
|
char bf[64];
|
2018-12-20 18:53:50 +01:00
|
|
|
const char *name, *orig_name;
|
2009-04-02 21:12:36 +02:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
if (bt->name_has_encoding)
|
|
|
|
name = s(cu, bt->name);
|
2009-04-02 21:12:36 +02:00
|
|
|
else
|
2012-08-17 23:47:15 +02:00
|
|
|
name = base_type__name(bt, cu, bf, sizeof(bf));
|
2018-12-20 18:53:50 +01:00
|
|
|
orig_name = name;
|
|
|
|
try_again:
|
2009-03-18 15:48:40 +01:00
|
|
|
while (base_type_name_to_size_table[i].name != NULL) {
|
2012-08-17 23:47:15 +02:00
|
|
|
if (bt->name_has_encoding) {
|
|
|
|
if (base_type_name_to_size_table[i].sname == bt->name) {
|
2009-04-02 21:12:36 +02:00
|
|
|
size_t size;
|
|
|
|
found:
|
|
|
|
size = base_type_name_to_size_table[i].size;
|
2009-03-18 15:48:40 +01:00
|
|
|
|
2009-04-02 21:12:36 +02:00
|
|
|
return size ?: ((size_t)cu->addr_size * 8);
|
|
|
|
}
|
|
|
|
} else if (strcmp(base_type_name_to_size_table[i].name,
|
|
|
|
name) == 0)
|
|
|
|
goto found;
|
2009-03-18 15:48:40 +01:00
|
|
|
++i;
|
|
|
|
}
|
2018-12-20 18:53:50 +01:00
|
|
|
|
|
|
|
if (strstarts(name, "signed ")) {
|
|
|
|
i = 0;
|
|
|
|
name += sizeof("signed");
|
|
|
|
goto try_again;
|
|
|
|
}
|
|
|
|
|
2009-03-19 02:49:33 +01:00
|
|
|
fprintf(stderr, "%s: %s %s\n",
|
2018-12-20 18:53:50 +01:00
|
|
|
__func__, dwarf_tag_name(bt->tag.tag), orig_name);
|
2009-03-18 15:48:40 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-04-02 21:12:36 +02:00
|
|
|
static const char *base_type_fp_type_str[] = {
|
|
|
|
[BT_FP_SINGLE] = "single",
|
|
|
|
[BT_FP_DOUBLE] = "double",
|
|
|
|
[BT_FP_CMPLX] = "complex",
|
|
|
|
[BT_FP_CMPLX_DBL] = "complex double",
|
|
|
|
[BT_FP_CMPLX_LDBL] = "complex long double",
|
|
|
|
[BT_FP_LDBL] = "long double",
|
|
|
|
[BT_FP_INTVL] = "interval",
|
|
|
|
[BT_FP_INTVL_DBL] = "interval double",
|
|
|
|
[BT_FP_INTVL_LDBL] = "interval long double",
|
|
|
|
[BT_FP_IMGRY] = "imaginary",
|
|
|
|
[BT_FP_IMGRY_DBL] = "imaginary double",
|
|
|
|
[BT_FP_IMGRY_LDBL] = "imaginary long double",
|
|
|
|
};
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
const char *base_type__name(const struct base_type *bt, const struct cu *cu,
|
2009-04-02 22:54:43 +02:00
|
|
|
char *bf, size_t len)
|
2009-04-02 21:12:36 +02:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
if (bt->name_has_encoding)
|
|
|
|
return s(cu, bt->name);
|
2009-04-02 21:12:36 +02:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
if (bt->float_type)
|
2009-04-02 21:12:36 +02:00
|
|
|
snprintf(bf, len, "%s %s",
|
2012-08-17 23:47:15 +02:00
|
|
|
base_type_fp_type_str[bt->float_type],
|
|
|
|
s(cu, bt->name));
|
2009-04-02 21:12:36 +02:00
|
|
|
else
|
2018-12-20 18:55:38 +01:00
|
|
|
snprintf(bf, len, "%s%s%s",
|
2012-08-17 23:47:15 +02:00
|
|
|
bt->is_bool ? "bool " : "",
|
|
|
|
bt->is_varargs ? "... " : "",
|
|
|
|
s(cu, bt->name));
|
2009-04-02 21:12:36 +02:00
|
|
|
return bf;
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
void namespace__delete(struct namespace *space, struct cu *cu)
|
2008-01-14 23:04:57 +01:00
|
|
|
{
|
|
|
|
struct tag *pos, *n;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
namespace__for_each_tag_safe_reverse(space, pos, n) {
|
2008-01-14 23:04:57 +01:00
|
|
|
list_del_init(&pos->node);
|
|
|
|
|
|
|
|
/* Look for nested namespaces */
|
2009-03-03 13:38:27 +01:00
|
|
|
if (tag__has_namespace(pos))
|
2009-08-18 23:21:20 +02:00
|
|
|
namespace__delete(tag__namespace(pos), cu);
|
|
|
|
tag__delete(pos, cu);
|
2008-01-14 23:04:57 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
tag__delete(&space->tag, cu);
|
2008-01-14 23:04:57 +01:00
|
|
|
}
|
|
|
|
|
2008-01-13 18:18:39 +01:00
|
|
|
struct class_member *
|
2012-08-17 23:47:15 +02:00
|
|
|
type__find_first_biggest_size_base_type_member(struct type *type,
|
2008-01-13 18:18:39 +01:00
|
|
|
const struct cu *cu)
|
|
|
|
{
|
|
|
|
struct class_member *pos, *result = NULL;
|
|
|
|
size_t result_size = 0;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
type__for_each_data_member(type, pos) {
|
2012-08-20 19:42:17 +02:00
|
|
|
if (pos->is_static)
|
|
|
|
continue;
|
|
|
|
|
2009-03-18 16:17:07 +01:00
|
|
|
struct tag *type = cu__type(cu, pos->tag.type);
|
2008-01-13 18:18:39 +01:00
|
|
|
size_t member_size = 0, power2;
|
|
|
|
struct class_member *inner = NULL;
|
2008-04-20 23:56:36 +02:00
|
|
|
|
|
|
|
if (type == NULL) {
|
2008-04-21 20:57:34 +02:00
|
|
|
tag__id_not_found_fprintf(stderr, pos->tag.type);
|
2008-04-20 23:56:36 +02:00
|
|
|
continue;
|
|
|
|
}
|
2008-01-13 18:18:39 +01:00
|
|
|
reevaluate:
|
|
|
|
switch (type->tag) {
|
|
|
|
case DW_TAG_base_type:
|
2008-03-04 22:38:21 +01:00
|
|
|
member_size = base_type__size(type);
|
2008-01-13 18:18:39 +01:00
|
|
|
break;
|
|
|
|
case DW_TAG_pointer_type:
|
|
|
|
case DW_TAG_reference_type:
|
|
|
|
member_size = cu->addr_size;
|
|
|
|
break;
|
2008-04-21 03:12:03 +02:00
|
|
|
case DW_TAG_class_type:
|
2008-01-13 18:18:39 +01:00
|
|
|
case DW_TAG_union_type:
|
|
|
|
case DW_TAG_structure_type:
|
2008-01-13 19:04:09 +01:00
|
|
|
if (tag__type(type)->nr_members == 0)
|
|
|
|
continue;
|
2008-01-13 18:18:39 +01:00
|
|
|
inner = type__find_first_biggest_size_base_type_member(tag__type(type), cu);
|
2009-03-17 18:31:18 +01:00
|
|
|
member_size = inner->byte_size;
|
2008-01-13 18:18:39 +01:00
|
|
|
break;
|
|
|
|
case DW_TAG_array_type:
|
2008-01-13 18:42:33 +01:00
|
|
|
case DW_TAG_const_type:
|
2008-01-13 18:18:39 +01:00
|
|
|
case DW_TAG_typedef:
|
2016-03-15 20:37:48 +01:00
|
|
|
case DW_TAG_rvalue_reference_type:
|
2008-04-20 23:56:36 +02:00
|
|
|
case DW_TAG_volatile_type: {
|
2009-04-02 18:33:05 +02:00
|
|
|
struct tag *tag = cu__type(cu, type->type);
|
dwarves: Fix check in type__find_first_biggest_size_base_type_member()
We stopped scrubbing type when looking for type->type by assigning the
result of cu__type(cu, type->type) to a temporary 'tag' variable but
continued to check the result of cu__type() looking at type... Check
'tag' instead.
Addresses these coverity report entries:
Error: NULL_RETURNS (CWE-476): [#def9]
dwarves-1.13/dwarves.c:333: returned_null: "cu__type" returns "NULL" (checked 54 out of 62 times).
dwarves-1.13/dwarves.c:333: var_assigned: Assigning: "tag" = "NULL" return value from "cu__type".
dwarves-1.13/dwarves.c:338: alias: Assigning: "type" = "tag". Both pointers are now "NULL".
dwarves-1.13/dwarves.c:312: dereference: Dereferencing "type", which is known to be "NULL".
dwarves-1.13/codiff.c:137: example_assign: Example 1: Assigning: "old_type" = return value from "cu__type(old_cu, old->tag.type)".
dwarves-1.13/codiff.c:141: example_checked: Example 1 (cont.): "old_type" has its value checked in "old_type == NULL".
dwarves-1.13/ctracer.c:356: example_assign: Example 2: Assigning: "type" = return value from "cu__type(cu, tag->type)".
dwarves-1.13/ctracer.c:358: example_checked: Example 2 (cont.): "type" has its value checked in "type == NULL".
dwarves-1.13/dwarves.c:914: example_assign: Example 3: Assigning: "type" = return value from "cu__type(cu, tag->type)".
dwarves-1.13/dwarves.c:916: example_checked: Example 3 (cont.): "type" has its value checked in "type == NULL".
dwarves-1.13/dwarves.c:941: example_assign: Example 4: Assigning: "tag" = return value from "cu__type(cu, var->ip.tag.type)".
dwarves-1.13/dwarves.c:942: example_checked: Example 4 (cont.): "tag" has its value checked in "tag != NULL".
dwarves-1.13/dwarves_emit.c:139: example_assign: Example 5: Assigning: "ptr_type" = return value from "cu__type(cu, type->type)".
dwarves-1.13/dwarves_emit.c:141: example_checked: Example 5 (cont.): "ptr_type" has its value checked in "ptr_type == NULL".
# 310| }
# 311| reevaluate:
# 312|-> switch (type->tag) {
# 313| case DW_TAG_base_type:
# 314|
Error: REVERSE_INULL (CWE-476): [#def10]
dwarves-1.13/dwarves.c:312: deref_ptr: Directly dereferencing pointer "type".
dwarves-1.13/dwarves.c:334: check_after_deref: Null-checking "type" suggests that it may be null, but it has already been dereferenced on all paths leading to the check.
# 332| case DW_TAG_volatile_type: {
# 333| struct tag *tag = cu__type(cu, type->type);
# 334|-> if (type == NULL) {
# 335| tag__id_not_found_fprintf(stderr, type->type);
# 336| continue;
Looking at this last one shows the problem in detail, check for NULL to
then deref it, phew.
This is just used in 'pahole --show_first_biggest_size_base_type_member'
and when fixing up alignment in the --reorganize code tho.
Reported-by: William Cohen <wcohen@redhat.com>
Fixes: 7fc7148be768 ("core: Fix thinko in type__find_first_biggest_size_base_type_member")
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-07-02 15:11:12 +02:00
|
|
|
if (tag == NULL) {
|
2009-04-02 18:33:05 +02:00
|
|
|
tag__id_not_found_fprintf(stderr, type->type);
|
2008-04-20 23:56:36 +02:00
|
|
|
continue;
|
|
|
|
}
|
2009-04-02 18:33:05 +02:00
|
|
|
type = tag;
|
2008-04-20 23:56:36 +02:00
|
|
|
}
|
2008-01-13 18:18:39 +01:00
|
|
|
goto reevaluate;
|
|
|
|
case DW_TAG_enumeration_type:
|
2009-03-19 03:01:32 +01:00
|
|
|
member_size = tag__type(type)->size / 8;
|
2008-01-13 18:18:39 +01:00
|
|
|
break;
|
|
|
|
}
|
2009-03-14 17:50:36 +01:00
|
|
|
|
2008-01-13 18:18:39 +01:00
|
|
|
/* long long */
|
|
|
|
if (member_size > cu->addr_size)
|
|
|
|
return pos;
|
|
|
|
|
|
|
|
for (power2 = cu->addr_size; power2 > result_size; power2 /= 2)
|
|
|
|
if (member_size >= power2) {
|
|
|
|
if (power2 == cu->addr_size)
|
|
|
|
return inner ?: pos;
|
|
|
|
result_size = power2;
|
|
|
|
result = inner ?: pos;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void cu__find_class_holes(struct cu *cu)
|
2009-03-06 15:48:33 +01:00
|
|
|
{
|
pahole: Use 32-bit integers for type ID iterations within CU
Existing code base assumes that single CU doesn't have more than 65535
types per each CU, which might be a reasonable assumption for DWARF
data. With BTF, though, all we get is single, potentially huge, CU which
can easily have more than 65k types. For example, this is the case for
allyesconfig version of Linux kernel, which has >200k types.
Due to this assumption, libdwarves and other parts of pahole are using
16-bit counters to iterate over entities within CU. This can cause
infinite loops when iterating BTF data, if there are more than 65535
types. This patch changes non-public variables to use 32-bit integers,
where appropriate.
This still leads to invalid reported data when using BTF loader (due to using
(X & 0xFFFF) type ID, instead of X, when X > 65535) and loading huge files,
but at least it's not stuck in an infinite loop anymore.
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Reported-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
[ Removed non type ID conversions, for instance for the kind of tag, like in type->namespace.tag.tag, that can remain a uint16_t ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-03-07 01:23:21 +01:00
|
|
|
uint32_t id;
|
2009-03-06 15:48:33 +01:00
|
|
|
struct class *pos;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
cu__for_each_struct(cu, id, pos)
|
2009-03-17 18:31:18 +01:00
|
|
|
class__find_holes(pos);
|
2009-03-06 15:48:33 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
void cus__add(struct cus *cus, struct cu *cu)
|
2006-10-31 20:12:42 +01:00
|
|
|
{
|
2019-04-08 16:54:06 +02:00
|
|
|
cus->nr_entries++;
|
2012-08-17 23:47:15 +02:00
|
|
|
list_add_tail(&cu->node, &cus->cus);
|
2009-03-06 15:48:33 +01:00
|
|
|
cu__find_class_holes(cu);
|
2006-10-31 20:12:42 +01:00
|
|
|
}
|
2009-03-14 17:50:36 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void ptr_table__init(struct ptr_table *pt)
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
pt->entries = NULL;
|
|
|
|
pt->nr_entries = pt->allocated_entries = 0;
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void ptr_table__exit(struct ptr_table *pt)
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
free(pt->entries);
|
|
|
|
pt->entries = NULL;
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
}
|
|
|
|
|
2019-03-07 15:58:06 +01:00
|
|
|
static int ptr_table__add(struct ptr_table *pt, void *ptr, uint32_t *idxp)
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
const uint32_t nr_entries = pt->nr_entries + 1;
|
2019-03-07 15:58:06 +01:00
|
|
|
const uint32_t rc = pt->nr_entries;
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
if (nr_entries > pt->allocated_entries) {
|
|
|
|
uint32_t allocated_entries = pt->allocated_entries + 256;
|
|
|
|
void *entries = realloc(pt->entries,
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
sizeof(void *) * allocated_entries);
|
|
|
|
if (entries == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
pt->allocated_entries = allocated_entries;
|
|
|
|
pt->entries = entries;
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
pt->entries[rc] = ptr;
|
|
|
|
pt->nr_entries = nr_entries;
|
2019-03-07 15:58:06 +01:00
|
|
|
*idxp = rc;
|
|
|
|
return 0;
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static int ptr_table__add_with_id(struct ptr_table *pt, void *ptr,
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
uint32_t id)
|
|
|
|
{
|
|
|
|
/* Assume we won't be fed with the same id more than once */
|
2012-08-17 23:47:15 +02:00
|
|
|
if (id >= pt->allocated_entries) {
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
uint32_t allocated_entries = roundup(id + 1, 256);
|
2012-08-17 23:47:15 +02:00
|
|
|
void *entries = realloc(pt->entries,
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
sizeof(void *) * allocated_entries);
|
|
|
|
if (entries == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2019-12-13 16:20:42 +01:00
|
|
|
/* Zero out the new range */
|
|
|
|
memset(entries + pt->allocated_entries * sizeof(void *), 0,
|
|
|
|
(allocated_entries - pt->allocated_entries) * sizeof(void *));
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
pt->allocated_entries = allocated_entries;
|
|
|
|
pt->entries = entries;
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
pt->entries[id] = ptr;
|
dwarves: Fix ptr_table__add_with_id() handling of pt->nr_entries
To agree with what ptr_table__add() does, i.e. the number of entries
(pt->nr_entries) is in fact the max id number in the table + 1, we can't
allow to add an id that is not contiguous and simply increment
nr_entries, as cu__for_each_variable(cu, id, pos) will iterate based on
nr_entries, skipping NULL buckets.
Detected when adding support for BTF variables, that share the id space
with types, but end up in different ptr_tables, so we end up with:
cu__table_add_tag(BTF_KIND_VAR)
ptr_table__add_with_id(cu->tags_table)
but:
cu__table_add_tag()
ptr_table__add_with_id(cu->types_table)
for all the other BTF_KIND_s, fix it so that ptr->nr_entries copes with
not receiving strictly monotonically incremented by one ids.
We'll have to fix this more properly by defining which tags are
supported by some debugging format and this what should go to a
ptr_table so that we have all its entries monononically incremented by
one and avoid tag__check_id_drift() returning true in the per debugging
format encoders (e.g.: btf_encoder.c).
This patch allows us to move forward and apply the BTF_KIND_VAR patch
where we'll at least produce, for global variables and a simple BPF
program with both DWARF and BTF tags the same results:
[root@quaco tracebuffer]# pglobal -F dwarf -v bristot.o
struct ____btf_map_tracebuffer__bristot ____btf_map_tracebuffer__bristot;; /* 0 */
char _license[4];; /* 0 */
int _version;; /* 0 */
struct bpf_map tracebuffer__bristot;; /* 0 */
[root@quaco tracebuffer]# pglobal -F btf -v bristot.o
BTF: idx: 17, off: 352, Unknown kind 15
BTF: idx: 18, off: 364, Unknown kind 0
BTF: idx: 19, off: 376, Unknown kind 15
BTF: idx: 20, off: 388, Unknown kind 0
BTF: idx: 21, off: 400, Unknown kind 15
BTF: idx: 22, off: 412, Unknown kind 0
BTF: idx: 23, off: 424, Unknown kind 15
BTF: idx: 24, off: 436, Unknown kind 0
struct ____btf_map_tracebuffer__bristot ____btf_map_tracebuffer__bristot;; /* 0 */
char _license[4];; /* 0 */
int _version;; /* 0 */
struct bpf_map tracebuffer__bristot;; /* 0 */
[root@quaco tracebuffer]#
Cc: Andrii Nakryiko <andriin@fb.com>
Cc: Daniel Bristot de Oliveira <bristot@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Yonghong Song <yhs@fb.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-10-24 21:56:40 +02:00
|
|
|
if (id >= pt->nr_entries)
|
|
|
|
pt->nr_entries = id + 1;
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void *ptr_table__entry(const struct ptr_table *pt, uint32_t id)
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
return id >= pt->nr_entries ? NULL : pt->entries[id];
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void cu__insert_function(struct cu *cu, struct tag *tag)
|
2009-06-04 19:56:44 +02:00
|
|
|
{
|
|
|
|
struct function *function = tag__function(tag);
|
2012-08-17 23:47:15 +02:00
|
|
|
struct rb_node **p = &cu->functions.rb_node;
|
2009-06-04 19:56:44 +02:00
|
|
|
struct rb_node *parent = NULL;
|
|
|
|
struct function *f;
|
|
|
|
|
|
|
|
while (*p != NULL) {
|
|
|
|
parent = *p;
|
|
|
|
f = rb_entry(parent, struct function, rb_node);
|
2009-06-04 22:30:06 +02:00
|
|
|
if (function->lexblock.ip.addr < f->lexblock.ip.addr)
|
2009-06-04 19:56:44 +02:00
|
|
|
p = &(*p)->rb_left;
|
|
|
|
else
|
|
|
|
p = &(*p)->rb_right;
|
|
|
|
}
|
|
|
|
rb_link_node(&function->rb_node, parent, p);
|
2012-08-17 23:47:15 +02:00
|
|
|
rb_insert_color(&function->rb_node, &cu->functions);
|
2009-06-04 19:56:44 +02:00
|
|
|
}
|
|
|
|
|
2019-03-07 19:42:29 +01:00
|
|
|
int cu__table_add_tag(struct cu *cu, struct tag *tag, uint32_t *type_id)
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
struct ptr_table *pt = &cu->tags_table;
|
2009-06-04 19:56:44 +02:00
|
|
|
|
|
|
|
if (tag__is_tag_type(tag))
|
2012-08-17 23:47:15 +02:00
|
|
|
pt = &cu->types_table;
|
2009-06-04 19:56:44 +02:00
|
|
|
else if (tag__is_function(tag)) {
|
2012-08-17 23:47:15 +02:00
|
|
|
pt = &cu->functions_table;
|
|
|
|
cu__insert_function(cu, tag);
|
2009-06-04 19:56:44 +02:00
|
|
|
}
|
|
|
|
|
2019-03-07 19:42:29 +01:00
|
|
|
return ptr_table__add(pt, tag, type_id) ? -ENOMEM : 0;
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
int cu__table_nullify_type_entry(struct cu *cu, uint32_t id)
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
return ptr_table__add_with_id(&cu->types_table, NULL, id);
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
}
|
|
|
|
|
2019-03-07 19:42:29 +01:00
|
|
|
int cu__add_tag(struct cu *cu, struct tag *tag, uint32_t *id)
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
int err = cu__table_add_tag(cu, tag, id);
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
|
|
|
|
if (err == 0)
|
2012-08-17 23:47:15 +02:00
|
|
|
list_add_tail(&tag->node, &cu->tags);
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
2006-10-31 20:12:42 +01:00
|
|
|
|
2019-03-07 19:42:29 +01:00
|
|
|
int cu__table_add_tag_with_id(struct cu *cu, struct tag *tag, uint32_t id)
|
|
|
|
{
|
|
|
|
struct ptr_table *pt = &cu->tags_table;
|
|
|
|
|
|
|
|
if (tag__is_tag_type(tag)) {
|
|
|
|
pt = &cu->types_table;
|
|
|
|
} else if (tag__is_function(tag)) {
|
|
|
|
pt = &cu->functions_table;
|
|
|
|
cu__insert_function(cu, tag);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ptr_table__add_with_id(pt, tag, id);
|
|
|
|
}
|
|
|
|
|
|
|
|
int cu__add_tag_with_id(struct cu *cu, struct tag *tag, uint32_t id)
|
|
|
|
{
|
|
|
|
int err = cu__table_add_tag_with_id(cu, tag, id);
|
|
|
|
|
|
|
|
if (err == 0)
|
|
|
|
list_add_tail(&tag->node, &cu->tags);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2008-03-03 17:50:44 +01:00
|
|
|
struct cu *cu__new(const char *name, uint8_t addr_size,
|
2009-03-19 02:35:54 +01:00
|
|
|
const unsigned char *build_id, int build_id_len,
|
|
|
|
const char *filename)
|
2006-10-31 20:12:42 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
struct cu *cu = malloc(sizeof(*cu) + build_id_len);
|
2006-10-31 20:12:42 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
if (cu != NULL) {
|
2019-03-07 15:58:06 +01:00
|
|
|
uint32_t void_id;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
cu->name = strdup(name);
|
|
|
|
cu->filename = strdup(filename);
|
|
|
|
if (cu->name == NULL || cu->filename == NULL)
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
goto out_free;
|
2008-02-11 14:47:17 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
obstack_init(&cu->obstack);
|
|
|
|
ptr_table__init(&cu->tags_table);
|
|
|
|
ptr_table__init(&cu->types_table);
|
|
|
|
ptr_table__init(&cu->functions_table);
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
/*
|
|
|
|
* the first entry is historically associated with void,
|
|
|
|
* so make sure we don't use it
|
|
|
|
*/
|
2019-03-07 15:58:06 +01:00
|
|
|
if (ptr_table__add(&cu->types_table, NULL, &void_id) < 0)
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
goto out_free_name;
|
2008-02-11 14:47:17 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
cu->functions = RB_ROOT;
|
2009-06-04 19:56:44 +02:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
cu->dfops = NULL;
|
|
|
|
INIT_LIST_HEAD(&cu->tags);
|
|
|
|
INIT_LIST_HEAD(&cu->tool_list);
|
2006-12-29 19:34:11 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
cu->addr_size = addr_size;
|
|
|
|
cu->extra_dbg_info = 0;
|
2006-12-29 19:34:11 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
cu->nr_inline_expansions = 0;
|
|
|
|
cu->size_inline_expansions = 0;
|
|
|
|
cu->nr_structures_changed = 0;
|
|
|
|
cu->nr_functions_changed = 0;
|
|
|
|
cu->max_len_changed_item = 0;
|
|
|
|
cu->function_bytes_added = 0;
|
|
|
|
cu->function_bytes_removed = 0;
|
|
|
|
cu->build_id_len = build_id_len;
|
2007-11-24 03:28:15 +01:00
|
|
|
if (build_id_len > 0)
|
2012-08-17 23:47:15 +02:00
|
|
|
memcpy(cu->build_id, build_id, build_id_len);
|
2006-11-03 18:38:43 +01:00
|
|
|
}
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
out:
|
2012-08-17 23:47:15 +02:00
|
|
|
return cu;
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
out_free_name:
|
2012-08-17 23:47:15 +02:00
|
|
|
free(cu->name);
|
|
|
|
free(cu->filename);
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
out_free:
|
2012-08-17 23:47:15 +02:00
|
|
|
free(cu);
|
|
|
|
cu = NULL;
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
goto out;
|
2006-10-31 20:12:42 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
void cu__delete(struct cu *cu)
|
2009-03-11 16:31:17 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
ptr_table__exit(&cu->tags_table);
|
|
|
|
ptr_table__exit(&cu->types_table);
|
|
|
|
ptr_table__exit(&cu->functions_table);
|
|
|
|
if (cu->dfops && cu->dfops->cu__delete)
|
|
|
|
cu->dfops->cu__delete(cu);
|
|
|
|
obstack_free(&cu->obstack, NULL);
|
|
|
|
free(cu->filename);
|
|
|
|
free(cu->name);
|
|
|
|
free(cu);
|
2008-01-14 23:04:57 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
bool cu__same_build_id(const struct cu *cu, const struct cu *other)
|
2008-01-14 18:39:41 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
return cu->build_id_len != 0 &&
|
|
|
|
cu->build_id_len == other->build_id_len &&
|
|
|
|
memcmp(cu->build_id, other->build_id, cu->build_id_len) == 0;
|
2008-01-14 18:39:41 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
struct tag *cu__function(const struct cu *cu, const uint32_t id)
|
2009-03-25 00:12:59 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
return cu ? ptr_table__entry(&cu->functions_table, id) : NULL;
|
2009-03-25 00:12:59 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
struct tag *cu__tag(const struct cu *cu, const uint32_t id)
|
2006-12-20 17:10:07 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
return cu ? ptr_table__entry(&cu->tags_table, id) : NULL;
|
2006-12-20 17:10:07 +01:00
|
|
|
}
|
|
|
|
|
2019-03-07 22:04:20 +01:00
|
|
|
struct tag *cu__type(const struct cu *cu, const type_id_t id)
|
2009-03-03 19:12:29 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
return cu ? ptr_table__entry(&cu->types_table, id) : NULL;
|
2009-03-03 19:12:29 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
struct tag *cu__find_first_typedef_of_type(const struct cu *cu,
|
2019-03-07 22:04:20 +01:00
|
|
|
const type_id_t type)
|
2007-01-28 05:18:34 +01:00
|
|
|
{
|
pahole: Use 32-bit integers for type ID iterations within CU
Existing code base assumes that single CU doesn't have more than 65535
types per each CU, which might be a reasonable assumption for DWARF
data. With BTF, though, all we get is single, potentially huge, CU which
can easily have more than 65k types. For example, this is the case for
allyesconfig version of Linux kernel, which has >200k types.
Due to this assumption, libdwarves and other parts of pahole are using
16-bit counters to iterate over entities within CU. This can cause
infinite loops when iterating BTF data, if there are more than 65535
types. This patch changes non-public variables to use 32-bit integers,
where appropriate.
This still leads to invalid reported data when using BTF loader (due to using
(X & 0xFFFF) type ID, instead of X, when X > 65535) and loading huge files,
but at least it's not stuck in an infinite loop anymore.
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Reported-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
[ Removed non type ID conversions, for instance for the kind of tag, like in type->namespace.tag.tag, that can remain a uint16_t ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-03-07 01:23:21 +01:00
|
|
|
uint32_t id;
|
2007-01-28 05:18:34 +01:00
|
|
|
struct tag *pos;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
if (cu == NULL || type == 0)
|
2007-01-28 05:18:34 +01:00
|
|
|
return NULL;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
cu__for_each_type(cu, id, pos)
|
2008-09-30 19:21:03 +02:00
|
|
|
if (tag__is_typedef(pos) && pos->type == type)
|
2007-01-28 05:18:34 +01:00
|
|
|
return pos;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
struct tag *cu__find_base_type_by_name(const struct cu *cu,
|
2019-03-07 22:04:20 +01:00
|
|
|
const char *name, type_id_t *idp)
|
2007-01-30 19:53:01 +01:00
|
|
|
{
|
pahole: Use 32-bit integers for type ID iterations within CU
Existing code base assumes that single CU doesn't have more than 65535
types per each CU, which might be a reasonable assumption for DWARF
data. With BTF, though, all we get is single, potentially huge, CU which
can easily have more than 65k types. For example, this is the case for
allyesconfig version of Linux kernel, which has >200k types.
Due to this assumption, libdwarves and other parts of pahole are using
16-bit counters to iterate over entities within CU. This can cause
infinite loops when iterating BTF data, if there are more than 65535
types. This patch changes non-public variables to use 32-bit integers,
where appropriate.
This still leads to invalid reported data when using BTF loader (due to using
(X & 0xFFFF) type ID, instead of X, when X > 65535) and loading huge files,
but at least it's not stuck in an infinite loop anymore.
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Reported-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
[ Removed non type ID conversions, for instance for the kind of tag, like in type->namespace.tag.tag, that can remain a uint16_t ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-03-07 01:23:21 +01:00
|
|
|
uint32_t id;
|
2007-01-30 19:53:01 +01:00
|
|
|
struct tag *pos;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
if (cu == NULL || name == NULL)
|
2007-01-30 19:53:01 +01:00
|
|
|
return NULL;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
cu__for_each_type(cu, id, pos) {
|
2009-04-02 21:12:36 +02:00
|
|
|
if (pos->tag != DW_TAG_base_type)
|
|
|
|
continue;
|
2008-02-01 23:00:07 +01:00
|
|
|
|
2009-04-02 21:12:36 +02:00
|
|
|
const struct base_type *bt = tag__base_type(pos);
|
2009-04-02 23:46:54 +02:00
|
|
|
char bf[64];
|
2012-08-17 23:47:15 +02:00
|
|
|
const char *bname = base_type__name(bt, cu, bf, sizeof(bf));
|
2009-08-16 17:13:38 +02:00
|
|
|
if (!bname || strcmp(bname, name) != 0)
|
2009-04-02 23:46:54 +02:00
|
|
|
continue;
|
2009-04-02 21:12:36 +02:00
|
|
|
|
|
|
|
if (idp != NULL)
|
|
|
|
*idp = id;
|
|
|
|
return pos;
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
}
|
2009-03-02 16:22:37 +01:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
struct tag *cu__find_base_type_by_sname_and_size(const struct cu *cu,
|
2009-03-14 17:36:45 +01:00
|
|
|
strings_t sname,
|
|
|
|
uint16_t bit_size,
|
2019-03-07 22:04:20 +01:00
|
|
|
type_id_t *idp)
|
2009-03-02 16:22:37 +01:00
|
|
|
{
|
pahole: Use 32-bit integers for type ID iterations within CU
Existing code base assumes that single CU doesn't have more than 65535
types per each CU, which might be a reasonable assumption for DWARF
data. With BTF, though, all we get is single, potentially huge, CU which
can easily have more than 65k types. For example, this is the case for
allyesconfig version of Linux kernel, which has >200k types.
Due to this assumption, libdwarves and other parts of pahole are using
16-bit counters to iterate over entities within CU. This can cause
infinite loops when iterating BTF data, if there are more than 65535
types. This patch changes non-public variables to use 32-bit integers,
where appropriate.
This still leads to invalid reported data when using BTF loader (due to using
(X & 0xFFFF) type ID, instead of X, when X > 65535) and loading huge files,
but at least it's not stuck in an infinite loop anymore.
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Reported-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
[ Removed non type ID conversions, for instance for the kind of tag, like in type->namespace.tag.tag, that can remain a uint16_t ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-03-07 01:23:21 +01:00
|
|
|
uint32_t id;
|
2009-03-02 16:22:37 +01:00
|
|
|
struct tag *pos;
|
|
|
|
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
if (sname == 0)
|
|
|
|
return NULL;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
cu__for_each_type(cu, id, pos) {
|
2009-03-02 16:22:37 +01:00
|
|
|
if (pos->tag == DW_TAG_base_type) {
|
|
|
|
const struct base_type *bt = tag__base_type(pos);
|
|
|
|
|
|
|
|
if (bt->bit_size == bit_size &&
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
bt->name == sname) {
|
|
|
|
if (idp != NULL)
|
|
|
|
*idp = id;
|
2008-02-01 23:00:07 +01:00
|
|
|
return pos;
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
}
|
2008-02-01 23:00:07 +01:00
|
|
|
}
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
}
|
2007-01-30 19:53:01 +01:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
struct tag *cu__find_enumeration_by_sname_and_size(const struct cu *cu,
|
2009-03-18 15:52:29 +01:00
|
|
|
strings_t sname,
|
|
|
|
uint16_t bit_size,
|
2019-03-07 22:04:20 +01:00
|
|
|
type_id_t *idp)
|
2009-03-18 15:52:29 +01:00
|
|
|
{
|
pahole: Use 32-bit integers for type ID iterations within CU
Existing code base assumes that single CU doesn't have more than 65535
types per each CU, which might be a reasonable assumption for DWARF
data. With BTF, though, all we get is single, potentially huge, CU which
can easily have more than 65k types. For example, this is the case for
allyesconfig version of Linux kernel, which has >200k types.
Due to this assumption, libdwarves and other parts of pahole are using
16-bit counters to iterate over entities within CU. This can cause
infinite loops when iterating BTF data, if there are more than 65535
types. This patch changes non-public variables to use 32-bit integers,
where appropriate.
This still leads to invalid reported data when using BTF loader (due to using
(X & 0xFFFF) type ID, instead of X, when X > 65535) and loading huge files,
but at least it's not stuck in an infinite loop anymore.
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Reported-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
[ Removed non type ID conversions, for instance for the kind of tag, like in type->namespace.tag.tag, that can remain a uint16_t ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-03-07 01:23:21 +01:00
|
|
|
uint32_t id;
|
2009-03-18 15:52:29 +01:00
|
|
|
struct tag *pos;
|
|
|
|
|
|
|
|
if (sname == 0)
|
|
|
|
return NULL;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
cu__for_each_type(cu, id, pos) {
|
2009-03-18 15:52:29 +01:00
|
|
|
if (pos->tag == DW_TAG_enumeration_type) {
|
|
|
|
const struct type *t = tag__type(pos);
|
|
|
|
|
|
|
|
if (t->size == bit_size &&
|
|
|
|
t->namespace.name == sname) {
|
|
|
|
if (idp != NULL)
|
|
|
|
*idp = id;
|
|
|
|
return pos;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-07-14 18:27:09 +02:00
|
|
|
struct tag *cu__find_enumeration_by_name(const struct cu *cu, const char *name, type_id_t *idp)
|
|
|
|
{
|
|
|
|
uint32_t id;
|
|
|
|
struct tag *pos;
|
|
|
|
|
|
|
|
if (name == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
cu__for_each_type(cu, id, pos) {
|
|
|
|
if (pos->tag == DW_TAG_enumeration_type) {
|
|
|
|
const struct type *type = tag__type(pos);
|
|
|
|
const char *tname = type__name(type, cu);
|
|
|
|
|
|
|
|
if (tname && strcmp(tname, name) == 0) {
|
|
|
|
if (idp != NULL)
|
|
|
|
*idp = id;
|
|
|
|
return pos;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
struct tag *cu__find_struct_by_sname(const struct cu *cu, strings_t sname,
|
2019-03-07 22:04:20 +01:00
|
|
|
const int include_decls, type_id_t *idp)
|
2006-10-28 23:22:42 +02:00
|
|
|
{
|
pahole: Use 32-bit integers for type ID iterations within CU
Existing code base assumes that single CU doesn't have more than 65535
types per each CU, which might be a reasonable assumption for DWARF
data. With BTF, though, all we get is single, potentially huge, CU which
can easily have more than 65k types. For example, this is the case for
allyesconfig version of Linux kernel, which has >200k types.
Due to this assumption, libdwarves and other parts of pahole are using
16-bit counters to iterate over entities within CU. This can cause
infinite loops when iterating BTF data, if there are more than 65535
types. This patch changes non-public variables to use 32-bit integers,
where appropriate.
This still leads to invalid reported data when using BTF loader (due to using
(X & 0xFFFF) type ID, instead of X, when X > 65535) and loading huge files,
but at least it's not stuck in an infinite loop anymore.
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Reported-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
[ Removed non type ID conversions, for instance for the kind of tag, like in type->namespace.tag.tag, that can remain a uint16_t ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-03-07 01:23:21 +01:00
|
|
|
uint32_t id;
|
2006-12-29 18:28:58 +01:00
|
|
|
struct tag *pos;
|
2006-10-28 23:22:42 +02:00
|
|
|
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
if (sname == 0)
|
|
|
|
return NULL;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
cu__for_each_type(cu, id, pos) {
|
2007-01-07 16:11:20 +01:00
|
|
|
struct type *type;
|
2006-12-29 23:58:03 +01:00
|
|
|
|
2007-05-31 06:53:01 +02:00
|
|
|
if (!tag__is_struct(pos))
|
2006-12-29 23:58:03 +01:00
|
|
|
continue;
|
|
|
|
|
2007-01-07 16:11:20 +01:00
|
|
|
type = tag__type(pos);
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
if (type->namespace.name == sname) {
|
2009-03-13 00:34:07 +01:00
|
|
|
if (!type->declaration)
|
|
|
|
goto found;
|
|
|
|
|
|
|
|
if (include_decls)
|
|
|
|
goto found;
|
2007-11-16 21:16:56 +01:00
|
|
|
}
|
2006-12-29 18:28:58 +01:00
|
|
|
}
|
2006-10-28 23:22:42 +02:00
|
|
|
|
|
|
|
return NULL;
|
2009-03-13 00:34:07 +01:00
|
|
|
found:
|
|
|
|
if (idp != NULL)
|
|
|
|
*idp = id;
|
|
|
|
return pos;
|
|
|
|
|
2006-10-28 23:22:42 +02:00
|
|
|
}
|
|
|
|
|
2020-01-15 17:45:47 +01:00
|
|
|
struct tag *cu__find_type_by_name(const struct cu *cu, const char *name, const int include_decls, type_id_t *idp)
|
|
|
|
{
|
|
|
|
if (cu == NULL || name == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
uint32_t id;
|
|
|
|
struct tag *pos;
|
|
|
|
cu__for_each_type(cu, id, pos) {
|
|
|
|
struct type *type;
|
|
|
|
|
|
|
|
if (!tag__is_type(pos))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
type = tag__type(pos);
|
|
|
|
const char *tname = type__name(type, cu);
|
|
|
|
if (tname && strcmp(tname, name) == 0) {
|
|
|
|
if (!type->declaration)
|
|
|
|
goto found;
|
|
|
|
|
|
|
|
if (include_decls)
|
|
|
|
goto found;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
found:
|
|
|
|
if (idp != NULL)
|
|
|
|
*idp = id;
|
|
|
|
return pos;
|
|
|
|
}
|
|
|
|
|
2020-07-24 14:45:25 +02:00
|
|
|
struct tag *cus__find_type_by_name(const struct cus *cus, struct cu **cu, const char *name,
|
|
|
|
const int include_decls, type_id_t *id)
|
|
|
|
{
|
|
|
|
struct cu *pos;
|
|
|
|
|
|
|
|
list_for_each_entry(pos, &cus->cus, node) {
|
|
|
|
struct tag *tag = cu__find_type_by_name(pos, name, include_decls, id);
|
|
|
|
if (tag != NULL) {
|
|
|
|
if (cu != NULL)
|
|
|
|
*cu = pos;
|
|
|
|
return tag;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-12-03 17:13:51 +01:00
|
|
|
static struct tag *__cu__find_struct_by_name(const struct cu *cu, const char *name,
|
2019-03-07 22:04:20 +01:00
|
|
|
const int include_decls, bool unions, type_id_t *idp)
|
2009-03-13 18:57:53 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
if (cu == NULL || name == NULL)
|
2009-03-13 18:57:53 +01:00
|
|
|
return NULL;
|
|
|
|
|
pahole: Use 32-bit integers for type ID iterations within CU
Existing code base assumes that single CU doesn't have more than 65535
types per each CU, which might be a reasonable assumption for DWARF
data. With BTF, though, all we get is single, potentially huge, CU which
can easily have more than 65k types. For example, this is the case for
allyesconfig version of Linux kernel, which has >200k types.
Due to this assumption, libdwarves and other parts of pahole are using
16-bit counters to iterate over entities within CU. This can cause
infinite loops when iterating BTF data, if there are more than 65535
types. This patch changes non-public variables to use 32-bit integers,
where appropriate.
This still leads to invalid reported data when using BTF loader (due to using
(X & 0xFFFF) type ID, instead of X, when X > 65535) and loading huge files,
but at least it's not stuck in an infinite loop anymore.
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Reported-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
[ Removed non type ID conversions, for instance for the kind of tag, like in type->namespace.tag.tag, that can remain a uint16_t ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-03-07 01:23:21 +01:00
|
|
|
uint32_t id;
|
2009-04-02 23:46:54 +02:00
|
|
|
struct tag *pos;
|
2012-08-17 23:47:15 +02:00
|
|
|
cu__for_each_type(cu, id, pos) {
|
2009-04-02 23:46:54 +02:00
|
|
|
struct type *type;
|
|
|
|
|
2018-12-03 17:13:51 +01:00
|
|
|
if (!(tag__is_struct(pos) || (unions && tag__is_union(pos))))
|
2009-04-02 23:46:54 +02:00
|
|
|
continue;
|
2009-03-13 18:57:53 +01:00
|
|
|
|
2009-04-02 23:46:54 +02:00
|
|
|
type = tag__type(pos);
|
2012-08-17 23:47:15 +02:00
|
|
|
const char *tname = type__name(type, cu);
|
2009-04-03 16:55:02 +02:00
|
|
|
if (tname && strcmp(tname, name) == 0) {
|
2009-04-02 23:46:54 +02:00
|
|
|
if (!type->declaration)
|
|
|
|
goto found;
|
|
|
|
|
|
|
|
if (include_decls)
|
|
|
|
goto found;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
found:
|
|
|
|
if (idp != NULL)
|
|
|
|
*idp = id;
|
|
|
|
return pos;
|
2009-03-13 18:57:53 +01:00
|
|
|
}
|
|
|
|
|
2018-12-03 17:13:51 +01:00
|
|
|
struct tag *cu__find_struct_by_name(const struct cu *cu, const char *name,
|
2019-03-07 22:04:20 +01:00
|
|
|
const int include_decls, type_id_t *idp)
|
2018-12-03 17:13:51 +01:00
|
|
|
{
|
|
|
|
return __cu__find_struct_by_name(cu, name, include_decls, false, idp);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct tag *cu__find_struct_or_union_by_name(const struct cu *cu, const char *name,
|
2019-03-07 22:04:20 +01:00
|
|
|
const int include_decls, type_id_t *idp)
|
2018-12-03 17:13:51 +01:00
|
|
|
{
|
|
|
|
return __cu__find_struct_by_name(cu, name, include_decls, true, idp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct tag *__cus__find_struct_by_name(const struct cus *cus,
|
|
|
|
struct cu **cu, const char *name,
|
2019-03-07 22:04:20 +01:00
|
|
|
const int include_decls, bool unions, type_id_t *id)
|
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
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
list_for_each_entry(pos, &cus->cus, node) {
|
2018-12-03 17:13:51 +01:00
|
|
|
struct tag *tag = __cu__find_struct_by_name(pos, name, include_decls, unions, id);
|
2007-01-07 16:11:20 +01:00
|
|
|
if (tag != NULL) {
|
2007-01-04 00:57:35 +01:00
|
|
|
if (cu != NULL)
|
|
|
|
*cu = pos;
|
2007-01-07 16:11:20 +01:00
|
|
|
return tag;
|
2007-01-04 00:57:35 +01:00
|
|
|
}
|
2006-10-31 21:23:16 +01:00
|
|
|
}
|
2006-10-31 20:12:42 +01:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-12-03 17:13:51 +01:00
|
|
|
struct tag *cus__find_struct_by_name(const struct cus *cus, struct cu **cu, const char *name,
|
2019-03-07 22:04:20 +01:00
|
|
|
const int include_decls, type_id_t *idp)
|
2018-12-03 17:13:51 +01:00
|
|
|
{
|
|
|
|
return __cus__find_struct_by_name(cus, cu, name, include_decls, false, idp);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct tag *cus__find_struct_or_union_by_name(const struct cus *cus, struct cu **cu, const char *name,
|
2019-03-07 22:04:20 +01:00
|
|
|
const int include_decls, type_id_t *idp)
|
2018-12-03 17:13:51 +01:00
|
|
|
{
|
|
|
|
return __cus__find_struct_by_name(cus, cu, name, include_decls, true, idp);
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
struct function *cu__find_function_at_addr(const struct cu *cu,
|
2009-06-04 19:56:44 +02:00
|
|
|
uint64_t addr)
|
|
|
|
{
|
|
|
|
struct rb_node *n;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
if (cu == NULL)
|
2009-06-04 19:56:44 +02:00
|
|
|
return NULL;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
n = cu->functions.rb_node;
|
2009-06-04 19:56:44 +02:00
|
|
|
|
|
|
|
while (n) {
|
|
|
|
struct function *f = rb_entry(n, struct function, rb_node);
|
|
|
|
|
2009-06-04 22:30:06 +02:00
|
|
|
if (addr < f->lexblock.ip.addr)
|
2009-06-04 19:56:44 +02:00
|
|
|
n = n->rb_left;
|
2009-06-04 22:30:06 +02:00
|
|
|
else if (addr >= f->lexblock.ip.addr + f->lexblock.size)
|
2009-06-04 19:56:44 +02:00
|
|
|
n = n->rb_right;
|
|
|
|
else
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
struct function *cus__find_function_at_addr(const struct cus *cus,
|
2009-06-04 19:56:44 +02:00
|
|
|
uint64_t addr, struct cu **cu)
|
|
|
|
{
|
|
|
|
struct cu *pos;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
list_for_each_entry(pos, &cus->cus, node) {
|
2009-06-04 19:56:44 +02:00
|
|
|
struct function *f = cu__find_function_at_addr(pos, addr);
|
|
|
|
|
|
|
|
if (f != NULL) {
|
|
|
|
if (cu != NULL)
|
|
|
|
*cu = pos;
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
struct cu *cus__find_cu_by_name(const struct cus *cus, const char *name)
|
2006-11-11 19:31:04 +01:00
|
|
|
{
|
|
|
|
struct cu *pos;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
list_for_each_entry(pos, &cus->cus, node)
|
2008-10-02 19:34:42 +02:00
|
|
|
if (pos->name && strcmp(pos->name, name) == 0)
|
2006-11-11 19:31:04 +01:00
|
|
|
return pos;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
struct tag *cu__find_function_by_name(const struct cu *cu, const char *name)
|
2006-11-18 17:33:48 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
if (cu == NULL || name == NULL)
|
2006-11-18 17:33:48 +01:00
|
|
|
return NULL;
|
|
|
|
|
2009-04-02 17:07:53 +02:00
|
|
|
uint32_t id;
|
|
|
|
struct function *pos;
|
2012-08-17 23:47:15 +02:00
|
|
|
cu__for_each_function(cu, id, pos) {
|
|
|
|
const char *fname = function__name(pos, cu);
|
2009-04-03 16:55:02 +02:00
|
|
|
if (fname && strcmp(fname, name) == 0)
|
2009-04-02 17:07:53 +02:00
|
|
|
return function__tag(pos);
|
2009-04-03 16:55:02 +02:00
|
|
|
}
|
2006-11-18 17:33:48 +01:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static size_t array_type__nr_entries(const struct array_type *at)
|
2006-12-08 15:58:46 +01:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
size_t nr_entries = 1;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
for (i = 0; i < at->dimensions; ++i)
|
|
|
|
nr_entries *= at->nr_entries[i];
|
2006-12-08 15:58:46 +01:00
|
|
|
|
|
|
|
return nr_entries;
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
size_t tag__size(const struct tag *tag, 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
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
switch (tag->tag) {
|
2009-03-17 17:57:40 +01:00
|
|
|
case DW_TAG_member: {
|
2012-08-20 19:42:17 +02:00
|
|
|
struct class_member *member = tag__class_member(tag);
|
|
|
|
if (member->is_static)
|
|
|
|
return 0;
|
2009-03-17 17:57:40 +01:00
|
|
|
/* Is it cached already? */
|
2012-08-20 19:42:17 +02:00
|
|
|
size = member->byte_size;
|
2009-03-17 17:57:40 +01:00
|
|
|
if (size != 0)
|
|
|
|
return size;
|
|
|
|
break;
|
|
|
|
}
|
2007-01-12 14:06:59 +01:00
|
|
|
case DW_TAG_pointer_type:
|
|
|
|
case DW_TAG_reference_type: return cu->addr_size;
|
2012-08-17 23:47:15 +02:00
|
|
|
case DW_TAG_base_type: return base_type__size(tag);
|
|
|
|
case DW_TAG_enumeration_type: return tag__type(tag)->size / 8;
|
2006-12-29 23:58:03 +01:00
|
|
|
}
|
2006-12-29 19:34:11 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
if (tag->type == 0) { /* struct class: unions, structs */
|
|
|
|
struct type *type = tag__type(tag);
|
2008-07-04 17:09:28 +02:00
|
|
|
|
|
|
|
/* empty base optimization trick */
|
|
|
|
if (type->size == 1 && type->nr_members == 0)
|
|
|
|
size = 0;
|
|
|
|
else
|
2012-08-17 23:47:15 +02:00
|
|
|
size = tag__type(tag)->size;
|
2008-07-04 17:09:28 +02:00
|
|
|
} else {
|
2012-08-17 23:47:15 +02:00
|
|
|
const struct tag *type = cu__type(cu, tag->type);
|
2006-12-29 19:34:11 +01:00
|
|
|
|
2007-01-12 02:09:06 +01:00
|
|
|
if (type == NULL) {
|
2012-08-17 23:47:15 +02:00
|
|
|
tag__id_not_found_fprintf(stderr, tag->type);
|
2007-01-12 02:09:06 +01:00
|
|
|
return -1;
|
2012-08-17 23:47:15 +02:00
|
|
|
} else if (tag__has_type_loop(tag, type, NULL, 0, NULL))
|
2009-09-14 22:07:02 +02:00
|
|
|
return -1;
|
2006-12-29 19:34:11 +01:00
|
|
|
size = tag__size(type, cu);
|
|
|
|
}
|
2006-10-28 23:22:42 +02:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
if (tag->tag == DW_TAG_array_type)
|
|
|
|
return size * array_type__nr_entries(tag__array_type(tag));
|
2006-10-28 23:22:42 +02:00
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
const char *variable__name(const struct variable *var, const struct cu *cu)
|
2009-04-02 17:40:33 +02:00
|
|
|
{
|
|
|
|
if (cu->dfops && cu->dfops->variable__name)
|
2012-08-17 23:47:15 +02:00
|
|
|
return cu->dfops->variable__name(var, cu);
|
|
|
|
return s(cu, var->name);
|
2009-04-02 17:40:33 +02:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
const char *variable__type_name(const struct variable *var,
|
2007-02-02 14:56:53 +01:00
|
|
|
const struct cu *cu,
|
|
|
|
char *bf, size_t len)
|
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
const struct tag *tag = cu__type(cu, var->ip.tag.type);
|
2009-08-24 22:22:43 +02:00
|
|
|
return tag != NULL ? tag__name(tag, cu, bf, len, NULL) : NULL;
|
2007-02-02 14:56:53 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
void class_member__delete(struct class_member *member, struct cu *cu)
|
2007-01-30 16:32:55 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
obstack_free(&cu->obstack, member);
|
2007-01-30 16:32:55 +01:00
|
|
|
}
|
|
|
|
|
2009-09-20 21:20:06 +02:00
|
|
|
static struct class_member *class_member__clone(const struct class_member *from,
|
|
|
|
struct cu *cu)
|
2007-01-30 16:32:55 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
struct class_member *member = obstack_alloc(&cu->obstack, sizeof(*member));
|
2007-01-30 16:32:55 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
if (member != NULL)
|
|
|
|
memcpy(member, from, sizeof(*member));
|
2007-01-30 16:32:55 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
return member;
|
2007-01-30 16:32:55 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void type__delete_class_members(struct type *type, struct cu *cu)
|
2007-01-30 16:32:55 +01:00
|
|
|
{
|
2007-02-01 18:54:42 +01:00
|
|
|
struct class_member *pos, *next;
|
2007-01-30 16:32:55 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
type__for_each_tag_safe_reverse(type, pos, next) {
|
2009-03-25 16:00:30 +01:00
|
|
|
list_del_init(&pos->tag.node);
|
2009-08-18 23:21:20 +02:00
|
|
|
class_member__delete(pos, cu);
|
2009-03-25 16:00:30 +01:00
|
|
|
}
|
|
|
|
}
|
2007-01-30 16:32:55 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
void class__delete(struct class *class, struct cu *cu)
|
2009-03-25 16:00:30 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
if (class->type.namespace.sname != NULL)
|
|
|
|
free(class->type.namespace.sname);
|
|
|
|
type__delete_class_members(&class->type, cu);
|
|
|
|
obstack_free(&cu->obstack, class);
|
2009-03-25 16:00:30 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
void type__delete(struct type *type, struct cu *cu)
|
2009-03-25 16:00:30 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
type__delete_class_members(type, cu);
|
|
|
|
obstack_free(&cu->obstack, type);
|
2007-01-30 16:32:55 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void enumerator__delete(struct enumerator *enumerator, struct cu *cu)
|
2009-03-25 16:17:50 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
obstack_free(&cu->obstack, enumerator);
|
2009-03-25 16:17:50 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
void enumeration__delete(struct type *type, struct cu *cu)
|
2009-03-25 16:17:50 +01:00
|
|
|
{
|
|
|
|
struct enumerator *pos, *n;
|
2012-08-17 23:47:15 +02:00
|
|
|
type__for_each_enumerator_safe_reverse(type, pos, n) {
|
2009-03-25 16:17:50 +01:00
|
|
|
list_del_init(&pos->tag.node);
|
2009-08-18 23:21:20 +02:00
|
|
|
enumerator__delete(pos, cu);
|
2009-03-25 16:17:50 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
void class__add_vtable_entry(struct class *class, struct function *vtable_entry)
|
2007-07-09 01:57:23 +02:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
++class->nr_vtable_entries;
|
|
|
|
list_add_tail(&vtable_entry->vtable_node, &class->vtable);
|
2007-07-09 01:57:23 +02:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
void namespace__add_tag(struct namespace *space, struct tag *tag)
|
2007-05-24 03:38:29 +02:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
++space->nr_tags;
|
|
|
|
list_add_tail(&tag->node, &space->tags);
|
2007-05-24 03:38:29 +02:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
void type__add_member(struct type *type, struct class_member *member)
|
2006-10-28 23:22:42 +02:00
|
|
|
{
|
2012-08-20 19:42:17 +02:00
|
|
|
if (member->is_static)
|
|
|
|
++type->nr_static_members;
|
|
|
|
else
|
|
|
|
++type->nr_members;
|
2012-08-17 23:47:15 +02:00
|
|
|
namespace__add_tag(&type->namespace, &member->tag);
|
2006-10-28 23:22:42 +02:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
struct class_member *type__last_member(struct type *type)
|
2007-05-24 03:10:50 +02:00
|
|
|
{
|
2007-05-24 03:38:29 +02:00
|
|
|
struct class_member *pos;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
list_for_each_entry_reverse(pos, &type->namespace.tags, tag.node)
|
2007-05-24 03:38:29 +02:00
|
|
|
if (pos->tag.tag == DW_TAG_member)
|
|
|
|
return pos;
|
|
|
|
return NULL;
|
2007-05-24 03:10:50 +02:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static int type__clone_members(struct type *type, const struct type *from,
|
2009-09-20 21:20:06 +02:00
|
|
|
struct cu *cu)
|
2007-01-30 16:32:55 +01:00
|
|
|
{
|
|
|
|
struct class_member *pos;
|
|
|
|
|
2012-08-20 19:42:17 +02:00
|
|
|
type->nr_members = type->nr_static_members = 0;
|
2012-08-17 23:47:15 +02:00
|
|
|
INIT_LIST_HEAD(&type->namespace.tags);
|
2007-01-30 16:32:55 +01:00
|
|
|
|
2007-05-24 02:43:01 +02:00
|
|
|
type__for_each_member(from, pos) {
|
2009-09-20 21:20:06 +02:00
|
|
|
struct class_member *clone = class_member__clone(pos, cu);
|
2007-01-30 16:32:55 +01:00
|
|
|
|
2009-09-20 21:20:06 +02:00
|
|
|
if (clone == NULL)
|
2007-01-30 16:32:55 +01:00
|
|
|
return -1;
|
2012-08-17 23:47:15 +02:00
|
|
|
type__add_member(type, clone);
|
2007-01-30 16:32:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-02-01 17:09:48 +01:00
|
|
|
struct class *class__clone(const struct class *from,
|
2009-08-18 23:21:20 +02:00
|
|
|
const char *new_class_name, struct cu *cu)
|
2007-01-30 16:32:55 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
struct class *class = obstack_alloc(&cu->obstack, sizeof(*class));
|
2007-01-30 16:32:55 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
if (class != NULL) {
|
|
|
|
memcpy(class, from, sizeof(*class));
|
2009-04-02 23:46:54 +02:00
|
|
|
if (new_class_name != NULL) {
|
2012-08-17 23:47:15 +02:00
|
|
|
class->type.namespace.name = 0;
|
|
|
|
class->type.namespace.sname = strdup(new_class_name);
|
|
|
|
if (class->type.namespace.sname == NULL) {
|
|
|
|
free(class);
|
2009-04-02 23:46:54 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
2012-08-17 23:47:15 +02:00
|
|
|
if (type__clone_members(&class->type, &from->type, cu) != 0) {
|
|
|
|
class__delete(class, cu);
|
|
|
|
class = NULL;
|
2007-01-30 16:32:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
return class;
|
2007-01-30 16:32:55 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
void enumeration__add(struct type *type, struct enumerator *enumerator)
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
++type->nr_members;
|
|
|
|
namespace__add_tag(&type->namespace, &enumerator->tag);
|
[CLASSES]: Add support for enums
Be it named enums such as:
/* include/linux/pid.h:7 */
enum pid_type {
PIDTYPE_PID = 0,
PIDTYPE_PGID = 1,
PIDTYPE_SID = 2,
PIDTYPE_MAX = 3,
};
Or nameless enums inside structs:
/* include/linux/journal-head.h:14 */
typedef struct transaction_s {
journal_t * t_journal; /* 0 4 */
tid_t t_tid; /* 4 4 */
enum {
T_RUNNING = 0,
T_LOCKED = 1,
T_RUNDOWN = 2,
T_FLUSH = 3,
T_COMMIT = 4,
T_FINISHED = 5,
} t_state; /* 8 4 */
long unsigned int t_log_start; /* 12 4 */
<SNIP>
} transaction_t; /* size: 84, cachelines: 3 */
/* last cacheline: 20 bytes */
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-12-24 14:56:59 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
void lexblock__add_lexblock(struct lexblock *block, struct lexblock *child)
|
2007-01-02 16:25:56 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
++block->nr_lexblocks;
|
|
|
|
list_add_tail(&child->ip.tag.node, &block->tags);
|
2006-11-20 19:54:39 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
const char *function__name(struct function *func, const struct cu *cu)
|
2007-01-07 20:13:39 +01:00
|
|
|
{
|
2009-04-02 16:46:26 +02:00
|
|
|
if (cu->dfops && cu->dfops->function__name)
|
2012-08-17 23:47:15 +02:00
|
|
|
return cu->dfops->function__name(func, cu);
|
|
|
|
return s(cu, func->name);
|
2007-01-07 20:13:39 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void parameter__delete(struct parameter *parm, struct cu *cu)
|
2009-03-25 15:40:05 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
obstack_free(&cu->obstack, parm);
|
2009-03-25 15:40:05 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
void ftype__delete(struct ftype *type, struct cu *cu)
|
2009-03-25 15:40:05 +01:00
|
|
|
{
|
|
|
|
struct parameter *pos, *n;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
if (type == NULL)
|
2009-03-25 15:40:05 +01:00
|
|
|
return;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
ftype__for_each_parameter_safe_reverse(type, pos, n) {
|
2009-03-25 15:40:05 +01:00
|
|
|
list_del_init(&pos->tag.node);
|
2009-08-18 23:21:20 +02:00
|
|
|
parameter__delete(pos, cu);
|
2009-03-25 15:40:05 +01:00
|
|
|
}
|
2012-08-17 23:47:15 +02:00
|
|
|
obstack_free(&cu->obstack, type);
|
2009-03-25 15:40:05 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
void function__delete(struct function *func, struct cu *cu)
|
2009-03-25 18:54:02 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
lexblock__delete_tags(&func->lexblock.ip.tag, cu);
|
|
|
|
ftype__delete(&func->proto, cu);
|
2009-03-25 18:54:02 +01:00
|
|
|
}
|
|
|
|
|
2019-03-07 22:04:20 +01:00
|
|
|
int ftype__has_parm_of_type(const struct ftype *ftype, const type_id_t target,
|
2006-12-30 19:34:20 +01:00
|
|
|
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
|
|
|
|
btf_loader: Add support for BTF_KIND_FUNC
Some changes to the fprintf routines were needed, as BTF has as the
function type just a BTF_KIND_FUNC_PROTO, while DWARF has as the type
for a function its return value type. With a function->btf flag this was
overcome and all the other goodies in pfunct are present, for instance:
$ pahole -JV examples/tcp.o | grep -w FUNC | head
[4068] FUNC tcp_init type_id=4067
[4070] FUNC tcp_abort type_id=4069
[4072] FUNC tcp_done type_id=4071
[4074] FUNC tcp_md5_hash_key type_id=4073
[4076] FUNC tcp_md5_hash_skb_data type_id=4075
[4078] FUNC tcp_get_md5sig_pool type_id=4077
[4080] FUNC tcp_alloc_md5sig_pool type_id=4079
[4082] FUNC compat_tcp_getsockopt type_id=4081
[4084] FUNC tcp_getsockopt type_id=4083
[4086] FUNC tcp_get_timestamping_opt_stats type_id=4085
$
$ pfunct -F btf examples/tcp.o | head
memset
memcpy
tcp_enter_memory_pressure
tcp_leave_memory_pressure
tcp_init_sock
tcp_init_transfer
tcp_poll
tcp_ioctl
tcp_splice_read
sk_stream_alloc_skb
$
$ pfunct --prototype -F btf examples/tcp.o | head
void * memset(void * p, int c, __kernel_size_t size);
void * memcpy(void * p, const void * q, __kernel_size_t size);
void tcp_enter_memory_pressure(struct sock * sk);
void tcp_leave_memory_pressure(struct sock * sk);
void tcp_init_sock(struct sock * sk);
void tcp_init_transfer(struct sock * sk, int bpf_op);
__poll_t tcp_poll(struct file * file, struct socket * sock, poll_table * wait);
int tcp_ioctl(struct sock * sk, int cmd, long unsigned int arg);
ssize_t tcp_splice_read(struct socket * sock, loff_t * ppos, struct pipe_inode_info * pipe, size_t len, unsigned int flags);
struct sk_buff * sk_stream_alloc_skb(struct sock * sk, int size, gfp_t gfp, bool force_schedule);
$
Now to ask just for the 'struct sock' 'methods', i.e. functions that
have as one of its arguments a pointer to the given 'class' name:
$ pfunct --class sock -F btf examples/tcp.o | head
tcp_abort
tcp_done
compat_tcp_getsockopt
tcp_getsockopt
tcp_get_info
compat_tcp_setsockopt
tcp_setsockopt
tcp_disconnect
tcp_write_queue_purge
tcp_close
$
Then ask for the prototypes, which requires -V, should have that fixed:
$ pfunct -V --prototypes --class sock -F btf examples/tcp.o | head
int tcp_abort(struct sock * sk, int err);
void tcp_done(struct sock * sk);
int compat_tcp_getsockopt(struct sock * sk, int level, int optname, char * optval, int * optlen);
int tcp_getsockopt(struct sock * sk, int level, int optname, char * optval, int * optlen);
void tcp_get_info(struct sock * sk, struct tcp_info * info);
int compat_tcp_setsockopt(struct sock * sk, int level, int optname, char * optval, unsigned int optlen);
int tcp_setsockopt(struct sock * sk, int level, int optname, char * optval, unsigned int optlen);
int tcp_disconnect(struct sock * sk, int flags);
void tcp_write_queue_purge(struct sock * sk);
void tcp_close(struct sock * sk, long int timeout);
$
Don't like prototypes with parm names, got you covered:
$ pfunct --no_parm_names -V --prototypes --class sock -F btf examples/tcp.o | head
int tcp_abort(struct sock *, int);
void tcp_done(struct sock *);
int compat_tcp_getsockopt(struct sock *, int, int, char *, int *);
int tcp_getsockopt(struct sock *, int, int, char *, int *);
void tcp_get_info(struct sock *, struct tcp_info *);
int compat_tcp_setsockopt(struct sock *, int, int, char *, unsigned int);
int tcp_setsockopt(struct sock *, int, int, char *, unsigned int);
int tcp_disconnect(struct sock *, int);
void tcp_write_queue_purge(struct sock *);
void tcp_close(struct sock *, long int);
$
Don't like long options and want just one function?
$ pfunct -f tcp_setsockopt -F btf examples/tcp.o
int tcp_setsockopt(struct sock * sk, int level, int optname, char * optval, unsigned int optlen);
$
Want to generate compileable code for all of those functions, full with
the necessary types, etc?
$ pfunct -F btf --compile examples/tcp.o > a.c
$ gcc -c -o a.o a.c
$ pfunct -F dwarf --prototypes --class sock a.o | head
pfunct: a.o: No debugging information found
$ gcc -g -c -o a.o a.c
$ pfunct -V -F dwarf --prototypes --class sock a.o | head
void tcp_enter_memory_pressure(struct sock * sk);
void tcp_leave_memory_pressure(struct sock * sk);
void tcp_init_sock(struct sock * sk);
void tcp_init_transfer(struct sock * sk, int bpf_op);
int tcp_ioctl(struct sock * sk, int cmd, long unsigned int arg);
struct sk_buff * sk_stream_alloc_skb(struct sock * sk, int size, gfp_t gfp, bool force_schedule);
ssize_t do_tcp_sendpages(struct sock * sk, struct page * page, int offset, size_t size, int flags);
int tcp_sendpage_locked(struct sock * sk, struct page * page, int offset, size_t size, int flags);
int tcp_sendpage(struct sock * sk, struct page * page, int offset, size_t size, int flags);
int tcp_sendmsg_locked(struct sock * sk, struct msghdr * msg, size_t size);
$
Now lets go full circle and encode BTF for this a.o generated from
source code generated from the original BTF info in that examples/tcp.o
file:
$ pahole -JV a.o | tail
[465] FUNC_PROTO (anon) return=35 args=(392 hp, 393 skb, 5 header_len)
[466] FUNC tcp_md5_hash_skb_data type_id=465
[467] FUNC_PROTO (anon) return=35 args=(392 hp, 394 key)
[468] FUNC tcp_md5_hash_key type_id=467
[469] FUNC_PROTO (anon) return=0 args=(49 sk)
[470] FUNC tcp_done type_id=469
[471] FUNC_PROTO (anon) return=35 args=(49 sk, 35 err)
[472] FUNC tcp_abort type_id=471
[473] FUNC_PROTO (anon) return=0 args=(void)
[474] FUNC tcp_init type_id=473
$
$ pfunct -F btf -V --prototypes --class=sock a.o | head
void tcp_enter_memory_pressure(struct sock * sk);
void tcp_leave_memory_pressure(struct sock * sk);
void tcp_init_sock(struct sock * sk);
void tcp_init_transfer(struct sock * sk, int bpf_op);
int tcp_ioctl(struct sock * sk, int cmd, long unsigned int arg);
struct sk_buff * sk_stream_alloc_skb(struct sock * sk, int size, gfp_t gfp, bool force_schedule);
ssize_t do_tcp_sendpages(struct sock * sk, struct page * page, int offset, size_t size, int flags);
int tcp_sendpage_locked(struct sock * sk, struct page * page, int offset, size_t size, int flags);
int tcp_sendpage(struct sock * sk, struct page * page, int offset, size_t size, int flags);
int tcp_sendmsg_locked(struct sock * sk, struct msghdr * msg, size_t size);
$
Curious about the code generated by 'pfunct -F btf --compile examples/tcp.o?
http://vger.kernel.org/~acme/pahole/pfunct-F-BTF--compile-examples-tcp.o.txt
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Andrii Nakryiko <andrii.nakryiko@gmail.com>
Cc: Andrii Nakryiko <andriin@fb.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Yonghong Song <yhs@fb.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-11-05 15:30:51 +01:00
|
|
|
if (ftype->tag.tag == DW_TAG_subprogram) {
|
|
|
|
struct function *func = (struct function *)ftype;
|
|
|
|
|
|
|
|
if (func->btf)
|
|
|
|
ftype = tag__ftype(cu__type(cu, ftype->tag.type));
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
ftype__for_each_parameter(ftype, pos) {
|
2009-03-18 16:17:07 +01:00
|
|
|
struct tag *type = cu__type(cu, pos->tag.type);
|
2006-12-20 15:03:12 +01:00
|
|
|
|
2019-04-05 20:21:55 +02:00
|
|
|
if (type != NULL && tag__is_pointer(type)) {
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
if (type->type == target)
|
2006-12-20 15:03:12 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
void ftype__add_parameter(struct ftype *ftype, struct parameter *parm)
|
2006-11-18 17:33:48 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
++ftype->nr_parms;
|
|
|
|
list_add_tail(&parm->tag.node, &ftype->parms);
|
2006-11-18 17:33:48 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
void lexblock__add_tag(struct lexblock *block, struct tag *tag)
|
2007-01-26 03:29:53 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
list_add_tail(&tag->node, &block->tags);
|
2007-01-26 03:29:53 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
void lexblock__add_inline_expansion(struct lexblock *block,
|
2008-03-03 17:50:44 +01:00
|
|
|
struct inline_expansion *exp)
|
2006-11-03 16:41:19 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
++block->nr_inline_expansions;
|
|
|
|
block->size_inline_expansions += exp->size;
|
|
|
|
lexblock__add_tag(block, &exp->ip.tag);
|
2006-11-03 16:41:19 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
void lexblock__add_variable(struct lexblock *block, 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
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
++block->nr_variables;
|
|
|
|
lexblock__add_tag(block, &var->ip.tag);
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
void lexblock__add_label(struct lexblock *block, struct label *label)
|
2006-11-20 19:17:42 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
++block->nr_labels;
|
|
|
|
lexblock__add_tag(block, &label->ip.tag);
|
2006-11-20 19:17:42 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
const struct class_member *class__find_bit_hole(const struct class *class,
|
2006-12-07 19:11:47 +01:00
|
|
|
const struct class_member *trailer,
|
2009-03-07 20:45:09 +01:00
|
|
|
const uint16_t bit_hole_size)
|
2006-12-07 19:11:47 +01:00
|
|
|
{
|
|
|
|
struct class_member *pos;
|
|
|
|
const size_t byte_hole_size = bit_hole_size / 8;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
type__for_each_data_member(&class->type, pos)
|
2006-12-07 19:11:47 +01:00
|
|
|
if (pos == trailer)
|
|
|
|
break;
|
|
|
|
else if (pos->hole >= byte_hole_size ||
|
|
|
|
pos->bit_hole >= bit_hole_size)
|
|
|
|
return pos;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
void class__find_holes(struct class *class)
|
2006-10-28 23:22:42 +02:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
const struct type *ctype = &class->type;
|
2006-10-28 23:22:42 +02:00
|
|
|
struct class_member *pos, *last = NULL;
|
dwarves: Revamp bit/byte holes detection logic
This patch rewrites hole detection logic. Now many crazy combinations of
bitfields and normal fields are handled correctly.
This was tested on allyesconfig kernel and differences before/after were
always in favor of new algorithm.
With subsequent change in next patch, there are no more BRAIN FART
ALERTs for allyesconfig and DWARF and BTF outputs have no discrepanies.
Example:
$ cat test.c
struct s {
short : 4; /* this one is not emitted in DWARF/BTF */
short a : 4;
int x;
int : 10;
int y : 4;
short zz;
short zzz : 4;
long z;
short : 4;
};
int main() {
struct s s;
return 0;
}
$ gcc -g test.c -o test
$ ~/pahole/build/pahole -J test
$ ~/pahole/build/pahole -F dwarf test
struct s {
/* XXX 4 bits hole, try to pack */
short int a:4; /* 0: 8 2 */
/* XXX 8 bits hole, try to pack */
/* XXX 2 bytes hole, try to pack */
int x; /* 4 4 */
/* XXX 10 bits hole, try to pack */
int y:4; /* 8:18 4 */
/* Bitfield combined with next fields */
/* XXX 2 bits hole, try to pack */
short int zz; /* 10 2 */
short int zzz:4; /* 12:12 2 */
/* XXX 12 bits hole, try to pack */
/* XXX 2 bytes hole, try to pack */
long int z; /* 16 8 */
/* size: 32, cachelines: 1, members: 6 */
/* sum members (bits): 124, holes: 2, sum holes: 4 */
/* bit holes: 5, sum bit holes: 36 bits */
/* padding: 8 */
/* last cacheline: 32 bytes */
};
No discrepanies between BTF/DWARF:
$ ../btfdiff test
$
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Mark Wielaard <mark@klomp.org>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-03-18 05:23:39 +01:00
|
|
|
int cur_bitfield_end = ctype->size * 8, cur_bitfield_size = 0;
|
|
|
|
int bit_holes = 0, byte_holes = 0;
|
|
|
|
int bit_start, bit_end;
|
|
|
|
int last_seen_bit = 0;
|
|
|
|
bool in_bitfield = false;
|
2006-10-28 23:22:42 +02:00
|
|
|
|
2018-12-21 18:18:26 +01:00
|
|
|
if (!tag__is_struct(class__tag(class)))
|
|
|
|
return;
|
|
|
|
|
2016-06-30 21:13:46 +02:00
|
|
|
if (class->holes_searched)
|
|
|
|
return;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
class->nr_holes = 0;
|
|
|
|
class->nr_bit_holes = 0;
|
2006-10-28 23:22:42 +02:00
|
|
|
|
2007-05-29 19:24:50 +02:00
|
|
|
type__for_each_member(ctype, pos) {
|
2007-05-25 00:11:53 +02:00
|
|
|
/* XXX for now just skip these */
|
|
|
|
if (pos->tag.tag == DW_TAG_inheritance &&
|
|
|
|
pos->virtuality == DW_VIRTUALITY_virtual)
|
|
|
|
continue;
|
|
|
|
|
2012-08-20 19:42:17 +02:00
|
|
|
if (pos->is_static)
|
|
|
|
continue;
|
|
|
|
|
class__find_holes: Zero out bit_hole/hole on member
pahole --reorganize is calling class__find_holes() multiple times on the
same struct to re-calculate holes. If it so happens that after reorg
last struct's member had hole previously, we are not going to clear it
out, which will lead to weird output and BFA, like this:
$ pahole -F btf --reorganize -C netns_frags ~/tmp/vmlinux-default
struct netns_frags {
long int high_thresh; /* 0 8 */
long int low_thresh; /* 8 8 */
int timeout; /* 16 4 */
int max_dist; /* 20 4 */
struct inet_frags * f; /* 24 8 */
atomic_long_t mem; /* 32 8 */
/* XXX 24 bytes hole, try to pack */
/* --- cacheline 1 boundary (64 bytes) --- */
struct rhashtable rhashtable; /* 64 136 */
/* XXX 56 bytes hole, try to pack */
/* size: 200, cachelines: 4, members: 7 */
/* sum members: 176, holes: 1, sum holes: 80 */
/* last cacheline: 8 bytes */
/* BRAIN FART ALERT! 200 bytes != 176 (member bytes) + 0 (member bits) + 80 (byte holes) + 0 (bit holes), diff = -448 bits */
}; /* saved 120 bytes and 1 cacheline! */
After this change:
$ pahole -F btf --reorganize -C netns_frags ~/tmp/vmlinux-defaultstruct netns_frags {
long int high_thresh; /* 0 8 */
long int low_thresh; /* 8 8 */
int timeout; /* 16 4 */
int max_dist; /* 20 4 */
struct inet_frags * f; /* 24 8 */
atomic_long_t mem; /* 32 8 */
/* XXX 24 bytes hole, try to pack */
/* --- cacheline 1 boundary (64 bytes) --- */
struct rhashtable rhashtable; /* 64 136 */
/* size: 200, cachelines: 4, members: 7 */
/* sum members: 176, holes: 1, sum holes: 24 */
/* last cacheline: 8 bytes */
}; /* saved 120 bytes and 1 cacheline! */
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Reported-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-04 01:26:06 +02:00
|
|
|
pos->bit_hole = 0;
|
|
|
|
pos->hole = 0;
|
|
|
|
|
dwarf_loader: Use DWARF recommended uniform bit offset scheme
Use uniform bit offset scheme as described in DWARF standard (though
apparently not really followed by major compilers), in which bit offset
is a natural extension of byte offset in both big- and little-endian
architectures.
BEFORE:
1. Bit offsets for little-endian are output as offsets from highest-order bit
of underlying int to highest-order bit of bitfield, so double-backwards for
little-endian arch and counter to how byte offsets are used, which point to
lowest-order bit of underlying type. This makes first bitfield to have bit
offset 27, instead of natural 0.
2. Bit offsets for big-endian are output as expected, by referencing
highest-order bit offset from highest-order bit of underlying int. This is
natural for big-endian platform, e.g., first bitfield has bit offset of 0.
3. Big-endian target also has problem with determining bit holes, because bit
positions have to be calculated differently for little- and big-endian
platforms and previous commit changed pahole logic to follow little-endian
semantics.
4. BTF encoder outputs uniform bit offset for both little- and big-endian
format (following DWARF's recommended bit offset scheme)
5. BTF loader, though, follows DWARF loader's format and outputs little-endian
bit offsets "double-backwards".
$ gcc -g dwarf_test.c -o dwarf_test
$ pahole -F dwarf dwarf_test
struct S {
int j:5; /* 0:27 4 */
int k:6; /* 0:21 4 */
int m:5; /* 0:16 4 */
int n:8; /* 0: 8 4 */
/* size: 4, cachelines: 1, members: 4 */
/* bit_padding: 8 bits */
/* last cacheline: 4 bytes */
};
$ pahole -JV dwarf_test
File dwarf_test:
[1] STRUCT S kind_flag=1 size=4 vlen=4
j type_id=2 bitfield_size=5 bits_offset=0
k type_id=2 bitfield_size=6 bits_offset=5
m type_id=2 bitfield_size=5 bits_offset=11
n type_id=2 bitfield_size=8 bits_offset=16
[2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
$ pahole -F btf dwarf_test
struct S {
int j:5; /* 0:27 4 */
int k:6; /* 0:21 4 */
int m:5; /* 0:16 4 */
int n:8; /* 0: 8 4 */
/* size: 4, cachelines: 1, members: 4 */
/* bit_padding: 8 bits */
/* last cacheline: 4 bytes */
};
$ aarch64-linux-gnu-gcc -mbig-endian -g -c dwarf_test.c -o dwarf_test.be
$ pahole -F dwarf dwarf_test.be
struct S {
/* XXX 27 bits hole, try to pack */
int j:5; /* 0: 0 4 */
/* XXX 245 bits hole, try to pack */
int k:6; /* 0: 5 4 */
/* XXX 245 bits hole, try to pack */
int m:5; /* 0:11 4 */
/* XXX 243 bits hole, try to pack */
int n:8; /* 0:16 4 */
/* size: 4, cachelines: 1, members: 4 */
/* bit holes: 4, sum bit holes: 760 bits */
/* bit_padding: 16 bits */
/* last cacheline: 4 bytes */
/* BRAIN FART ALERT! 4 bytes != 24 (member bits) + 0 (byte holes) + 760 (bit holes), diff = -768 bits */
};
$ pahole -JV dwarf_test.be
File dwarf_test.be:
[1] STRUCT S kind_flag=1 size=4 vlen=4
j type_id=2 bitfield_size=5 bits_offset=0
k type_id=2 bitfield_size=6 bits_offset=5
m type_id=2 bitfield_size=5 bits_offset=11
n type_id=2 bitfield_size=8 bits_offset=16
[2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
$ pahole -F btf dwarf_test.be
struct S {
/* XXX 27 bits hole, try to pack */
int j:5; /* 0: 0 4 */
/* XXX 245 bits hole, try to pack */
int k:6; /* 0: 5 4 */
/* XXX 245 bits hole, try to pack */
int m:5; /* 0:11 4 */
/* XXX 243 bits hole, try to pack */
int n:8; /* 0:16 4 */
/* size: 4, cachelines: 1, members: 4 */
/* bit holes: 4, sum bit holes: 760 bits */
/* bit_padding: 16 bits */
/* last cacheline: 4 bytes */
/* BRAIN FART ALERT! 4 bytes != 24 (member bits) + 0 (byte holes) + 760 (bit holes), diff = -768 bits */
};
AFTER:
1. Same output for little- and big-endian binaries, both for BTF and DWARF
loader.
2. For little-endian target, bit offsets are natural extensions of byte offset,
counting from lowest-order bit of underlying int to lowest-order bit of a
bitfield.
3. BTF encoder still emits correct and natural bit offsets (for both binaries).
4. No more BRAIN FART ALERTs for big-endian.
$ pahole -F dwarf dwarf_test
struct S {
int j:5; /* 0: 0 4 */
int k:6; /* 0: 5 4 */
int m:5; /* 0:11 4 */
int n:8; /* 0:16 4 */
/* size: 4, cachelines: 1, members: 4 */
/* bit_padding: 8 bits */
/* last cacheline: 4 bytes */
};
$ pahole -JV dwarf_test
File dwarf_test:
[1] STRUCT S kind_flag=1 size=4 vlen=4
j type_id=2 bitfield_size=5 bits_offset=0
k type_id=2 bitfield_size=6 bits_offset=5
m type_id=2 bitfield_size=5 bits_offset=11
n type_id=2 bitfield_size=8 bits_offset=16
[2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
$ pahole -F btf dwarf_test
struct S {
int j:5; /* 0: 0 4 */
int k:6; /* 0: 5 4 */
int m:5; /* 0:11 4 */
int n:8; /* 0:16 4 */
/* size: 4, cachelines: 1, members: 4 */
/* bit_padding: 8 bits */
/* last cacheline: 4 bytes */
};
$ pahole -F dwarf dwarf_test.be
struct S {
int j:5; /* 0: 0 4 */
int k:6; /* 0: 5 4 */
int m:5; /* 0:11 4 */
int n:8; /* 0:16 4 */
/* size: 4, cachelines: 1, members: 4 */
/* bit_padding: 8 bits */
/* last cacheline: 4 bytes */
};
$ pahole -JV dwarf_test.be
File dwarf_test.be:
[1] STRUCT S kind_flag=1 size=4 vlen=4
j type_id=2 bitfield_size=5 bits_offset=0
k type_id=2 bitfield_size=6 bits_offset=5
m type_id=2 bitfield_size=5 bits_offset=11
n type_id=2 bitfield_size=8 bits_offset=16
[2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
$ pahole -F btf dwarf_test.be
struct S {
int j:5; /* 0: 0 4 */
int k:6; /* 0: 5 4 */
int m:5; /* 0:11 4 */
int n:8; /* 0:16 4 */
/* size: 4, cachelines: 1, members: 4 */
/* bit_padding: 8 bits */
/* last cacheline: 4 bytes */
};
FOR REFERENCE. Relevant parts of DWARF output from GCC (clang outputs exactly
the same data) for both little- and big-endian binaries:
$ readelf -wi dwarf_test
Contents of the .debug_info section:
<snip>
<1><2d>: Abbrev Number: 2 (DW_TAG_structure_type)
<2e> DW_AT_name : S
<30> DW_AT_byte_size : 4
<31> DW_AT_decl_file : 1
<32> DW_AT_decl_line : 1
<33> DW_AT_decl_column : 8
<34> DW_AT_sibling : <0x71>
<2><38>: Abbrev Number: 3 (DW_TAG_member)
<39> DW_AT_name : j
<3b> DW_AT_decl_file : 1
<3c> DW_AT_decl_line : 2
<3d> DW_AT_decl_column : 6
<3e> DW_AT_type : <0x71>
<42> DW_AT_byte_size : 4
<43> DW_AT_bit_size : 5
<44> DW_AT_bit_offset : 27
<45> DW_AT_data_member_location: 0
<2><46>: Abbrev Number: 3 (DW_TAG_member)
<47> DW_AT_name : k
<49> DW_AT_decl_file : 1
<4a> DW_AT_decl_line : 3
<4b> DW_AT_decl_column : 6
<4c> DW_AT_type : <0x71>
<50> DW_AT_byte_size : 4
<51> DW_AT_bit_size : 6
<52> DW_AT_bit_offset : 21
<53> DW_AT_data_member_location: 0
<2><54>: Abbrev Number: 3 (DW_TAG_member)
<55> DW_AT_name : m
<57> DW_AT_decl_file : 1
<58> DW_AT_decl_line : 4
<59> DW_AT_decl_column : 6
<5a> DW_AT_type : <0x71>
<5e> DW_AT_byte_size : 4
<5f> DW_AT_bit_size : 5
<60> DW_AT_bit_offset : 16
<61> DW_AT_data_member_location: 0
<2><62>: Abbrev Number: 3 (DW_TAG_member)
<63> DW_AT_name : n
<65> DW_AT_decl_file : 1
<66> DW_AT_decl_line : 5
<67> DW_AT_decl_column : 6
<68> DW_AT_type : <0x71>
<6c> DW_AT_byte_size : 4
<6d> DW_AT_bit_size : 8
<6e> DW_AT_bit_offset : 8
<6f> DW_AT_data_member_location: 0
<2><70>: Abbrev Number: 0
<1><71>: Abbrev Number: 4 (DW_TAG_base_type)
<72> DW_AT_byte_size : 4
<73> DW_AT_encoding : 5 (signed)
<74> DW_AT_name : int
<snip>
$ readelf -wi dwarf_test.be
Contents of the .debug_info section:
<snip>
<1><2d>: Abbrev Number: 2 (DW_TAG_structure_type)
<2e> DW_AT_name : S
<30> DW_AT_byte_size : 4
<31> DW_AT_decl_file : 1
<32> DW_AT_decl_line : 1
<33> DW_AT_sibling : <0x6c>
<2><37>: Abbrev Number: 3 (DW_TAG_member)
<38> DW_AT_name : j
<3a> DW_AT_decl_file : 1
<3b> DW_AT_decl_line : 2
<3c> DW_AT_type : <0x6c>
<40> DW_AT_byte_size : 4
<41> DW_AT_bit_size : 5
<42> DW_AT_bit_offset : 0
<43> DW_AT_data_member_location: 0
<2><44>: Abbrev Number: 3 (DW_TAG_member)
<45> DW_AT_name : k
<47> DW_AT_decl_file : 1
<48> DW_AT_decl_line : 3
<49> DW_AT_type : <0x6c>
<4d> DW_AT_byte_size : 4
<4e> DW_AT_bit_size : 6
<4f> DW_AT_bit_offset : 5
<50> DW_AT_data_member_location: 0
<2><51>: Abbrev Number: 3 (DW_TAG_member)
<52> DW_AT_name : m
<54> DW_AT_decl_file : 1
<55> DW_AT_decl_line : 4
<56> DW_AT_type : <0x6c>
<5a> DW_AT_byte_size : 4
<5b> DW_AT_bit_size : 5
<5c> DW_AT_bit_offset : 11
<5d> DW_AT_data_member_location: 0
<2><5e>: Abbrev Number: 3 (DW_TAG_member)
<5f> DW_AT_name : n
<61> DW_AT_decl_file : 1
<62> DW_AT_decl_line : 5
<63> DW_AT_type : <0x6c>
<67> DW_AT_byte_size : 4
<68> DW_AT_bit_size : 8
<69> DW_AT_bit_offset : 16
<6a> DW_AT_data_member_location: 0
<snip>
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Mark Wielaard <mark@klomp.org>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-03-18 05:23:42 +01:00
|
|
|
bit_start = pos->bit_offset;
|
dwarves: Revamp bit/byte holes detection logic
This patch rewrites hole detection logic. Now many crazy combinations of
bitfields and normal fields are handled correctly.
This was tested on allyesconfig kernel and differences before/after were
always in favor of new algorithm.
With subsequent change in next patch, there are no more BRAIN FART
ALERTs for allyesconfig and DWARF and BTF outputs have no discrepanies.
Example:
$ cat test.c
struct s {
short : 4; /* this one is not emitted in DWARF/BTF */
short a : 4;
int x;
int : 10;
int y : 4;
short zz;
short zzz : 4;
long z;
short : 4;
};
int main() {
struct s s;
return 0;
}
$ gcc -g test.c -o test
$ ~/pahole/build/pahole -J test
$ ~/pahole/build/pahole -F dwarf test
struct s {
/* XXX 4 bits hole, try to pack */
short int a:4; /* 0: 8 2 */
/* XXX 8 bits hole, try to pack */
/* XXX 2 bytes hole, try to pack */
int x; /* 4 4 */
/* XXX 10 bits hole, try to pack */
int y:4; /* 8:18 4 */
/* Bitfield combined with next fields */
/* XXX 2 bits hole, try to pack */
short int zz; /* 10 2 */
short int zzz:4; /* 12:12 2 */
/* XXX 12 bits hole, try to pack */
/* XXX 2 bytes hole, try to pack */
long int z; /* 16 8 */
/* size: 32, cachelines: 1, members: 6 */
/* sum members (bits): 124, holes: 2, sum holes: 4 */
/* bit holes: 5, sum bit holes: 36 bits */
/* padding: 8 */
/* last cacheline: 32 bytes */
};
No discrepanies between BTF/DWARF:
$ ../btfdiff test
$
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Mark Wielaard <mark@klomp.org>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-03-18 05:23:39 +01:00
|
|
|
if (pos->bitfield_size) {
|
|
|
|
bit_end = bit_start + pos->bitfield_size;
|
|
|
|
} else {
|
|
|
|
bit_end = bit_start + pos->byte_size * 8;
|
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
|
|
|
|
dwarves: Revamp bit/byte holes detection logic
This patch rewrites hole detection logic. Now many crazy combinations of
bitfields and normal fields are handled correctly.
This was tested on allyesconfig kernel and differences before/after were
always in favor of new algorithm.
With subsequent change in next patch, there are no more BRAIN FART
ALERTs for allyesconfig and DWARF and BTF outputs have no discrepanies.
Example:
$ cat test.c
struct s {
short : 4; /* this one is not emitted in DWARF/BTF */
short a : 4;
int x;
int : 10;
int y : 4;
short zz;
short zzz : 4;
long z;
short : 4;
};
int main() {
struct s s;
return 0;
}
$ gcc -g test.c -o test
$ ~/pahole/build/pahole -J test
$ ~/pahole/build/pahole -F dwarf test
struct s {
/* XXX 4 bits hole, try to pack */
short int a:4; /* 0: 8 2 */
/* XXX 8 bits hole, try to pack */
/* XXX 2 bytes hole, try to pack */
int x; /* 4 4 */
/* XXX 10 bits hole, try to pack */
int y:4; /* 8:18 4 */
/* Bitfield combined with next fields */
/* XXX 2 bits hole, try to pack */
short int zz; /* 10 2 */
short int zzz:4; /* 12:12 2 */
/* XXX 12 bits hole, try to pack */
/* XXX 2 bytes hole, try to pack */
long int z; /* 16 8 */
/* size: 32, cachelines: 1, members: 6 */
/* sum members (bits): 124, holes: 2, sum holes: 4 */
/* bit holes: 5, sum bit holes: 36 bits */
/* padding: 8 */
/* last cacheline: 32 bytes */
};
No discrepanies between BTF/DWARF:
$ ../btfdiff test
$
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Mark Wielaard <mark@klomp.org>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-03-18 05:23:39 +01:00
|
|
|
bit_holes = 0;
|
|
|
|
byte_holes = 0;
|
|
|
|
if (in_bitfield) {
|
|
|
|
/* check if we have some trailing bitfield bits left */
|
|
|
|
int bitfield_end = min(bit_start, cur_bitfield_end);
|
|
|
|
bit_holes = bitfield_end - last_seen_bit;
|
|
|
|
last_seen_bit = bitfield_end;
|
|
|
|
}
|
|
|
|
if (pos->bitfield_size) {
|
|
|
|
int aligned_start = pos->byte_offset * 8;
|
|
|
|
/* we can have some alignment byte padding left,
|
dwarves: Fix classification of byte/bit hole for aligned bitfield
This patch fixes a bug in class__find_holes() with determining byte hole
as a bit hole in case where previous member is not bitfield, but current
one is aligned bitfield. See example below, notice hole classification
hw_stopped field..
$ cat test/bit_test.c
struct s {
long unused: 62;
/* 2 bit hole */
int hw_stopped;
/* 4 byte hole */
long unused2: 55;
/* 9 bit padding */
};
int main() {
static struct s s;
return 0;
}
$ clang -g test/bit_test.c -o test/bit_test
$ pahole -JV test/bit_test
File test/bit_test:
[1] STRUCT s kind_flag=1 size=24 vlen=3
unused type_id=2 bitfield_size=62 bits_offset=0
hw_stopped type_id=3 bitfield_size=0 bits_offset=64
unused2 type_id=2 bitfield_size=55 bits_offset=128
[2] INT long int size=8 bit_offset=0 nr_bits=64 encoding=SIGNED
[3] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
BEFORE:
$ pahole -F btf test/bit_test
struct s {
long int unused:62; /* 0: 0 8 */
/* XXX 2 bits hole, try to pack */
int hw_stopped; /* 8 4 */
/* XXX 32 bits hole, try to pack */
long int unused2:55; /* 16: 0 8 */
/* size: 24, cachelines: 1, members: 3 */
/* sum members: 4 */
/* sum bitfield members: 117 bits, bit holes: 2, sum bit holes: 34 bits */
/* bit_padding: 9 bits */
/* last cacheline: 24 bytes */
};
AFTER:
$ pahole -F btf test/bit_test
struct s {
long int unused:62; /* 0: 0 8 */
/* XXX 2 bits hole, try to pack */
int hw_stopped; /* 8 4 */
/* XXX 4 bytes hole, try to pack */
long int unused2:55; /* 16: 0 8 */
/* size: 24, cachelines: 1, members: 3 */
/* sum members: 4, holes: 1, sum holes: 4 */
/* sum bitfield members: 117 bits, bit holes: 1, sum bit holes: 2 bits */
/* bit_padding: 9 bits */
/* last cacheline: 24 bytes */
};
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-03 09:01:46 +02:00
|
|
|
* but we need to be careful about bitfield spanning
|
dwarves: Revamp bit/byte holes detection logic
This patch rewrites hole detection logic. Now many crazy combinations of
bitfields and normal fields are handled correctly.
This was tested on allyesconfig kernel and differences before/after were
always in favor of new algorithm.
With subsequent change in next patch, there are no more BRAIN FART
ALERTs for allyesconfig and DWARF and BTF outputs have no discrepanies.
Example:
$ cat test.c
struct s {
short : 4; /* this one is not emitted in DWARF/BTF */
short a : 4;
int x;
int : 10;
int y : 4;
short zz;
short zzz : 4;
long z;
short : 4;
};
int main() {
struct s s;
return 0;
}
$ gcc -g test.c -o test
$ ~/pahole/build/pahole -J test
$ ~/pahole/build/pahole -F dwarf test
struct s {
/* XXX 4 bits hole, try to pack */
short int a:4; /* 0: 8 2 */
/* XXX 8 bits hole, try to pack */
/* XXX 2 bytes hole, try to pack */
int x; /* 4 4 */
/* XXX 10 bits hole, try to pack */
int y:4; /* 8:18 4 */
/* Bitfield combined with next fields */
/* XXX 2 bits hole, try to pack */
short int zz; /* 10 2 */
short int zzz:4; /* 12:12 2 */
/* XXX 12 bits hole, try to pack */
/* XXX 2 bytes hole, try to pack */
long int z; /* 16 8 */
/* size: 32, cachelines: 1, members: 6 */
/* sum members (bits): 124, holes: 2, sum holes: 4 */
/* bit holes: 5, sum bit holes: 36 bits */
/* padding: 8 */
/* last cacheline: 32 bytes */
};
No discrepanies between BTF/DWARF:
$ ../btfdiff test
$
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Mark Wielaard <mark@klomp.org>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-03-18 05:23:39 +01:00
|
|
|
* multiple aligned boundaries */
|
dwarves: Fix classification of byte/bit hole for aligned bitfield
This patch fixes a bug in class__find_holes() with determining byte hole
as a bit hole in case where previous member is not bitfield, but current
one is aligned bitfield. See example below, notice hole classification
hw_stopped field..
$ cat test/bit_test.c
struct s {
long unused: 62;
/* 2 bit hole */
int hw_stopped;
/* 4 byte hole */
long unused2: 55;
/* 9 bit padding */
};
int main() {
static struct s s;
return 0;
}
$ clang -g test/bit_test.c -o test/bit_test
$ pahole -JV test/bit_test
File test/bit_test:
[1] STRUCT s kind_flag=1 size=24 vlen=3
unused type_id=2 bitfield_size=62 bits_offset=0
hw_stopped type_id=3 bitfield_size=0 bits_offset=64
unused2 type_id=2 bitfield_size=55 bits_offset=128
[2] INT long int size=8 bit_offset=0 nr_bits=64 encoding=SIGNED
[3] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
BEFORE:
$ pahole -F btf test/bit_test
struct s {
long int unused:62; /* 0: 0 8 */
/* XXX 2 bits hole, try to pack */
int hw_stopped; /* 8 4 */
/* XXX 32 bits hole, try to pack */
long int unused2:55; /* 16: 0 8 */
/* size: 24, cachelines: 1, members: 3 */
/* sum members: 4 */
/* sum bitfield members: 117 bits, bit holes: 2, sum bit holes: 34 bits */
/* bit_padding: 9 bits */
/* last cacheline: 24 bytes */
};
AFTER:
$ pahole -F btf test/bit_test
struct s {
long int unused:62; /* 0: 0 8 */
/* XXX 2 bits hole, try to pack */
int hw_stopped; /* 8 4 */
/* XXX 4 bytes hole, try to pack */
long int unused2:55; /* 16: 0 8 */
/* size: 24, cachelines: 1, members: 3 */
/* sum members: 4, holes: 1, sum holes: 4 */
/* sum bitfield members: 117 bits, bit holes: 1, sum bit holes: 2 bits */
/* bit_padding: 9 bits */
/* last cacheline: 24 bytes */
};
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-03 09:01:46 +02:00
|
|
|
if (last_seen_bit < aligned_start && aligned_start <= bit_start) {
|
dwarves: Revamp bit/byte holes detection logic
This patch rewrites hole detection logic. Now many crazy combinations of
bitfields and normal fields are handled correctly.
This was tested on allyesconfig kernel and differences before/after were
always in favor of new algorithm.
With subsequent change in next patch, there are no more BRAIN FART
ALERTs for allyesconfig and DWARF and BTF outputs have no discrepanies.
Example:
$ cat test.c
struct s {
short : 4; /* this one is not emitted in DWARF/BTF */
short a : 4;
int x;
int : 10;
int y : 4;
short zz;
short zzz : 4;
long z;
short : 4;
};
int main() {
struct s s;
return 0;
}
$ gcc -g test.c -o test
$ ~/pahole/build/pahole -J test
$ ~/pahole/build/pahole -F dwarf test
struct s {
/* XXX 4 bits hole, try to pack */
short int a:4; /* 0: 8 2 */
/* XXX 8 bits hole, try to pack */
/* XXX 2 bytes hole, try to pack */
int x; /* 4 4 */
/* XXX 10 bits hole, try to pack */
int y:4; /* 8:18 4 */
/* Bitfield combined with next fields */
/* XXX 2 bits hole, try to pack */
short int zz; /* 10 2 */
short int zzz:4; /* 12:12 2 */
/* XXX 12 bits hole, try to pack */
/* XXX 2 bytes hole, try to pack */
long int z; /* 16 8 */
/* size: 32, cachelines: 1, members: 6 */
/* sum members (bits): 124, holes: 2, sum holes: 4 */
/* bit holes: 5, sum bit holes: 36 bits */
/* padding: 8 */
/* last cacheline: 32 bytes */
};
No discrepanies between BTF/DWARF:
$ ../btfdiff test
$
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Mark Wielaard <mark@klomp.org>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-03-18 05:23:39 +01:00
|
|
|
byte_holes = pos->byte_offset - last_seen_bit / 8;
|
|
|
|
last_seen_bit = aligned_start;
|
|
|
|
}
|
|
|
|
bit_holes += bit_start - last_seen_bit;
|
|
|
|
} else {
|
|
|
|
byte_holes = bit_start/8 - last_seen_bit/8;
|
|
|
|
}
|
|
|
|
last_seen_bit = bit_end;
|
|
|
|
|
|
|
|
if (pos->bitfield_size) {
|
|
|
|
in_bitfield = true;
|
|
|
|
/* if it's a new bitfield set or same, but with
|
|
|
|
* bigger-sized type, readjust size and end bit */
|
dwarf_loader: Use DWARF recommended uniform bit offset scheme
Use uniform bit offset scheme as described in DWARF standard (though
apparently not really followed by major compilers), in which bit offset
is a natural extension of byte offset in both big- and little-endian
architectures.
BEFORE:
1. Bit offsets for little-endian are output as offsets from highest-order bit
of underlying int to highest-order bit of bitfield, so double-backwards for
little-endian arch and counter to how byte offsets are used, which point to
lowest-order bit of underlying type. This makes first bitfield to have bit
offset 27, instead of natural 0.
2. Bit offsets for big-endian are output as expected, by referencing
highest-order bit offset from highest-order bit of underlying int. This is
natural for big-endian platform, e.g., first bitfield has bit offset of 0.
3. Big-endian target also has problem with determining bit holes, because bit
positions have to be calculated differently for little- and big-endian
platforms and previous commit changed pahole logic to follow little-endian
semantics.
4. BTF encoder outputs uniform bit offset for both little- and big-endian
format (following DWARF's recommended bit offset scheme)
5. BTF loader, though, follows DWARF loader's format and outputs little-endian
bit offsets "double-backwards".
$ gcc -g dwarf_test.c -o dwarf_test
$ pahole -F dwarf dwarf_test
struct S {
int j:5; /* 0:27 4 */
int k:6; /* 0:21 4 */
int m:5; /* 0:16 4 */
int n:8; /* 0: 8 4 */
/* size: 4, cachelines: 1, members: 4 */
/* bit_padding: 8 bits */
/* last cacheline: 4 bytes */
};
$ pahole -JV dwarf_test
File dwarf_test:
[1] STRUCT S kind_flag=1 size=4 vlen=4
j type_id=2 bitfield_size=5 bits_offset=0
k type_id=2 bitfield_size=6 bits_offset=5
m type_id=2 bitfield_size=5 bits_offset=11
n type_id=2 bitfield_size=8 bits_offset=16
[2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
$ pahole -F btf dwarf_test
struct S {
int j:5; /* 0:27 4 */
int k:6; /* 0:21 4 */
int m:5; /* 0:16 4 */
int n:8; /* 0: 8 4 */
/* size: 4, cachelines: 1, members: 4 */
/* bit_padding: 8 bits */
/* last cacheline: 4 bytes */
};
$ aarch64-linux-gnu-gcc -mbig-endian -g -c dwarf_test.c -o dwarf_test.be
$ pahole -F dwarf dwarf_test.be
struct S {
/* XXX 27 bits hole, try to pack */
int j:5; /* 0: 0 4 */
/* XXX 245 bits hole, try to pack */
int k:6; /* 0: 5 4 */
/* XXX 245 bits hole, try to pack */
int m:5; /* 0:11 4 */
/* XXX 243 bits hole, try to pack */
int n:8; /* 0:16 4 */
/* size: 4, cachelines: 1, members: 4 */
/* bit holes: 4, sum bit holes: 760 bits */
/* bit_padding: 16 bits */
/* last cacheline: 4 bytes */
/* BRAIN FART ALERT! 4 bytes != 24 (member bits) + 0 (byte holes) + 760 (bit holes), diff = -768 bits */
};
$ pahole -JV dwarf_test.be
File dwarf_test.be:
[1] STRUCT S kind_flag=1 size=4 vlen=4
j type_id=2 bitfield_size=5 bits_offset=0
k type_id=2 bitfield_size=6 bits_offset=5
m type_id=2 bitfield_size=5 bits_offset=11
n type_id=2 bitfield_size=8 bits_offset=16
[2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
$ pahole -F btf dwarf_test.be
struct S {
/* XXX 27 bits hole, try to pack */
int j:5; /* 0: 0 4 */
/* XXX 245 bits hole, try to pack */
int k:6; /* 0: 5 4 */
/* XXX 245 bits hole, try to pack */
int m:5; /* 0:11 4 */
/* XXX 243 bits hole, try to pack */
int n:8; /* 0:16 4 */
/* size: 4, cachelines: 1, members: 4 */
/* bit holes: 4, sum bit holes: 760 bits */
/* bit_padding: 16 bits */
/* last cacheline: 4 bytes */
/* BRAIN FART ALERT! 4 bytes != 24 (member bits) + 0 (byte holes) + 760 (bit holes), diff = -768 bits */
};
AFTER:
1. Same output for little- and big-endian binaries, both for BTF and DWARF
loader.
2. For little-endian target, bit offsets are natural extensions of byte offset,
counting from lowest-order bit of underlying int to lowest-order bit of a
bitfield.
3. BTF encoder still emits correct and natural bit offsets (for both binaries).
4. No more BRAIN FART ALERTs for big-endian.
$ pahole -F dwarf dwarf_test
struct S {
int j:5; /* 0: 0 4 */
int k:6; /* 0: 5 4 */
int m:5; /* 0:11 4 */
int n:8; /* 0:16 4 */
/* size: 4, cachelines: 1, members: 4 */
/* bit_padding: 8 bits */
/* last cacheline: 4 bytes */
};
$ pahole -JV dwarf_test
File dwarf_test:
[1] STRUCT S kind_flag=1 size=4 vlen=4
j type_id=2 bitfield_size=5 bits_offset=0
k type_id=2 bitfield_size=6 bits_offset=5
m type_id=2 bitfield_size=5 bits_offset=11
n type_id=2 bitfield_size=8 bits_offset=16
[2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
$ pahole -F btf dwarf_test
struct S {
int j:5; /* 0: 0 4 */
int k:6; /* 0: 5 4 */
int m:5; /* 0:11 4 */
int n:8; /* 0:16 4 */
/* size: 4, cachelines: 1, members: 4 */
/* bit_padding: 8 bits */
/* last cacheline: 4 bytes */
};
$ pahole -F dwarf dwarf_test.be
struct S {
int j:5; /* 0: 0 4 */
int k:6; /* 0: 5 4 */
int m:5; /* 0:11 4 */
int n:8; /* 0:16 4 */
/* size: 4, cachelines: 1, members: 4 */
/* bit_padding: 8 bits */
/* last cacheline: 4 bytes */
};
$ pahole -JV dwarf_test.be
File dwarf_test.be:
[1] STRUCT S kind_flag=1 size=4 vlen=4
j type_id=2 bitfield_size=5 bits_offset=0
k type_id=2 bitfield_size=6 bits_offset=5
m type_id=2 bitfield_size=5 bits_offset=11
n type_id=2 bitfield_size=8 bits_offset=16
[2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
$ pahole -F btf dwarf_test.be
struct S {
int j:5; /* 0: 0 4 */
int k:6; /* 0: 5 4 */
int m:5; /* 0:11 4 */
int n:8; /* 0:16 4 */
/* size: 4, cachelines: 1, members: 4 */
/* bit_padding: 8 bits */
/* last cacheline: 4 bytes */
};
FOR REFERENCE. Relevant parts of DWARF output from GCC (clang outputs exactly
the same data) for both little- and big-endian binaries:
$ readelf -wi dwarf_test
Contents of the .debug_info section:
<snip>
<1><2d>: Abbrev Number: 2 (DW_TAG_structure_type)
<2e> DW_AT_name : S
<30> DW_AT_byte_size : 4
<31> DW_AT_decl_file : 1
<32> DW_AT_decl_line : 1
<33> DW_AT_decl_column : 8
<34> DW_AT_sibling : <0x71>
<2><38>: Abbrev Number: 3 (DW_TAG_member)
<39> DW_AT_name : j
<3b> DW_AT_decl_file : 1
<3c> DW_AT_decl_line : 2
<3d> DW_AT_decl_column : 6
<3e> DW_AT_type : <0x71>
<42> DW_AT_byte_size : 4
<43> DW_AT_bit_size : 5
<44> DW_AT_bit_offset : 27
<45> DW_AT_data_member_location: 0
<2><46>: Abbrev Number: 3 (DW_TAG_member)
<47> DW_AT_name : k
<49> DW_AT_decl_file : 1
<4a> DW_AT_decl_line : 3
<4b> DW_AT_decl_column : 6
<4c> DW_AT_type : <0x71>
<50> DW_AT_byte_size : 4
<51> DW_AT_bit_size : 6
<52> DW_AT_bit_offset : 21
<53> DW_AT_data_member_location: 0
<2><54>: Abbrev Number: 3 (DW_TAG_member)
<55> DW_AT_name : m
<57> DW_AT_decl_file : 1
<58> DW_AT_decl_line : 4
<59> DW_AT_decl_column : 6
<5a> DW_AT_type : <0x71>
<5e> DW_AT_byte_size : 4
<5f> DW_AT_bit_size : 5
<60> DW_AT_bit_offset : 16
<61> DW_AT_data_member_location: 0
<2><62>: Abbrev Number: 3 (DW_TAG_member)
<63> DW_AT_name : n
<65> DW_AT_decl_file : 1
<66> DW_AT_decl_line : 5
<67> DW_AT_decl_column : 6
<68> DW_AT_type : <0x71>
<6c> DW_AT_byte_size : 4
<6d> DW_AT_bit_size : 8
<6e> DW_AT_bit_offset : 8
<6f> DW_AT_data_member_location: 0
<2><70>: Abbrev Number: 0
<1><71>: Abbrev Number: 4 (DW_TAG_base_type)
<72> DW_AT_byte_size : 4
<73> DW_AT_encoding : 5 (signed)
<74> DW_AT_name : int
<snip>
$ readelf -wi dwarf_test.be
Contents of the .debug_info section:
<snip>
<1><2d>: Abbrev Number: 2 (DW_TAG_structure_type)
<2e> DW_AT_name : S
<30> DW_AT_byte_size : 4
<31> DW_AT_decl_file : 1
<32> DW_AT_decl_line : 1
<33> DW_AT_sibling : <0x6c>
<2><37>: Abbrev Number: 3 (DW_TAG_member)
<38> DW_AT_name : j
<3a> DW_AT_decl_file : 1
<3b> DW_AT_decl_line : 2
<3c> DW_AT_type : <0x6c>
<40> DW_AT_byte_size : 4
<41> DW_AT_bit_size : 5
<42> DW_AT_bit_offset : 0
<43> DW_AT_data_member_location: 0
<2><44>: Abbrev Number: 3 (DW_TAG_member)
<45> DW_AT_name : k
<47> DW_AT_decl_file : 1
<48> DW_AT_decl_line : 3
<49> DW_AT_type : <0x6c>
<4d> DW_AT_byte_size : 4
<4e> DW_AT_bit_size : 6
<4f> DW_AT_bit_offset : 5
<50> DW_AT_data_member_location: 0
<2><51>: Abbrev Number: 3 (DW_TAG_member)
<52> DW_AT_name : m
<54> DW_AT_decl_file : 1
<55> DW_AT_decl_line : 4
<56> DW_AT_type : <0x6c>
<5a> DW_AT_byte_size : 4
<5b> DW_AT_bit_size : 5
<5c> DW_AT_bit_offset : 11
<5d> DW_AT_data_member_location: 0
<2><5e>: Abbrev Number: 3 (DW_TAG_member)
<5f> DW_AT_name : n
<61> DW_AT_decl_file : 1
<62> DW_AT_decl_line : 5
<63> DW_AT_type : <0x6c>
<67> DW_AT_byte_size : 4
<68> DW_AT_bit_size : 8
<69> DW_AT_bit_offset : 16
<6a> DW_AT_data_member_location: 0
<snip>
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Mark Wielaard <mark@klomp.org>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-03-18 05:23:42 +01:00
|
|
|
if (bit_end > cur_bitfield_end || pos->bit_size > cur_bitfield_size) {
|
dwarves: Revamp bit/byte holes detection logic
This patch rewrites hole detection logic. Now many crazy combinations of
bitfields and normal fields are handled correctly.
This was tested on allyesconfig kernel and differences before/after were
always in favor of new algorithm.
With subsequent change in next patch, there are no more BRAIN FART
ALERTs for allyesconfig and DWARF and BTF outputs have no discrepanies.
Example:
$ cat test.c
struct s {
short : 4; /* this one is not emitted in DWARF/BTF */
short a : 4;
int x;
int : 10;
int y : 4;
short zz;
short zzz : 4;
long z;
short : 4;
};
int main() {
struct s s;
return 0;
}
$ gcc -g test.c -o test
$ ~/pahole/build/pahole -J test
$ ~/pahole/build/pahole -F dwarf test
struct s {
/* XXX 4 bits hole, try to pack */
short int a:4; /* 0: 8 2 */
/* XXX 8 bits hole, try to pack */
/* XXX 2 bytes hole, try to pack */
int x; /* 4 4 */
/* XXX 10 bits hole, try to pack */
int y:4; /* 8:18 4 */
/* Bitfield combined with next fields */
/* XXX 2 bits hole, try to pack */
short int zz; /* 10 2 */
short int zzz:4; /* 12:12 2 */
/* XXX 12 bits hole, try to pack */
/* XXX 2 bytes hole, try to pack */
long int z; /* 16 8 */
/* size: 32, cachelines: 1, members: 6 */
/* sum members (bits): 124, holes: 2, sum holes: 4 */
/* bit holes: 5, sum bit holes: 36 bits */
/* padding: 8 */
/* last cacheline: 32 bytes */
};
No discrepanies between BTF/DWARF:
$ ../btfdiff test
$
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Mark Wielaard <mark@klomp.org>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-03-18 05:23:39 +01:00
|
|
|
cur_bitfield_size = pos->bit_size;
|
|
|
|
cur_bitfield_end = pos->byte_offset * 8 + cur_bitfield_size;
|
dwarf_loader: Use DWARF recommended uniform bit offset scheme
Use uniform bit offset scheme as described in DWARF standard (though
apparently not really followed by major compilers), in which bit offset
is a natural extension of byte offset in both big- and little-endian
architectures.
BEFORE:
1. Bit offsets for little-endian are output as offsets from highest-order bit
of underlying int to highest-order bit of bitfield, so double-backwards for
little-endian arch and counter to how byte offsets are used, which point to
lowest-order bit of underlying type. This makes first bitfield to have bit
offset 27, instead of natural 0.
2. Bit offsets for big-endian are output as expected, by referencing
highest-order bit offset from highest-order bit of underlying int. This is
natural for big-endian platform, e.g., first bitfield has bit offset of 0.
3. Big-endian target also has problem with determining bit holes, because bit
positions have to be calculated differently for little- and big-endian
platforms and previous commit changed pahole logic to follow little-endian
semantics.
4. BTF encoder outputs uniform bit offset for both little- and big-endian
format (following DWARF's recommended bit offset scheme)
5. BTF loader, though, follows DWARF loader's format and outputs little-endian
bit offsets "double-backwards".
$ gcc -g dwarf_test.c -o dwarf_test
$ pahole -F dwarf dwarf_test
struct S {
int j:5; /* 0:27 4 */
int k:6; /* 0:21 4 */
int m:5; /* 0:16 4 */
int n:8; /* 0: 8 4 */
/* size: 4, cachelines: 1, members: 4 */
/* bit_padding: 8 bits */
/* last cacheline: 4 bytes */
};
$ pahole -JV dwarf_test
File dwarf_test:
[1] STRUCT S kind_flag=1 size=4 vlen=4
j type_id=2 bitfield_size=5 bits_offset=0
k type_id=2 bitfield_size=6 bits_offset=5
m type_id=2 bitfield_size=5 bits_offset=11
n type_id=2 bitfield_size=8 bits_offset=16
[2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
$ pahole -F btf dwarf_test
struct S {
int j:5; /* 0:27 4 */
int k:6; /* 0:21 4 */
int m:5; /* 0:16 4 */
int n:8; /* 0: 8 4 */
/* size: 4, cachelines: 1, members: 4 */
/* bit_padding: 8 bits */
/* last cacheline: 4 bytes */
};
$ aarch64-linux-gnu-gcc -mbig-endian -g -c dwarf_test.c -o dwarf_test.be
$ pahole -F dwarf dwarf_test.be
struct S {
/* XXX 27 bits hole, try to pack */
int j:5; /* 0: 0 4 */
/* XXX 245 bits hole, try to pack */
int k:6; /* 0: 5 4 */
/* XXX 245 bits hole, try to pack */
int m:5; /* 0:11 4 */
/* XXX 243 bits hole, try to pack */
int n:8; /* 0:16 4 */
/* size: 4, cachelines: 1, members: 4 */
/* bit holes: 4, sum bit holes: 760 bits */
/* bit_padding: 16 bits */
/* last cacheline: 4 bytes */
/* BRAIN FART ALERT! 4 bytes != 24 (member bits) + 0 (byte holes) + 760 (bit holes), diff = -768 bits */
};
$ pahole -JV dwarf_test.be
File dwarf_test.be:
[1] STRUCT S kind_flag=1 size=4 vlen=4
j type_id=2 bitfield_size=5 bits_offset=0
k type_id=2 bitfield_size=6 bits_offset=5
m type_id=2 bitfield_size=5 bits_offset=11
n type_id=2 bitfield_size=8 bits_offset=16
[2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
$ pahole -F btf dwarf_test.be
struct S {
/* XXX 27 bits hole, try to pack */
int j:5; /* 0: 0 4 */
/* XXX 245 bits hole, try to pack */
int k:6; /* 0: 5 4 */
/* XXX 245 bits hole, try to pack */
int m:5; /* 0:11 4 */
/* XXX 243 bits hole, try to pack */
int n:8; /* 0:16 4 */
/* size: 4, cachelines: 1, members: 4 */
/* bit holes: 4, sum bit holes: 760 bits */
/* bit_padding: 16 bits */
/* last cacheline: 4 bytes */
/* BRAIN FART ALERT! 4 bytes != 24 (member bits) + 0 (byte holes) + 760 (bit holes), diff = -768 bits */
};
AFTER:
1. Same output for little- and big-endian binaries, both for BTF and DWARF
loader.
2. For little-endian target, bit offsets are natural extensions of byte offset,
counting from lowest-order bit of underlying int to lowest-order bit of a
bitfield.
3. BTF encoder still emits correct and natural bit offsets (for both binaries).
4. No more BRAIN FART ALERTs for big-endian.
$ pahole -F dwarf dwarf_test
struct S {
int j:5; /* 0: 0 4 */
int k:6; /* 0: 5 4 */
int m:5; /* 0:11 4 */
int n:8; /* 0:16 4 */
/* size: 4, cachelines: 1, members: 4 */
/* bit_padding: 8 bits */
/* last cacheline: 4 bytes */
};
$ pahole -JV dwarf_test
File dwarf_test:
[1] STRUCT S kind_flag=1 size=4 vlen=4
j type_id=2 bitfield_size=5 bits_offset=0
k type_id=2 bitfield_size=6 bits_offset=5
m type_id=2 bitfield_size=5 bits_offset=11
n type_id=2 bitfield_size=8 bits_offset=16
[2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
$ pahole -F btf dwarf_test
struct S {
int j:5; /* 0: 0 4 */
int k:6; /* 0: 5 4 */
int m:5; /* 0:11 4 */
int n:8; /* 0:16 4 */
/* size: 4, cachelines: 1, members: 4 */
/* bit_padding: 8 bits */
/* last cacheline: 4 bytes */
};
$ pahole -F dwarf dwarf_test.be
struct S {
int j:5; /* 0: 0 4 */
int k:6; /* 0: 5 4 */
int m:5; /* 0:11 4 */
int n:8; /* 0:16 4 */
/* size: 4, cachelines: 1, members: 4 */
/* bit_padding: 8 bits */
/* last cacheline: 4 bytes */
};
$ pahole -JV dwarf_test.be
File dwarf_test.be:
[1] STRUCT S kind_flag=1 size=4 vlen=4
j type_id=2 bitfield_size=5 bits_offset=0
k type_id=2 bitfield_size=6 bits_offset=5
m type_id=2 bitfield_size=5 bits_offset=11
n type_id=2 bitfield_size=8 bits_offset=16
[2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
$ pahole -F btf dwarf_test.be
struct S {
int j:5; /* 0: 0 4 */
int k:6; /* 0: 5 4 */
int m:5; /* 0:11 4 */
int n:8; /* 0:16 4 */
/* size: 4, cachelines: 1, members: 4 */
/* bit_padding: 8 bits */
/* last cacheline: 4 bytes */
};
FOR REFERENCE. Relevant parts of DWARF output from GCC (clang outputs exactly
the same data) for both little- and big-endian binaries:
$ readelf -wi dwarf_test
Contents of the .debug_info section:
<snip>
<1><2d>: Abbrev Number: 2 (DW_TAG_structure_type)
<2e> DW_AT_name : S
<30> DW_AT_byte_size : 4
<31> DW_AT_decl_file : 1
<32> DW_AT_decl_line : 1
<33> DW_AT_decl_column : 8
<34> DW_AT_sibling : <0x71>
<2><38>: Abbrev Number: 3 (DW_TAG_member)
<39> DW_AT_name : j
<3b> DW_AT_decl_file : 1
<3c> DW_AT_decl_line : 2
<3d> DW_AT_decl_column : 6
<3e> DW_AT_type : <0x71>
<42> DW_AT_byte_size : 4
<43> DW_AT_bit_size : 5
<44> DW_AT_bit_offset : 27
<45> DW_AT_data_member_location: 0
<2><46>: Abbrev Number: 3 (DW_TAG_member)
<47> DW_AT_name : k
<49> DW_AT_decl_file : 1
<4a> DW_AT_decl_line : 3
<4b> DW_AT_decl_column : 6
<4c> DW_AT_type : <0x71>
<50> DW_AT_byte_size : 4
<51> DW_AT_bit_size : 6
<52> DW_AT_bit_offset : 21
<53> DW_AT_data_member_location: 0
<2><54>: Abbrev Number: 3 (DW_TAG_member)
<55> DW_AT_name : m
<57> DW_AT_decl_file : 1
<58> DW_AT_decl_line : 4
<59> DW_AT_decl_column : 6
<5a> DW_AT_type : <0x71>
<5e> DW_AT_byte_size : 4
<5f> DW_AT_bit_size : 5
<60> DW_AT_bit_offset : 16
<61> DW_AT_data_member_location: 0
<2><62>: Abbrev Number: 3 (DW_TAG_member)
<63> DW_AT_name : n
<65> DW_AT_decl_file : 1
<66> DW_AT_decl_line : 5
<67> DW_AT_decl_column : 6
<68> DW_AT_type : <0x71>
<6c> DW_AT_byte_size : 4
<6d> DW_AT_bit_size : 8
<6e> DW_AT_bit_offset : 8
<6f> DW_AT_data_member_location: 0
<2><70>: Abbrev Number: 0
<1><71>: Abbrev Number: 4 (DW_TAG_base_type)
<72> DW_AT_byte_size : 4
<73> DW_AT_encoding : 5 (signed)
<74> DW_AT_name : int
<snip>
$ readelf -wi dwarf_test.be
Contents of the .debug_info section:
<snip>
<1><2d>: Abbrev Number: 2 (DW_TAG_structure_type)
<2e> DW_AT_name : S
<30> DW_AT_byte_size : 4
<31> DW_AT_decl_file : 1
<32> DW_AT_decl_line : 1
<33> DW_AT_sibling : <0x6c>
<2><37>: Abbrev Number: 3 (DW_TAG_member)
<38> DW_AT_name : j
<3a> DW_AT_decl_file : 1
<3b> DW_AT_decl_line : 2
<3c> DW_AT_type : <0x6c>
<40> DW_AT_byte_size : 4
<41> DW_AT_bit_size : 5
<42> DW_AT_bit_offset : 0
<43> DW_AT_data_member_location: 0
<2><44>: Abbrev Number: 3 (DW_TAG_member)
<45> DW_AT_name : k
<47> DW_AT_decl_file : 1
<48> DW_AT_decl_line : 3
<49> DW_AT_type : <0x6c>
<4d> DW_AT_byte_size : 4
<4e> DW_AT_bit_size : 6
<4f> DW_AT_bit_offset : 5
<50> DW_AT_data_member_location: 0
<2><51>: Abbrev Number: 3 (DW_TAG_member)
<52> DW_AT_name : m
<54> DW_AT_decl_file : 1
<55> DW_AT_decl_line : 4
<56> DW_AT_type : <0x6c>
<5a> DW_AT_byte_size : 4
<5b> DW_AT_bit_size : 5
<5c> DW_AT_bit_offset : 11
<5d> DW_AT_data_member_location: 0
<2><5e>: Abbrev Number: 3 (DW_TAG_member)
<5f> DW_AT_name : n
<61> DW_AT_decl_file : 1
<62> DW_AT_decl_line : 5
<63> DW_AT_type : <0x6c>
<67> DW_AT_byte_size : 4
<68> DW_AT_bit_size : 8
<69> DW_AT_bit_offset : 16
<6a> DW_AT_data_member_location: 0
<snip>
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Mark Wielaard <mark@klomp.org>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-03-18 05:23:42 +01:00
|
|
|
/*
|
|
|
|
* if current bitfield "borrowed" bits from
|
|
|
|
* previous bitfield, it will have byte_offset
|
|
|
|
* of previous bitfield's backing integral
|
|
|
|
* type, but its end bit will be in a new
|
|
|
|
* bitfield "area", so we need to adjust
|
|
|
|
* bitfield end appropriately
|
|
|
|
*/
|
|
|
|
if (bit_end > cur_bitfield_end) {
|
|
|
|
cur_bitfield_end += cur_bitfield_size;
|
|
|
|
}
|
dwarves: Revamp bit/byte holes detection logic
This patch rewrites hole detection logic. Now many crazy combinations of
bitfields and normal fields are handled correctly.
This was tested on allyesconfig kernel and differences before/after were
always in favor of new algorithm.
With subsequent change in next patch, there are no more BRAIN FART
ALERTs for allyesconfig and DWARF and BTF outputs have no discrepanies.
Example:
$ cat test.c
struct s {
short : 4; /* this one is not emitted in DWARF/BTF */
short a : 4;
int x;
int : 10;
int y : 4;
short zz;
short zzz : 4;
long z;
short : 4;
};
int main() {
struct s s;
return 0;
}
$ gcc -g test.c -o test
$ ~/pahole/build/pahole -J test
$ ~/pahole/build/pahole -F dwarf test
struct s {
/* XXX 4 bits hole, try to pack */
short int a:4; /* 0: 8 2 */
/* XXX 8 bits hole, try to pack */
/* XXX 2 bytes hole, try to pack */
int x; /* 4 4 */
/* XXX 10 bits hole, try to pack */
int y:4; /* 8:18 4 */
/* Bitfield combined with next fields */
/* XXX 2 bits hole, try to pack */
short int zz; /* 10 2 */
short int zzz:4; /* 12:12 2 */
/* XXX 12 bits hole, try to pack */
/* XXX 2 bytes hole, try to pack */
long int z; /* 16 8 */
/* size: 32, cachelines: 1, members: 6 */
/* sum members (bits): 124, holes: 2, sum holes: 4 */
/* bit holes: 5, sum bit holes: 36 bits */
/* padding: 8 */
/* last cacheline: 32 bytes */
};
No discrepanies between BTF/DWARF:
$ ../btfdiff test
$
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Mark Wielaard <mark@klomp.org>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-03-18 05:23:39 +01:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
in_bitfield = false;
|
|
|
|
cur_bitfield_size = 0;
|
|
|
|
cur_bitfield_end = bit_end;
|
|
|
|
}
|
2006-12-14 16:18:07 +01:00
|
|
|
|
2019-04-03 09:01:45 +02:00
|
|
|
if (last) {
|
|
|
|
last->hole = byte_holes;
|
|
|
|
last->bit_hole = bit_holes;
|
|
|
|
} else {
|
|
|
|
class->pre_hole = byte_holes;
|
|
|
|
class->pre_bit_hole = bit_holes;
|
|
|
|
}
|
dwarves: Revamp bit/byte holes detection logic
This patch rewrites hole detection logic. Now many crazy combinations of
bitfields and normal fields are handled correctly.
This was tested on allyesconfig kernel and differences before/after were
always in favor of new algorithm.
With subsequent change in next patch, there are no more BRAIN FART
ALERTs for allyesconfig and DWARF and BTF outputs have no discrepanies.
Example:
$ cat test.c
struct s {
short : 4; /* this one is not emitted in DWARF/BTF */
short a : 4;
int x;
int : 10;
int y : 4;
short zz;
short zzz : 4;
long z;
short : 4;
};
int main() {
struct s s;
return 0;
}
$ gcc -g test.c -o test
$ ~/pahole/build/pahole -J test
$ ~/pahole/build/pahole -F dwarf test
struct s {
/* XXX 4 bits hole, try to pack */
short int a:4; /* 0: 8 2 */
/* XXX 8 bits hole, try to pack */
/* XXX 2 bytes hole, try to pack */
int x; /* 4 4 */
/* XXX 10 bits hole, try to pack */
int y:4; /* 8:18 4 */
/* Bitfield combined with next fields */
/* XXX 2 bits hole, try to pack */
short int zz; /* 10 2 */
short int zzz:4; /* 12:12 2 */
/* XXX 12 bits hole, try to pack */
/* XXX 2 bytes hole, try to pack */
long int z; /* 16 8 */
/* size: 32, cachelines: 1, members: 6 */
/* sum members (bits): 124, holes: 2, sum holes: 4 */
/* bit holes: 5, sum bit holes: 36 bits */
/* padding: 8 */
/* last cacheline: 32 bytes */
};
No discrepanies between BTF/DWARF:
$ ../btfdiff test
$
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Mark Wielaard <mark@klomp.org>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-03-18 05:23:39 +01:00
|
|
|
if (bit_holes)
|
|
|
|
class->nr_bit_holes++;
|
|
|
|
if (byte_holes)
|
|
|
|
class->nr_holes++;
|
2006-10-28 23:22:42 +02:00
|
|
|
|
2006-12-14 16:18:07 +01:00
|
|
|
last = pos;
|
2006-10-28 23:22:42 +02:00
|
|
|
}
|
|
|
|
|
dwarves: Revamp bit/byte holes detection logic
This patch rewrites hole detection logic. Now many crazy combinations of
bitfields and normal fields are handled correctly.
This was tested on allyesconfig kernel and differences before/after were
always in favor of new algorithm.
With subsequent change in next patch, there are no more BRAIN FART
ALERTs for allyesconfig and DWARF and BTF outputs have no discrepanies.
Example:
$ cat test.c
struct s {
short : 4; /* this one is not emitted in DWARF/BTF */
short a : 4;
int x;
int : 10;
int y : 4;
short zz;
short zzz : 4;
long z;
short : 4;
};
int main() {
struct s s;
return 0;
}
$ gcc -g test.c -o test
$ ~/pahole/build/pahole -J test
$ ~/pahole/build/pahole -F dwarf test
struct s {
/* XXX 4 bits hole, try to pack */
short int a:4; /* 0: 8 2 */
/* XXX 8 bits hole, try to pack */
/* XXX 2 bytes hole, try to pack */
int x; /* 4 4 */
/* XXX 10 bits hole, try to pack */
int y:4; /* 8:18 4 */
/* Bitfield combined with next fields */
/* XXX 2 bits hole, try to pack */
short int zz; /* 10 2 */
short int zzz:4; /* 12:12 2 */
/* XXX 12 bits hole, try to pack */
/* XXX 2 bytes hole, try to pack */
long int z; /* 16 8 */
/* size: 32, cachelines: 1, members: 6 */
/* sum members (bits): 124, holes: 2, sum holes: 4 */
/* bit holes: 5, sum bit holes: 36 bits */
/* padding: 8 */
/* last cacheline: 32 bytes */
};
No discrepanies between BTF/DWARF:
$ ../btfdiff test
$
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Mark Wielaard <mark@klomp.org>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-03-18 05:23:39 +01:00
|
|
|
if (in_bitfield) {
|
|
|
|
int bitfield_end = min(ctype->size * 8, cur_bitfield_end);
|
|
|
|
class->bit_padding = bitfield_end - last_seen_bit;
|
|
|
|
last_seen_bit = bitfield_end;
|
2019-04-03 09:01:47 +02:00
|
|
|
} else {
|
|
|
|
class->bit_padding = 0;
|
dwarves: Revamp bit/byte holes detection logic
This patch rewrites hole detection logic. Now many crazy combinations of
bitfields and normal fields are handled correctly.
This was tested on allyesconfig kernel and differences before/after were
always in favor of new algorithm.
With subsequent change in next patch, there are no more BRAIN FART
ALERTs for allyesconfig and DWARF and BTF outputs have no discrepanies.
Example:
$ cat test.c
struct s {
short : 4; /* this one is not emitted in DWARF/BTF */
short a : 4;
int x;
int : 10;
int y : 4;
short zz;
short zzz : 4;
long z;
short : 4;
};
int main() {
struct s s;
return 0;
}
$ gcc -g test.c -o test
$ ~/pahole/build/pahole -J test
$ ~/pahole/build/pahole -F dwarf test
struct s {
/* XXX 4 bits hole, try to pack */
short int a:4; /* 0: 8 2 */
/* XXX 8 bits hole, try to pack */
/* XXX 2 bytes hole, try to pack */
int x; /* 4 4 */
/* XXX 10 bits hole, try to pack */
int y:4; /* 8:18 4 */
/* Bitfield combined with next fields */
/* XXX 2 bits hole, try to pack */
short int zz; /* 10 2 */
short int zzz:4; /* 12:12 2 */
/* XXX 12 bits hole, try to pack */
/* XXX 2 bytes hole, try to pack */
long int z; /* 16 8 */
/* size: 32, cachelines: 1, members: 6 */
/* sum members (bits): 124, holes: 2, sum holes: 4 */
/* bit holes: 5, sum bit holes: 36 bits */
/* padding: 8 */
/* last cacheline: 32 bytes */
};
No discrepanies between BTF/DWARF:
$ ../btfdiff test
$
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Mark Wielaard <mark@klomp.org>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-03-18 05:23:39 +01:00
|
|
|
}
|
|
|
|
class->padding = ctype->size - last_seen_bit / 8;
|
2016-06-30 21:13:46 +02:00
|
|
|
|
|
|
|
class->holes_searched = true;
|
2006-10-28 23:22:42 +02:00
|
|
|
}
|
|
|
|
|
core: Improve the natural alignment calculation
We need to take more than just arrays into account when figuring out the
natural alignment of struct members, looking recursively at types till
we get to basic types and pointers.
Before this patch the 'new' struct field in the 'v' union was considered
__packed__, when in fact it is not, as the natural alignment for the
'state_id' typedef is 4, so it can start at offset 36 (or 4 considering
just its container struct), see below:
$ pahole -IC nfsd4_lock /home/acme/git/build/v5.1-rc4+/fs/nfsd/nfs4xdr.o
/* Used at: /home/acme/git/linux/fs/nfsd/nfs4xdr.c */
/* <1717a> /home/acme/git/linux/fs/nfsd/xdr4.h:156 */
struct nfsd4_lock {
u32 lk_type; /* 0 4 */
u32 lk_reclaim; /* 4 4 */
u64 lk_offset; /* 8 8 */
u64 lk_length; /* 16 8 */
u32 lk_is_new; /* 24 4 */
/* XXX 4 bytes hole, try to pack */
union {
struct {
u32 open_seqid; /* 32 4 */
stateid_t open_stateid; /* 36 16 */
u32 lock_seqid; /* 52 4 */
clientid_t clientid; /* 56 8 */
/* --- cacheline 1 boundary (64 bytes) --- */
struct xdr_netobj owner; /* 64 16 */
} __attribute__((__packed__)) new; /* 32 48 */
struct {
stateid_t lock_stateid; /* 32 16 */
u32 lock_seqid; /* 48 4 */
} __attribute__((__packed__)) old; /* 32 20 */
} v; /* 32 48 */
/* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */
union {
struct {
stateid_t stateid; /* 80 16 */
} ok; /* 80 16 */
struct nfsd4_lock_denied denied; /* 80 48 */
} u; /* 80 48 */
/* size: 128, cachelines: 2, members: 7 */
/* sum members: 124, holes: 1, sum holes: 4 */
};
$
Asking for -rEIC, i.e. relative offsets, expand types we can see that
stateid_t opaque type:
struct {
/* typedef u32 -> __u32 */ unsigned int open_seqid; /* 0 4 */
/* typedef stateid_t */ struct {
/* typedef u32 -> __u32 */ unsigned int si_generation; /* 0 4 */
/* typedef stateid_opaque_t */ struct {
/* typedef clientid_t */ struct {
/* typedef u32 -> __u32 */ unsigned int cl_boot; /* 0 4 */
/* typedef u32 -> __u32 */ unsigned int cl_id; /* 4 4 */
} so_clid; /* 0 8 */
/* typedef u32 -> __u32 */ unsigned int so_id; /* 8 4 */
} si_opaque; /* 4 12 */
} open_stateid; /* 4 16 */
With the algorithm implemented in this patch we get it correctly as not
packed:
$ pahole -IC nfsd4_lock /home/acme/git/build/v5.1-rc4+/fs/nfsd/nfs4xdr.o
/* Used at: /home/acme/git/linux/fs/nfsd/nfs4xdr.c */
/* <1717a> /home/acme/git/linux/fs/nfsd/xdr4.h:156 */
struct nfsd4_lock {
u32 lk_type; /* 0 4 */
u32 lk_reclaim; /* 4 4 */
u64 lk_offset; /* 8 8 */
u64 lk_length; /* 16 8 */
u32 lk_is_new; /* 24 4 */
/* XXX 4 bytes hole, try to pack */
union {
struct {
u32 open_seqid; /* 32 4 */
stateid_t open_stateid; /* 36 16 */
u32 lock_seqid; /* 52 4 */
clientid_t clientid; /* 56 8 */
/* --- cacheline 1 boundary (64 bytes) --- */
struct xdr_netobj owner; /* 64 16 */
} new; /* 32 48 */
struct {
stateid_t lock_stateid; /* 32 16 */
u32 lock_seqid; /* 48 4 */
} old; /* 32 20 */
} v; /* 32 48 */
/* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */
union {
struct {
stateid_t stateid; /* 80 16 */
} ok; /* 80 16 */
struct nfsd4_lock_denied denied; /* 80 48 */
} u; /* 80 48 */
/* size: 128, cachelines: 2, members: 7 */
/* sum members: 124, holes: 1, sum holes: 4 */
};
Fixes: f2641ce169d6 ("core: Take arrays into account when inferring if a struct is packed")
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-11 21:36:49 +02:00
|
|
|
static size_t type__natural_alignment(struct type *type, const struct cu *cu);
|
|
|
|
|
|
|
|
static size_t tag__natural_alignment(struct tag *tag, const struct cu *cu)
|
|
|
|
{
|
|
|
|
size_t natural_alignment = 1;
|
|
|
|
|
|
|
|
if (tag__is_pointer(tag)) {
|
|
|
|
natural_alignment = cu->addr_size;
|
|
|
|
} else if (tag->tag == DW_TAG_base_type) {
|
|
|
|
natural_alignment = base_type__size(tag);
|
|
|
|
} else if (tag__is_enumeration(tag)) {
|
|
|
|
natural_alignment = tag__type(tag)->size / 8;
|
|
|
|
} else if (tag__is_struct(tag) || tag__is_union(tag)) {
|
|
|
|
natural_alignment = type__natural_alignment(tag__type(tag), cu);
|
|
|
|
} else if (tag->tag == DW_TAG_array_type) {
|
|
|
|
tag = tag__strip_typedefs_and_modifiers(tag, cu);
|
|
|
|
natural_alignment = tag__natural_alignment(tag, cu);
|
|
|
|
}
|
|
|
|
|
2019-04-15 19:08:13 +02:00
|
|
|
/*
|
|
|
|
* Cope with zero sized types, like:
|
|
|
|
*
|
|
|
|
* struct u64_stats_sync {
|
|
|
|
* #if BITS_PER_LONG==32 && defined(CONFIG_SMP)
|
|
|
|
* seqcount_t seq;
|
|
|
|
* #endif
|
|
|
|
* };
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
return natural_alignment ?: 1;
|
core: Improve the natural alignment calculation
We need to take more than just arrays into account when figuring out the
natural alignment of struct members, looking recursively at types till
we get to basic types and pointers.
Before this patch the 'new' struct field in the 'v' union was considered
__packed__, when in fact it is not, as the natural alignment for the
'state_id' typedef is 4, so it can start at offset 36 (or 4 considering
just its container struct), see below:
$ pahole -IC nfsd4_lock /home/acme/git/build/v5.1-rc4+/fs/nfsd/nfs4xdr.o
/* Used at: /home/acme/git/linux/fs/nfsd/nfs4xdr.c */
/* <1717a> /home/acme/git/linux/fs/nfsd/xdr4.h:156 */
struct nfsd4_lock {
u32 lk_type; /* 0 4 */
u32 lk_reclaim; /* 4 4 */
u64 lk_offset; /* 8 8 */
u64 lk_length; /* 16 8 */
u32 lk_is_new; /* 24 4 */
/* XXX 4 bytes hole, try to pack */
union {
struct {
u32 open_seqid; /* 32 4 */
stateid_t open_stateid; /* 36 16 */
u32 lock_seqid; /* 52 4 */
clientid_t clientid; /* 56 8 */
/* --- cacheline 1 boundary (64 bytes) --- */
struct xdr_netobj owner; /* 64 16 */
} __attribute__((__packed__)) new; /* 32 48 */
struct {
stateid_t lock_stateid; /* 32 16 */
u32 lock_seqid; /* 48 4 */
} __attribute__((__packed__)) old; /* 32 20 */
} v; /* 32 48 */
/* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */
union {
struct {
stateid_t stateid; /* 80 16 */
} ok; /* 80 16 */
struct nfsd4_lock_denied denied; /* 80 48 */
} u; /* 80 48 */
/* size: 128, cachelines: 2, members: 7 */
/* sum members: 124, holes: 1, sum holes: 4 */
};
$
Asking for -rEIC, i.e. relative offsets, expand types we can see that
stateid_t opaque type:
struct {
/* typedef u32 -> __u32 */ unsigned int open_seqid; /* 0 4 */
/* typedef stateid_t */ struct {
/* typedef u32 -> __u32 */ unsigned int si_generation; /* 0 4 */
/* typedef stateid_opaque_t */ struct {
/* typedef clientid_t */ struct {
/* typedef u32 -> __u32 */ unsigned int cl_boot; /* 0 4 */
/* typedef u32 -> __u32 */ unsigned int cl_id; /* 4 4 */
} so_clid; /* 0 8 */
/* typedef u32 -> __u32 */ unsigned int so_id; /* 8 4 */
} si_opaque; /* 4 12 */
} open_stateid; /* 4 16 */
With the algorithm implemented in this patch we get it correctly as not
packed:
$ pahole -IC nfsd4_lock /home/acme/git/build/v5.1-rc4+/fs/nfsd/nfs4xdr.o
/* Used at: /home/acme/git/linux/fs/nfsd/nfs4xdr.c */
/* <1717a> /home/acme/git/linux/fs/nfsd/xdr4.h:156 */
struct nfsd4_lock {
u32 lk_type; /* 0 4 */
u32 lk_reclaim; /* 4 4 */
u64 lk_offset; /* 8 8 */
u64 lk_length; /* 16 8 */
u32 lk_is_new; /* 24 4 */
/* XXX 4 bytes hole, try to pack */
union {
struct {
u32 open_seqid; /* 32 4 */
stateid_t open_stateid; /* 36 16 */
u32 lock_seqid; /* 52 4 */
clientid_t clientid; /* 56 8 */
/* --- cacheline 1 boundary (64 bytes) --- */
struct xdr_netobj owner; /* 64 16 */
} new; /* 32 48 */
struct {
stateid_t lock_stateid; /* 32 16 */
u32 lock_seqid; /* 48 4 */
} old; /* 32 20 */
} v; /* 32 48 */
/* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */
union {
struct {
stateid_t stateid; /* 80 16 */
} ok; /* 80 16 */
struct nfsd4_lock_denied denied; /* 80 48 */
} u; /* 80 48 */
/* size: 128, cachelines: 2, members: 7 */
/* sum members: 124, holes: 1, sum holes: 4 */
};
Fixes: f2641ce169d6 ("core: Take arrays into account when inferring if a struct is packed")
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-11 21:36:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static size_t type__natural_alignment(struct type *type, const struct cu *cu)
|
core: Take arrays into account when inferring if a struct is packed
Before:
$ pahole -C qrwlock /home/acme/git/build/v5.1-rc4+/fs/ceph/dir.o
struct qrwlock {
union {
atomic_t cnts; /* 0 4 */
struct {
u8 wlocked; /* 0 1 */
u8 __lstate[3]; /* 1 3 */
} __attribute__((__packed__)); /* 0 4 */
}; /* 0 4 */
arch_spinlock_t wait_lock; /* 4 4 */
/* size: 8, cachelines: 1, members: 2 */
/* last cacheline: 8 bytes */
};
I.e. __lstate's class_member->byte_size is 3, causing the misinference that that
struct was packed, it is naturally aligned, we need to look at the size of the
array's entries to figure out its natural alignment:
After:
$ pahole -C qrwlock /home/acme/git/build/v5.1-rc4+/fs/ceph/dir.o
struct qrwlock {
union {
atomic_t cnts; /* 0 4 */
struct {
u8 wlocked; /* 0 1 */
u8 __lstate[3]; /* 1 3 */
}; /* 0 4 */
}; /* 0 4 */
arch_spinlock_t wait_lock; /* 4 4 */
/* size: 8, cachelines: 1, members: 2 */
/* last cacheline: 8 bytes */
};
$
To further test:
$ cat packed_array_struct.c
struct sarray {
short array[3];
long long first;
} __attribute__((__packed__));
void foo(struct sarray *s) {}
$ gcc -g -c packed_array_struct.c
$ pahole packed_array_struct.o
struct sarray {
short int array[3]; /* 0 6 */
long long int first; /* 6 8 */
/* size: 14, cachelines: 1, members: 2 */
/* last cacheline: 14 bytes */
} __attribute__((__packed__));
$ cat packed_array_struct.c
struct sarray {
short array[3];
long long first;
};
void foo(struct sarray *s) {}
$ gcc -g -c packed_array_struct.c
$ pahole packed_array_struct.o
struct sarray {
short int array[3]; /* 0 6 */
/* XXX 2 bytes hole, try to pack */
long long int first; /* 8 8 */
/* size: 16, cachelines: 1, members: 2 */
/* sum members: 14, holes: 1, sum holes: 2 */
/* last cacheline: 16 bytes */
};
$
One more test:
$ cat packed_array_struct.c
struct sarray {
short a;
short array[3];
long long b;
};
void foo(struct sarray *s) {}
$
Before this patch:
$ gcc -g -c packed_array_struct.c
$ pahole packed_array_struct.o
struct sarray {
short int a; /* 0 2 */
short int array[3]; /* 2 6 */
long long int b; /* 8 8 */
/* size: 16, cachelines: 1, members: 3 */
/* last cacheline: 16 bytes */
} __attribute__((__packed__));
After:
$ pahole packed_array_struct.o
struct sarray {
short int a; /* 0 2 */
short int array[3]; /* 2 6 */
long long int b; /* 8 8 */
/* size: 16, cachelines: 1, members: 3 */
/* last cacheline: 16 bytes */
};
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-11 18:14:52 +02:00
|
|
|
{
|
core: Improve the natural alignment calculation
We need to take more than just arrays into account when figuring out the
natural alignment of struct members, looking recursively at types till
we get to basic types and pointers.
Before this patch the 'new' struct field in the 'v' union was considered
__packed__, when in fact it is not, as the natural alignment for the
'state_id' typedef is 4, so it can start at offset 36 (or 4 considering
just its container struct), see below:
$ pahole -IC nfsd4_lock /home/acme/git/build/v5.1-rc4+/fs/nfsd/nfs4xdr.o
/* Used at: /home/acme/git/linux/fs/nfsd/nfs4xdr.c */
/* <1717a> /home/acme/git/linux/fs/nfsd/xdr4.h:156 */
struct nfsd4_lock {
u32 lk_type; /* 0 4 */
u32 lk_reclaim; /* 4 4 */
u64 lk_offset; /* 8 8 */
u64 lk_length; /* 16 8 */
u32 lk_is_new; /* 24 4 */
/* XXX 4 bytes hole, try to pack */
union {
struct {
u32 open_seqid; /* 32 4 */
stateid_t open_stateid; /* 36 16 */
u32 lock_seqid; /* 52 4 */
clientid_t clientid; /* 56 8 */
/* --- cacheline 1 boundary (64 bytes) --- */
struct xdr_netobj owner; /* 64 16 */
} __attribute__((__packed__)) new; /* 32 48 */
struct {
stateid_t lock_stateid; /* 32 16 */
u32 lock_seqid; /* 48 4 */
} __attribute__((__packed__)) old; /* 32 20 */
} v; /* 32 48 */
/* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */
union {
struct {
stateid_t stateid; /* 80 16 */
} ok; /* 80 16 */
struct nfsd4_lock_denied denied; /* 80 48 */
} u; /* 80 48 */
/* size: 128, cachelines: 2, members: 7 */
/* sum members: 124, holes: 1, sum holes: 4 */
};
$
Asking for -rEIC, i.e. relative offsets, expand types we can see that
stateid_t opaque type:
struct {
/* typedef u32 -> __u32 */ unsigned int open_seqid; /* 0 4 */
/* typedef stateid_t */ struct {
/* typedef u32 -> __u32 */ unsigned int si_generation; /* 0 4 */
/* typedef stateid_opaque_t */ struct {
/* typedef clientid_t */ struct {
/* typedef u32 -> __u32 */ unsigned int cl_boot; /* 0 4 */
/* typedef u32 -> __u32 */ unsigned int cl_id; /* 4 4 */
} so_clid; /* 0 8 */
/* typedef u32 -> __u32 */ unsigned int so_id; /* 8 4 */
} si_opaque; /* 4 12 */
} open_stateid; /* 4 16 */
With the algorithm implemented in this patch we get it correctly as not
packed:
$ pahole -IC nfsd4_lock /home/acme/git/build/v5.1-rc4+/fs/nfsd/nfs4xdr.o
/* Used at: /home/acme/git/linux/fs/nfsd/nfs4xdr.c */
/* <1717a> /home/acme/git/linux/fs/nfsd/xdr4.h:156 */
struct nfsd4_lock {
u32 lk_type; /* 0 4 */
u32 lk_reclaim; /* 4 4 */
u64 lk_offset; /* 8 8 */
u64 lk_length; /* 16 8 */
u32 lk_is_new; /* 24 4 */
/* XXX 4 bytes hole, try to pack */
union {
struct {
u32 open_seqid; /* 32 4 */
stateid_t open_stateid; /* 36 16 */
u32 lock_seqid; /* 52 4 */
clientid_t clientid; /* 56 8 */
/* --- cacheline 1 boundary (64 bytes) --- */
struct xdr_netobj owner; /* 64 16 */
} new; /* 32 48 */
struct {
stateid_t lock_stateid; /* 32 16 */
u32 lock_seqid; /* 48 4 */
} old; /* 32 20 */
} v; /* 32 48 */
/* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */
union {
struct {
stateid_t stateid; /* 80 16 */
} ok; /* 80 16 */
struct nfsd4_lock_denied denied; /* 80 48 */
} u; /* 80 48 */
/* size: 128, cachelines: 2, members: 7 */
/* sum members: 124, holes: 1, sum holes: 4 */
};
Fixes: f2641ce169d6 ("core: Take arrays into account when inferring if a struct is packed")
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-11 21:36:49 +02:00
|
|
|
struct class_member *member;
|
|
|
|
|
|
|
|
if (type->natural_alignment != 0)
|
|
|
|
return type->natural_alignment;
|
|
|
|
|
|
|
|
type__for_each_member(type, member) {
|
|
|
|
/* XXX for now just skip these */
|
|
|
|
if (member->tag.tag == DW_TAG_inheritance &&
|
|
|
|
member->virtuality == DW_VIRTUALITY_virtual)
|
|
|
|
continue;
|
2019-11-12 15:00:31 +01:00
|
|
|
if (member->is_static) continue;
|
core: Take arrays into account when inferring if a struct is packed
Before:
$ pahole -C qrwlock /home/acme/git/build/v5.1-rc4+/fs/ceph/dir.o
struct qrwlock {
union {
atomic_t cnts; /* 0 4 */
struct {
u8 wlocked; /* 0 1 */
u8 __lstate[3]; /* 1 3 */
} __attribute__((__packed__)); /* 0 4 */
}; /* 0 4 */
arch_spinlock_t wait_lock; /* 4 4 */
/* size: 8, cachelines: 1, members: 2 */
/* last cacheline: 8 bytes */
};
I.e. __lstate's class_member->byte_size is 3, causing the misinference that that
struct was packed, it is naturally aligned, we need to look at the size of the
array's entries to figure out its natural alignment:
After:
$ pahole -C qrwlock /home/acme/git/build/v5.1-rc4+/fs/ceph/dir.o
struct qrwlock {
union {
atomic_t cnts; /* 0 4 */
struct {
u8 wlocked; /* 0 1 */
u8 __lstate[3]; /* 1 3 */
}; /* 0 4 */
}; /* 0 4 */
arch_spinlock_t wait_lock; /* 4 4 */
/* size: 8, cachelines: 1, members: 2 */
/* last cacheline: 8 bytes */
};
$
To further test:
$ cat packed_array_struct.c
struct sarray {
short array[3];
long long first;
} __attribute__((__packed__));
void foo(struct sarray *s) {}
$ gcc -g -c packed_array_struct.c
$ pahole packed_array_struct.o
struct sarray {
short int array[3]; /* 0 6 */
long long int first; /* 6 8 */
/* size: 14, cachelines: 1, members: 2 */
/* last cacheline: 14 bytes */
} __attribute__((__packed__));
$ cat packed_array_struct.c
struct sarray {
short array[3];
long long first;
};
void foo(struct sarray *s) {}
$ gcc -g -c packed_array_struct.c
$ pahole packed_array_struct.o
struct sarray {
short int array[3]; /* 0 6 */
/* XXX 2 bytes hole, try to pack */
long long int first; /* 8 8 */
/* size: 16, cachelines: 1, members: 2 */
/* sum members: 14, holes: 1, sum holes: 2 */
/* last cacheline: 16 bytes */
};
$
One more test:
$ cat packed_array_struct.c
struct sarray {
short a;
short array[3];
long long b;
};
void foo(struct sarray *s) {}
$
Before this patch:
$ gcc -g -c packed_array_struct.c
$ pahole packed_array_struct.o
struct sarray {
short int a; /* 0 2 */
short int array[3]; /* 2 6 */
long long int b; /* 8 8 */
/* size: 16, cachelines: 1, members: 3 */
/* last cacheline: 16 bytes */
} __attribute__((__packed__));
After:
$ pahole packed_array_struct.o
struct sarray {
short int a; /* 0 2 */
short int array[3]; /* 2 6 */
long long int b; /* 8 8 */
/* size: 16, cachelines: 1, members: 3 */
/* last cacheline: 16 bytes */
};
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-11 18:14:52 +02:00
|
|
|
|
core: Improve the natural alignment calculation
We need to take more than just arrays into account when figuring out the
natural alignment of struct members, looking recursively at types till
we get to basic types and pointers.
Before this patch the 'new' struct field in the 'v' union was considered
__packed__, when in fact it is not, as the natural alignment for the
'state_id' typedef is 4, so it can start at offset 36 (or 4 considering
just its container struct), see below:
$ pahole -IC nfsd4_lock /home/acme/git/build/v5.1-rc4+/fs/nfsd/nfs4xdr.o
/* Used at: /home/acme/git/linux/fs/nfsd/nfs4xdr.c */
/* <1717a> /home/acme/git/linux/fs/nfsd/xdr4.h:156 */
struct nfsd4_lock {
u32 lk_type; /* 0 4 */
u32 lk_reclaim; /* 4 4 */
u64 lk_offset; /* 8 8 */
u64 lk_length; /* 16 8 */
u32 lk_is_new; /* 24 4 */
/* XXX 4 bytes hole, try to pack */
union {
struct {
u32 open_seqid; /* 32 4 */
stateid_t open_stateid; /* 36 16 */
u32 lock_seqid; /* 52 4 */
clientid_t clientid; /* 56 8 */
/* --- cacheline 1 boundary (64 bytes) --- */
struct xdr_netobj owner; /* 64 16 */
} __attribute__((__packed__)) new; /* 32 48 */
struct {
stateid_t lock_stateid; /* 32 16 */
u32 lock_seqid; /* 48 4 */
} __attribute__((__packed__)) old; /* 32 20 */
} v; /* 32 48 */
/* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */
union {
struct {
stateid_t stateid; /* 80 16 */
} ok; /* 80 16 */
struct nfsd4_lock_denied denied; /* 80 48 */
} u; /* 80 48 */
/* size: 128, cachelines: 2, members: 7 */
/* sum members: 124, holes: 1, sum holes: 4 */
};
$
Asking for -rEIC, i.e. relative offsets, expand types we can see that
stateid_t opaque type:
struct {
/* typedef u32 -> __u32 */ unsigned int open_seqid; /* 0 4 */
/* typedef stateid_t */ struct {
/* typedef u32 -> __u32 */ unsigned int si_generation; /* 0 4 */
/* typedef stateid_opaque_t */ struct {
/* typedef clientid_t */ struct {
/* typedef u32 -> __u32 */ unsigned int cl_boot; /* 0 4 */
/* typedef u32 -> __u32 */ unsigned int cl_id; /* 4 4 */
} so_clid; /* 0 8 */
/* typedef u32 -> __u32 */ unsigned int so_id; /* 8 4 */
} si_opaque; /* 4 12 */
} open_stateid; /* 4 16 */
With the algorithm implemented in this patch we get it correctly as not
packed:
$ pahole -IC nfsd4_lock /home/acme/git/build/v5.1-rc4+/fs/nfsd/nfs4xdr.o
/* Used at: /home/acme/git/linux/fs/nfsd/nfs4xdr.c */
/* <1717a> /home/acme/git/linux/fs/nfsd/xdr4.h:156 */
struct nfsd4_lock {
u32 lk_type; /* 0 4 */
u32 lk_reclaim; /* 4 4 */
u64 lk_offset; /* 8 8 */
u64 lk_length; /* 16 8 */
u32 lk_is_new; /* 24 4 */
/* XXX 4 bytes hole, try to pack */
union {
struct {
u32 open_seqid; /* 32 4 */
stateid_t open_stateid; /* 36 16 */
u32 lock_seqid; /* 52 4 */
clientid_t clientid; /* 56 8 */
/* --- cacheline 1 boundary (64 bytes) --- */
struct xdr_netobj owner; /* 64 16 */
} new; /* 32 48 */
struct {
stateid_t lock_stateid; /* 32 16 */
u32 lock_seqid; /* 48 4 */
} old; /* 32 20 */
} v; /* 32 48 */
/* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */
union {
struct {
stateid_t stateid; /* 80 16 */
} ok; /* 80 16 */
struct nfsd4_lock_denied denied; /* 80 48 */
} u; /* 80 48 */
/* size: 128, cachelines: 2, members: 7 */
/* sum members: 124, holes: 1, sum holes: 4 */
};
Fixes: f2641ce169d6 ("core: Take arrays into account when inferring if a struct is packed")
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-11 21:36:49 +02:00
|
|
|
struct tag *member_type = tag__strip_typedefs_and_modifiers(&member->tag, cu);
|
|
|
|
size_t member_natural_alignment = tag__natural_alignment(member_type, cu);
|
core: Take arrays into account when inferring if a struct is packed
Before:
$ pahole -C qrwlock /home/acme/git/build/v5.1-rc4+/fs/ceph/dir.o
struct qrwlock {
union {
atomic_t cnts; /* 0 4 */
struct {
u8 wlocked; /* 0 1 */
u8 __lstate[3]; /* 1 3 */
} __attribute__((__packed__)); /* 0 4 */
}; /* 0 4 */
arch_spinlock_t wait_lock; /* 4 4 */
/* size: 8, cachelines: 1, members: 2 */
/* last cacheline: 8 bytes */
};
I.e. __lstate's class_member->byte_size is 3, causing the misinference that that
struct was packed, it is naturally aligned, we need to look at the size of the
array's entries to figure out its natural alignment:
After:
$ pahole -C qrwlock /home/acme/git/build/v5.1-rc4+/fs/ceph/dir.o
struct qrwlock {
union {
atomic_t cnts; /* 0 4 */
struct {
u8 wlocked; /* 0 1 */
u8 __lstate[3]; /* 1 3 */
}; /* 0 4 */
}; /* 0 4 */
arch_spinlock_t wait_lock; /* 4 4 */
/* size: 8, cachelines: 1, members: 2 */
/* last cacheline: 8 bytes */
};
$
To further test:
$ cat packed_array_struct.c
struct sarray {
short array[3];
long long first;
} __attribute__((__packed__));
void foo(struct sarray *s) {}
$ gcc -g -c packed_array_struct.c
$ pahole packed_array_struct.o
struct sarray {
short int array[3]; /* 0 6 */
long long int first; /* 6 8 */
/* size: 14, cachelines: 1, members: 2 */
/* last cacheline: 14 bytes */
} __attribute__((__packed__));
$ cat packed_array_struct.c
struct sarray {
short array[3];
long long first;
};
void foo(struct sarray *s) {}
$ gcc -g -c packed_array_struct.c
$ pahole packed_array_struct.o
struct sarray {
short int array[3]; /* 0 6 */
/* XXX 2 bytes hole, try to pack */
long long int first; /* 8 8 */
/* size: 16, cachelines: 1, members: 2 */
/* sum members: 14, holes: 1, sum holes: 2 */
/* last cacheline: 16 bytes */
};
$
One more test:
$ cat packed_array_struct.c
struct sarray {
short a;
short array[3];
long long b;
};
void foo(struct sarray *s) {}
$
Before this patch:
$ gcc -g -c packed_array_struct.c
$ pahole packed_array_struct.o
struct sarray {
short int a; /* 0 2 */
short int array[3]; /* 2 6 */
long long int b; /* 8 8 */
/* size: 16, cachelines: 1, members: 3 */
/* last cacheline: 16 bytes */
} __attribute__((__packed__));
After:
$ pahole packed_array_struct.o
struct sarray {
short int a; /* 0 2 */
short int array[3]; /* 2 6 */
long long int b; /* 8 8 */
/* size: 16, cachelines: 1, members: 3 */
/* last cacheline: 16 bytes */
};
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-11 18:14:52 +02:00
|
|
|
|
core: Improve the natural alignment calculation
We need to take more than just arrays into account when figuring out the
natural alignment of struct members, looking recursively at types till
we get to basic types and pointers.
Before this patch the 'new' struct field in the 'v' union was considered
__packed__, when in fact it is not, as the natural alignment for the
'state_id' typedef is 4, so it can start at offset 36 (or 4 considering
just its container struct), see below:
$ pahole -IC nfsd4_lock /home/acme/git/build/v5.1-rc4+/fs/nfsd/nfs4xdr.o
/* Used at: /home/acme/git/linux/fs/nfsd/nfs4xdr.c */
/* <1717a> /home/acme/git/linux/fs/nfsd/xdr4.h:156 */
struct nfsd4_lock {
u32 lk_type; /* 0 4 */
u32 lk_reclaim; /* 4 4 */
u64 lk_offset; /* 8 8 */
u64 lk_length; /* 16 8 */
u32 lk_is_new; /* 24 4 */
/* XXX 4 bytes hole, try to pack */
union {
struct {
u32 open_seqid; /* 32 4 */
stateid_t open_stateid; /* 36 16 */
u32 lock_seqid; /* 52 4 */
clientid_t clientid; /* 56 8 */
/* --- cacheline 1 boundary (64 bytes) --- */
struct xdr_netobj owner; /* 64 16 */
} __attribute__((__packed__)) new; /* 32 48 */
struct {
stateid_t lock_stateid; /* 32 16 */
u32 lock_seqid; /* 48 4 */
} __attribute__((__packed__)) old; /* 32 20 */
} v; /* 32 48 */
/* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */
union {
struct {
stateid_t stateid; /* 80 16 */
} ok; /* 80 16 */
struct nfsd4_lock_denied denied; /* 80 48 */
} u; /* 80 48 */
/* size: 128, cachelines: 2, members: 7 */
/* sum members: 124, holes: 1, sum holes: 4 */
};
$
Asking for -rEIC, i.e. relative offsets, expand types we can see that
stateid_t opaque type:
struct {
/* typedef u32 -> __u32 */ unsigned int open_seqid; /* 0 4 */
/* typedef stateid_t */ struct {
/* typedef u32 -> __u32 */ unsigned int si_generation; /* 0 4 */
/* typedef stateid_opaque_t */ struct {
/* typedef clientid_t */ struct {
/* typedef u32 -> __u32 */ unsigned int cl_boot; /* 0 4 */
/* typedef u32 -> __u32 */ unsigned int cl_id; /* 4 4 */
} so_clid; /* 0 8 */
/* typedef u32 -> __u32 */ unsigned int so_id; /* 8 4 */
} si_opaque; /* 4 12 */
} open_stateid; /* 4 16 */
With the algorithm implemented in this patch we get it correctly as not
packed:
$ pahole -IC nfsd4_lock /home/acme/git/build/v5.1-rc4+/fs/nfsd/nfs4xdr.o
/* Used at: /home/acme/git/linux/fs/nfsd/nfs4xdr.c */
/* <1717a> /home/acme/git/linux/fs/nfsd/xdr4.h:156 */
struct nfsd4_lock {
u32 lk_type; /* 0 4 */
u32 lk_reclaim; /* 4 4 */
u64 lk_offset; /* 8 8 */
u64 lk_length; /* 16 8 */
u32 lk_is_new; /* 24 4 */
/* XXX 4 bytes hole, try to pack */
union {
struct {
u32 open_seqid; /* 32 4 */
stateid_t open_stateid; /* 36 16 */
u32 lock_seqid; /* 52 4 */
clientid_t clientid; /* 56 8 */
/* --- cacheline 1 boundary (64 bytes) --- */
struct xdr_netobj owner; /* 64 16 */
} new; /* 32 48 */
struct {
stateid_t lock_stateid; /* 32 16 */
u32 lock_seqid; /* 48 4 */
} old; /* 32 20 */
} v; /* 32 48 */
/* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */
union {
struct {
stateid_t stateid; /* 80 16 */
} ok; /* 80 16 */
struct nfsd4_lock_denied denied; /* 80 48 */
} u; /* 80 48 */
/* size: 128, cachelines: 2, members: 7 */
/* sum members: 124, holes: 1, sum holes: 4 */
};
Fixes: f2641ce169d6 ("core: Take arrays into account when inferring if a struct is packed")
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-11 21:36:49 +02:00
|
|
|
if (type->natural_alignment < member_natural_alignment)
|
|
|
|
type->natural_alignment = member_natural_alignment;
|
core: Take arrays into account when inferring if a struct is packed
Before:
$ pahole -C qrwlock /home/acme/git/build/v5.1-rc4+/fs/ceph/dir.o
struct qrwlock {
union {
atomic_t cnts; /* 0 4 */
struct {
u8 wlocked; /* 0 1 */
u8 __lstate[3]; /* 1 3 */
} __attribute__((__packed__)); /* 0 4 */
}; /* 0 4 */
arch_spinlock_t wait_lock; /* 4 4 */
/* size: 8, cachelines: 1, members: 2 */
/* last cacheline: 8 bytes */
};
I.e. __lstate's class_member->byte_size is 3, causing the misinference that that
struct was packed, it is naturally aligned, we need to look at the size of the
array's entries to figure out its natural alignment:
After:
$ pahole -C qrwlock /home/acme/git/build/v5.1-rc4+/fs/ceph/dir.o
struct qrwlock {
union {
atomic_t cnts; /* 0 4 */
struct {
u8 wlocked; /* 0 1 */
u8 __lstate[3]; /* 1 3 */
}; /* 0 4 */
}; /* 0 4 */
arch_spinlock_t wait_lock; /* 4 4 */
/* size: 8, cachelines: 1, members: 2 */
/* last cacheline: 8 bytes */
};
$
To further test:
$ cat packed_array_struct.c
struct sarray {
short array[3];
long long first;
} __attribute__((__packed__));
void foo(struct sarray *s) {}
$ gcc -g -c packed_array_struct.c
$ pahole packed_array_struct.o
struct sarray {
short int array[3]; /* 0 6 */
long long int first; /* 6 8 */
/* size: 14, cachelines: 1, members: 2 */
/* last cacheline: 14 bytes */
} __attribute__((__packed__));
$ cat packed_array_struct.c
struct sarray {
short array[3];
long long first;
};
void foo(struct sarray *s) {}
$ gcc -g -c packed_array_struct.c
$ pahole packed_array_struct.o
struct sarray {
short int array[3]; /* 0 6 */
/* XXX 2 bytes hole, try to pack */
long long int first; /* 8 8 */
/* size: 16, cachelines: 1, members: 2 */
/* sum members: 14, holes: 1, sum holes: 2 */
/* last cacheline: 16 bytes */
};
$
One more test:
$ cat packed_array_struct.c
struct sarray {
short a;
short array[3];
long long b;
};
void foo(struct sarray *s) {}
$
Before this patch:
$ gcc -g -c packed_array_struct.c
$ pahole packed_array_struct.o
struct sarray {
short int a; /* 0 2 */
short int array[3]; /* 2 6 */
long long int b; /* 8 8 */
/* size: 16, cachelines: 1, members: 3 */
/* last cacheline: 16 bytes */
} __attribute__((__packed__));
After:
$ pahole packed_array_struct.o
struct sarray {
short int a; /* 0 2 */
short int array[3]; /* 2 6 */
long long int b; /* 8 8 */
/* size: 16, cachelines: 1, members: 3 */
/* last cacheline: 16 bytes */
};
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-11 18:14:52 +02:00
|
|
|
}
|
|
|
|
|
core: Improve the natural alignment calculation
We need to take more than just arrays into account when figuring out the
natural alignment of struct members, looking recursively at types till
we get to basic types and pointers.
Before this patch the 'new' struct field in the 'v' union was considered
__packed__, when in fact it is not, as the natural alignment for the
'state_id' typedef is 4, so it can start at offset 36 (or 4 considering
just its container struct), see below:
$ pahole -IC nfsd4_lock /home/acme/git/build/v5.1-rc4+/fs/nfsd/nfs4xdr.o
/* Used at: /home/acme/git/linux/fs/nfsd/nfs4xdr.c */
/* <1717a> /home/acme/git/linux/fs/nfsd/xdr4.h:156 */
struct nfsd4_lock {
u32 lk_type; /* 0 4 */
u32 lk_reclaim; /* 4 4 */
u64 lk_offset; /* 8 8 */
u64 lk_length; /* 16 8 */
u32 lk_is_new; /* 24 4 */
/* XXX 4 bytes hole, try to pack */
union {
struct {
u32 open_seqid; /* 32 4 */
stateid_t open_stateid; /* 36 16 */
u32 lock_seqid; /* 52 4 */
clientid_t clientid; /* 56 8 */
/* --- cacheline 1 boundary (64 bytes) --- */
struct xdr_netobj owner; /* 64 16 */
} __attribute__((__packed__)) new; /* 32 48 */
struct {
stateid_t lock_stateid; /* 32 16 */
u32 lock_seqid; /* 48 4 */
} __attribute__((__packed__)) old; /* 32 20 */
} v; /* 32 48 */
/* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */
union {
struct {
stateid_t stateid; /* 80 16 */
} ok; /* 80 16 */
struct nfsd4_lock_denied denied; /* 80 48 */
} u; /* 80 48 */
/* size: 128, cachelines: 2, members: 7 */
/* sum members: 124, holes: 1, sum holes: 4 */
};
$
Asking for -rEIC, i.e. relative offsets, expand types we can see that
stateid_t opaque type:
struct {
/* typedef u32 -> __u32 */ unsigned int open_seqid; /* 0 4 */
/* typedef stateid_t */ struct {
/* typedef u32 -> __u32 */ unsigned int si_generation; /* 0 4 */
/* typedef stateid_opaque_t */ struct {
/* typedef clientid_t */ struct {
/* typedef u32 -> __u32 */ unsigned int cl_boot; /* 0 4 */
/* typedef u32 -> __u32 */ unsigned int cl_id; /* 4 4 */
} so_clid; /* 0 8 */
/* typedef u32 -> __u32 */ unsigned int so_id; /* 8 4 */
} si_opaque; /* 4 12 */
} open_stateid; /* 4 16 */
With the algorithm implemented in this patch we get it correctly as not
packed:
$ pahole -IC nfsd4_lock /home/acme/git/build/v5.1-rc4+/fs/nfsd/nfs4xdr.o
/* Used at: /home/acme/git/linux/fs/nfsd/nfs4xdr.c */
/* <1717a> /home/acme/git/linux/fs/nfsd/xdr4.h:156 */
struct nfsd4_lock {
u32 lk_type; /* 0 4 */
u32 lk_reclaim; /* 4 4 */
u64 lk_offset; /* 8 8 */
u64 lk_length; /* 16 8 */
u32 lk_is_new; /* 24 4 */
/* XXX 4 bytes hole, try to pack */
union {
struct {
u32 open_seqid; /* 32 4 */
stateid_t open_stateid; /* 36 16 */
u32 lock_seqid; /* 52 4 */
clientid_t clientid; /* 56 8 */
/* --- cacheline 1 boundary (64 bytes) --- */
struct xdr_netobj owner; /* 64 16 */
} new; /* 32 48 */
struct {
stateid_t lock_stateid; /* 32 16 */
u32 lock_seqid; /* 48 4 */
} old; /* 32 20 */
} v; /* 32 48 */
/* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */
union {
struct {
stateid_t stateid; /* 80 16 */
} ok; /* 80 16 */
struct nfsd4_lock_denied denied; /* 80 48 */
} u; /* 80 48 */
/* size: 128, cachelines: 2, members: 7 */
/* sum members: 124, holes: 1, sum holes: 4 */
};
Fixes: f2641ce169d6 ("core: Take arrays into account when inferring if a struct is packed")
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-11 21:36:49 +02:00
|
|
|
return type->natural_alignment;
|
core: Take arrays into account when inferring if a struct is packed
Before:
$ pahole -C qrwlock /home/acme/git/build/v5.1-rc4+/fs/ceph/dir.o
struct qrwlock {
union {
atomic_t cnts; /* 0 4 */
struct {
u8 wlocked; /* 0 1 */
u8 __lstate[3]; /* 1 3 */
} __attribute__((__packed__)); /* 0 4 */
}; /* 0 4 */
arch_spinlock_t wait_lock; /* 4 4 */
/* size: 8, cachelines: 1, members: 2 */
/* last cacheline: 8 bytes */
};
I.e. __lstate's class_member->byte_size is 3, causing the misinference that that
struct was packed, it is naturally aligned, we need to look at the size of the
array's entries to figure out its natural alignment:
After:
$ pahole -C qrwlock /home/acme/git/build/v5.1-rc4+/fs/ceph/dir.o
struct qrwlock {
union {
atomic_t cnts; /* 0 4 */
struct {
u8 wlocked; /* 0 1 */
u8 __lstate[3]; /* 1 3 */
}; /* 0 4 */
}; /* 0 4 */
arch_spinlock_t wait_lock; /* 4 4 */
/* size: 8, cachelines: 1, members: 2 */
/* last cacheline: 8 bytes */
};
$
To further test:
$ cat packed_array_struct.c
struct sarray {
short array[3];
long long first;
} __attribute__((__packed__));
void foo(struct sarray *s) {}
$ gcc -g -c packed_array_struct.c
$ pahole packed_array_struct.o
struct sarray {
short int array[3]; /* 0 6 */
long long int first; /* 6 8 */
/* size: 14, cachelines: 1, members: 2 */
/* last cacheline: 14 bytes */
} __attribute__((__packed__));
$ cat packed_array_struct.c
struct sarray {
short array[3];
long long first;
};
void foo(struct sarray *s) {}
$ gcc -g -c packed_array_struct.c
$ pahole packed_array_struct.o
struct sarray {
short int array[3]; /* 0 6 */
/* XXX 2 bytes hole, try to pack */
long long int first; /* 8 8 */
/* size: 16, cachelines: 1, members: 2 */
/* sum members: 14, holes: 1, sum holes: 2 */
/* last cacheline: 16 bytes */
};
$
One more test:
$ cat packed_array_struct.c
struct sarray {
short a;
short array[3];
long long b;
};
void foo(struct sarray *s) {}
$
Before this patch:
$ gcc -g -c packed_array_struct.c
$ pahole packed_array_struct.o
struct sarray {
short int a; /* 0 2 */
short int array[3]; /* 2 6 */
long long int b; /* 8 8 */
/* size: 16, cachelines: 1, members: 3 */
/* last cacheline: 16 bytes */
} __attribute__((__packed__));
After:
$ pahole packed_array_struct.o
struct sarray {
short int a; /* 0 2 */
short int array[3]; /* 2 6 */
long long int b; /* 8 8 */
/* size: 16, cachelines: 1, members: 3 */
/* last cacheline: 16 bytes */
};
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-11 18:14:52 +02:00
|
|
|
}
|
|
|
|
|
core: Use unnatural alignment of struct embedded in another to infer __packed__
Since we don't have something like DW_AT_alignment for
__attribute__((__packed__)), we need to use whatever hints that are
there in the alignments to figure out if a naturally packed struct has
the __attribute__((packed)) in the original sources, because that is
needed to waiver its natural alignment requisites.
For instance,
/* Used at: btrfs.c */
/* <1e7b> /home/acme/git/pahole/btrfs.c:199 */
struct btrfs_block_group_cache {
struct btrfs_key key; /* 0 17 */
struct btrfs_block_group_item item; /* 17 24 */
/* XXX 7 bytes hole, try to pack */
struct btrfs_fs_info * fs_info; /* 48 8 */
struct inode * inode; /* 56 8 */
In the original source code, btrfs_block_group_item is marked
__packed__, and being so, even seemingly unnecessarily, makes it, when
embedded in another struct, like the above, forfeit its natural
alingment, that would be 8 bytes, and instead appear right at the 17th
byte offset...
struct btrfs_block_group_item {
__le64 used; /* 0 8 */
__le64 chunk_objectid; /* 8 8 */
__le64 flags; /* 16 8 */
/* size: 24, cachelines: 1, members: 3 */
/* last cacheline: 24 bytes */
} __attribute__((__packed__));
So we need to, seeing its use at a unnatural offset, go backwards to the
btrfs_block_group_item pahole internal data structure, 'struct type' and
mark is_packed field as 'true', despite it not looking like a packed
struct.
Same thing with:
struct ieee80211_mcs_info {
u8 rx_mask[10]; /* 0 10 */
__le16 rx_highest; /* 10 2 */
u8 tx_params; /* 12 1 */
u8 reserved[3]; /* 13 3 */
/* size: 16, cachelines: 1, members: 4 */
/* last cacheline: 16 bytes */
};
That is naturally aligned and as 16 bytes, a power of two, then when it appears at the end of:
$ pahole -IC ieee80211_sta_ht_cap vht.o
/* Used at: vht.c */
/* <31ea> /home/acme/git/pahole/vht.c:1769 */
struct ieee80211_sta_ht_cap {
u16 cap; /* 0 2 */
bool ht_supported; /* 2 1 */
u8 ampdu_factor; /* 3 1 */
u8 ampdu_density; /* 4 1 */
/* XXX 1 byte hole, try to pack */
struct ieee80211_mcs_info mcs; /* 6 16 */
/* size: 22, cachelines: 1, members: 5 */
/* sum members: 21, holes: 1, sum holes: 1 */
/* last cacheline: 22 bytes */
};
$
We get that one byte hole if ieee80211_mcs_info isn't marked __packed__, as soon as we mark it:
$ pahole -IC ieee80211_sta_ht_cap vht.o
/* Used at: vht.c */
/* <31ea> /home/acme/git/pahole/vht.c:1769 */
struct ieee80211_sta_ht_cap {
u16 cap; /* 0 2 */
bool ht_supported; /* 2 1 */
u8 ampdu_factor; /* 3 1 */
u8 ampdu_density; /* 4 1 */
struct ieee80211_mcs_info mcs; /* 5 16 */
/* size: 22, cachelines: 1, members: 5 */
/* padding: 1 */
/* last cacheline: 22 bytes */
};
[acme@quaco pahole]$
It works, so __packed__ in this case just says: trow away the natural
alignment, make it 1 in whatever container structs.
So, before emitting the types for some struct, we go back looking at
each of its members and checking for such unnatural offsets, marking the
types as __packed__. Now:
$ pfunct --compile /home/acme/git/build/v5.1-rc4+/net/mac80211/vht.o | grep "^struct ieee80211_mcs_info" -A8
struct ieee80211_mcs_info {
u8 rx_mask[10]; /* 0 10 */
__le16 rx_highest; /* 10 2 */
u8 tx_params; /* 12 1 */
u8 reserved[3]; /* 13 3 */
/* size: 16, cachelines: 1, members: 4 */
/* last cacheline: 16 bytes */
} __attribute__((__packed__));
$
$ pfunct --compile /home/acme/git/build/v5.1-rc4+/fs/btrfs/free-space-tree.o | grep "^struct btrfs_block_group_item" -A7
struct btrfs_block_group_item {
__le64 used; /* 0 8 */
__le64 chunk_objectid; /* 8 8 */
__le64 flags; /* 16 8 */
/* size: 24, cachelines: 1, members: 3 */
/* last cacheline: 24 bytes */
} __attribute__((__packed__));
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-15 20:51:16 +02:00
|
|
|
/*
|
|
|
|
* Sometimes the only indication that a struct is __packed__ is for it to
|
|
|
|
* appear embedded in another and at an offset that is not natural for it,
|
|
|
|
* so, in !__packed__ parked struct, check for that and mark the types of
|
|
|
|
* members at unnatural alignments.
|
|
|
|
*/
|
|
|
|
void type__check_structs_at_unnatural_alignments(struct type *type, const struct cu *cu)
|
|
|
|
{
|
|
|
|
struct class_member *member;
|
|
|
|
|
|
|
|
type__for_each_member(type, member) {
|
|
|
|
struct tag *member_type = tag__strip_typedefs_and_modifiers(&member->tag, cu);
|
|
|
|
|
|
|
|
if (!tag__is_struct(member_type))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
size_t natural_alignment = tag__natural_alignment(member_type, cu);
|
|
|
|
|
|
|
|
/* Would this break the natural alignment */
|
|
|
|
if ((member->byte_offset % natural_alignment) != 0) {
|
|
|
|
struct class *cls = tag__class(member_type);
|
|
|
|
|
|
|
|
cls->is_packed = true;
|
|
|
|
cls->type.packed_attributes_inferred = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
core: Infer if a struct is packed by the offsets/natural alignments
As DWARF (nor BTF) provides explicit attributes, we need to look at the
natural alignments, a byte is always alignted, etc.
This probably fails with things like __attribute__(__aligned(power-of-two)),
but with it most of the kernel data structures are full circled, i.e.
'pfunct --compile' regenerates source code from debug info that when
compiled generats debug info that end up matching the original sources.
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
const char * uptr;
int refcnt;
};
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
const char * uptr; /* 8 8 */
int refcnt; /* 16 4 */
/* size: 24, cachelines: 1, members: 3 */
/* padding: 4 */
/* last cacheline: 24 bytes */
};
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
const char * uptr;
int refcnt;
} __packed;
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
const char * uptr; /* 8 8 */
int refcnt; /* 16 4 */
/* size: 20, cachelines: 1, members: 3 */
/* last cacheline: 20 bytes */
} __attribute__((__packed__));
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
int refcnt;
const char * uptr;
};
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
int refcnt; /* 8 4 */
/* XXX 4 bytes hole, try to pack */
const char * uptr; /* 16 8 */
/* size: 24, cachelines: 1, members: 3 */
/* sum members: 20, holes: 1, sum holes: 4 */
/* last cacheline: 24 bytes */
};
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
int refcnt;
const char * uptr;
} __packed;
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
int refcnt; /* 8 4 */
const char * uptr; /* 12 8 */
/* size: 20, cachelines: 1, members: 3 */
/* last cacheline: 20 bytes */
} __attribute__((__packed__));
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
const char * uptr;
unsigned char refcnt;
};
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
const char * uptr; /* 8 8 */
unsigned char refcnt; /* 16 1 */
/* size: 24, cachelines: 1, members: 3 */
/* padding: 7 */
/* last cacheline: 24 bytes */
};
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
const char * uptr;
unsigned char refcnt;
} __packed;
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
const char * uptr; /* 8 8 */
unsigned char refcnt; /* 16 1 */
/* size: 17, cachelines: 1, members: 3 */
/* last cacheline: 17 bytes */
} __attribute__((__packed__));
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
unsigned char refcnt;
const char * uptr;
};
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
unsigned char refcnt; /* 8 1 */
/* XXX 7 bytes hole, try to pack */
const char * uptr; /* 16 8 */
/* size: 24, cachelines: 1, members: 3 */
/* sum members: 17, holes: 1, sum holes: 7 */
/* last cacheline: 24 bytes */
};
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
unsigned char refcnt;
const char * uptr;
} __packed;
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
unsigned char refcnt; /* 8 1 */
const char * uptr; /* 9 8 */
/* size: 17, cachelines: 1, members: 3 */
/* last cacheline: 17 bytes */
} __attribute__((__packed__));
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-10 22:41:59 +02:00
|
|
|
bool class__infer_packed_attributes(struct class *cls, const struct cu *cu)
|
|
|
|
{
|
2019-04-12 17:39:50 +02:00
|
|
|
struct type *ctype = &cls->type;
|
2019-07-01 21:24:31 +02:00
|
|
|
struct class_member *pos;
|
core: Infer if a struct is packed by the offsets/natural alignments
As DWARF (nor BTF) provides explicit attributes, we need to look at the
natural alignments, a byte is always alignted, etc.
This probably fails with things like __attribute__(__aligned(power-of-two)),
but with it most of the kernel data structures are full circled, i.e.
'pfunct --compile' regenerates source code from debug info that when
compiled generats debug info that end up matching the original sources.
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
const char * uptr;
int refcnt;
};
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
const char * uptr; /* 8 8 */
int refcnt; /* 16 4 */
/* size: 24, cachelines: 1, members: 3 */
/* padding: 4 */
/* last cacheline: 24 bytes */
};
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
const char * uptr;
int refcnt;
} __packed;
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
const char * uptr; /* 8 8 */
int refcnt; /* 16 4 */
/* size: 20, cachelines: 1, members: 3 */
/* last cacheline: 20 bytes */
} __attribute__((__packed__));
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
int refcnt;
const char * uptr;
};
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
int refcnt; /* 8 4 */
/* XXX 4 bytes hole, try to pack */
const char * uptr; /* 16 8 */
/* size: 24, cachelines: 1, members: 3 */
/* sum members: 20, holes: 1, sum holes: 4 */
/* last cacheline: 24 bytes */
};
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
int refcnt;
const char * uptr;
} __packed;
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
int refcnt; /* 8 4 */
const char * uptr; /* 12 8 */
/* size: 20, cachelines: 1, members: 3 */
/* last cacheline: 20 bytes */
} __attribute__((__packed__));
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
const char * uptr;
unsigned char refcnt;
};
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
const char * uptr; /* 8 8 */
unsigned char refcnt; /* 16 1 */
/* size: 24, cachelines: 1, members: 3 */
/* padding: 7 */
/* last cacheline: 24 bytes */
};
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
const char * uptr;
unsigned char refcnt;
} __packed;
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
const char * uptr; /* 8 8 */
unsigned char refcnt; /* 16 1 */
/* size: 17, cachelines: 1, members: 3 */
/* last cacheline: 17 bytes */
} __attribute__((__packed__));
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
unsigned char refcnt;
const char * uptr;
};
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
unsigned char refcnt; /* 8 1 */
/* XXX 7 bytes hole, try to pack */
const char * uptr; /* 16 8 */
/* size: 24, cachelines: 1, members: 3 */
/* sum members: 17, holes: 1, sum holes: 7 */
/* last cacheline: 24 bytes */
};
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
unsigned char refcnt;
const char * uptr;
} __packed;
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
unsigned char refcnt; /* 8 1 */
const char * uptr; /* 9 8 */
/* size: 17, cachelines: 1, members: 3 */
/* last cacheline: 17 bytes */
} __attribute__((__packed__));
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-10 22:41:59 +02:00
|
|
|
uint16_t max_natural_alignment = 1;
|
|
|
|
|
|
|
|
if (!tag__is_struct(class__tag(cls)))
|
|
|
|
return false;
|
|
|
|
|
2019-04-12 17:39:50 +02:00
|
|
|
if (ctype->packed_attributes_inferred)
|
core: Infer if a struct is packed by the offsets/natural alignments
As DWARF (nor BTF) provides explicit attributes, we need to look at the
natural alignments, a byte is always alignted, etc.
This probably fails with things like __attribute__(__aligned(power-of-two)),
but with it most of the kernel data structures are full circled, i.e.
'pfunct --compile' regenerates source code from debug info that when
compiled generats debug info that end up matching the original sources.
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
const char * uptr;
int refcnt;
};
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
const char * uptr; /* 8 8 */
int refcnt; /* 16 4 */
/* size: 24, cachelines: 1, members: 3 */
/* padding: 4 */
/* last cacheline: 24 bytes */
};
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
const char * uptr;
int refcnt;
} __packed;
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
const char * uptr; /* 8 8 */
int refcnt; /* 16 4 */
/* size: 20, cachelines: 1, members: 3 */
/* last cacheline: 20 bytes */
} __attribute__((__packed__));
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
int refcnt;
const char * uptr;
};
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
int refcnt; /* 8 4 */
/* XXX 4 bytes hole, try to pack */
const char * uptr; /* 16 8 */
/* size: 24, cachelines: 1, members: 3 */
/* sum members: 20, holes: 1, sum holes: 4 */
/* last cacheline: 24 bytes */
};
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
int refcnt;
const char * uptr;
} __packed;
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
int refcnt; /* 8 4 */
const char * uptr; /* 12 8 */
/* size: 20, cachelines: 1, members: 3 */
/* last cacheline: 20 bytes */
} __attribute__((__packed__));
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
const char * uptr;
unsigned char refcnt;
};
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
const char * uptr; /* 8 8 */
unsigned char refcnt; /* 16 1 */
/* size: 24, cachelines: 1, members: 3 */
/* padding: 7 */
/* last cacheline: 24 bytes */
};
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
const char * uptr;
unsigned char refcnt;
} __packed;
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
const char * uptr; /* 8 8 */
unsigned char refcnt; /* 16 1 */
/* size: 17, cachelines: 1, members: 3 */
/* last cacheline: 17 bytes */
} __attribute__((__packed__));
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
unsigned char refcnt;
const char * uptr;
};
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
unsigned char refcnt; /* 8 1 */
/* XXX 7 bytes hole, try to pack */
const char * uptr; /* 16 8 */
/* size: 24, cachelines: 1, members: 3 */
/* sum members: 17, holes: 1, sum holes: 7 */
/* last cacheline: 24 bytes */
};
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
unsigned char refcnt;
const char * uptr;
} __packed;
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
unsigned char refcnt; /* 8 1 */
const char * uptr; /* 9 8 */
/* size: 17, cachelines: 1, members: 3 */
/* last cacheline: 17 bytes */
} __attribute__((__packed__));
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-10 22:41:59 +02:00
|
|
|
return cls->is_packed;
|
|
|
|
|
|
|
|
class__find_holes(cls);
|
|
|
|
|
|
|
|
if (cls->padding != 0 || cls->nr_holes != 0) {
|
core: Use unnatural alignment of struct embedded in another to infer __packed__
Since we don't have something like DW_AT_alignment for
__attribute__((__packed__)), we need to use whatever hints that are
there in the alignments to figure out if a naturally packed struct has
the __attribute__((packed)) in the original sources, because that is
needed to waiver its natural alignment requisites.
For instance,
/* Used at: btrfs.c */
/* <1e7b> /home/acme/git/pahole/btrfs.c:199 */
struct btrfs_block_group_cache {
struct btrfs_key key; /* 0 17 */
struct btrfs_block_group_item item; /* 17 24 */
/* XXX 7 bytes hole, try to pack */
struct btrfs_fs_info * fs_info; /* 48 8 */
struct inode * inode; /* 56 8 */
In the original source code, btrfs_block_group_item is marked
__packed__, and being so, even seemingly unnecessarily, makes it, when
embedded in another struct, like the above, forfeit its natural
alingment, that would be 8 bytes, and instead appear right at the 17th
byte offset...
struct btrfs_block_group_item {
__le64 used; /* 0 8 */
__le64 chunk_objectid; /* 8 8 */
__le64 flags; /* 16 8 */
/* size: 24, cachelines: 1, members: 3 */
/* last cacheline: 24 bytes */
} __attribute__((__packed__));
So we need to, seeing its use at a unnatural offset, go backwards to the
btrfs_block_group_item pahole internal data structure, 'struct type' and
mark is_packed field as 'true', despite it not looking like a packed
struct.
Same thing with:
struct ieee80211_mcs_info {
u8 rx_mask[10]; /* 0 10 */
__le16 rx_highest; /* 10 2 */
u8 tx_params; /* 12 1 */
u8 reserved[3]; /* 13 3 */
/* size: 16, cachelines: 1, members: 4 */
/* last cacheline: 16 bytes */
};
That is naturally aligned and as 16 bytes, a power of two, then when it appears at the end of:
$ pahole -IC ieee80211_sta_ht_cap vht.o
/* Used at: vht.c */
/* <31ea> /home/acme/git/pahole/vht.c:1769 */
struct ieee80211_sta_ht_cap {
u16 cap; /* 0 2 */
bool ht_supported; /* 2 1 */
u8 ampdu_factor; /* 3 1 */
u8 ampdu_density; /* 4 1 */
/* XXX 1 byte hole, try to pack */
struct ieee80211_mcs_info mcs; /* 6 16 */
/* size: 22, cachelines: 1, members: 5 */
/* sum members: 21, holes: 1, sum holes: 1 */
/* last cacheline: 22 bytes */
};
$
We get that one byte hole if ieee80211_mcs_info isn't marked __packed__, as soon as we mark it:
$ pahole -IC ieee80211_sta_ht_cap vht.o
/* Used at: vht.c */
/* <31ea> /home/acme/git/pahole/vht.c:1769 */
struct ieee80211_sta_ht_cap {
u16 cap; /* 0 2 */
bool ht_supported; /* 2 1 */
u8 ampdu_factor; /* 3 1 */
u8 ampdu_density; /* 4 1 */
struct ieee80211_mcs_info mcs; /* 5 16 */
/* size: 22, cachelines: 1, members: 5 */
/* padding: 1 */
/* last cacheline: 22 bytes */
};
[acme@quaco pahole]$
It works, so __packed__ in this case just says: trow away the natural
alignment, make it 1 in whatever container structs.
So, before emitting the types for some struct, we go back looking at
each of its members and checking for such unnatural offsets, marking the
types as __packed__. Now:
$ pfunct --compile /home/acme/git/build/v5.1-rc4+/net/mac80211/vht.o | grep "^struct ieee80211_mcs_info" -A8
struct ieee80211_mcs_info {
u8 rx_mask[10]; /* 0 10 */
__le16 rx_highest; /* 10 2 */
u8 tx_params; /* 12 1 */
u8 reserved[3]; /* 13 3 */
/* size: 16, cachelines: 1, members: 4 */
/* last cacheline: 16 bytes */
} __attribute__((__packed__));
$
$ pfunct --compile /home/acme/git/build/v5.1-rc4+/fs/btrfs/free-space-tree.o | grep "^struct btrfs_block_group_item" -A7
struct btrfs_block_group_item {
__le64 used; /* 0 8 */
__le64 chunk_objectid; /* 8 8 */
__le64 flags; /* 16 8 */
/* size: 24, cachelines: 1, members: 3 */
/* last cacheline: 24 bytes */
} __attribute__((__packed__));
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-15 20:51:16 +02:00
|
|
|
type__check_structs_at_unnatural_alignments(ctype, cu);
|
core: Infer if a struct is packed by the offsets/natural alignments
As DWARF (nor BTF) provides explicit attributes, we need to look at the
natural alignments, a byte is always alignted, etc.
This probably fails with things like __attribute__(__aligned(power-of-two)),
but with it most of the kernel data structures are full circled, i.e.
'pfunct --compile' regenerates source code from debug info that when
compiled generats debug info that end up matching the original sources.
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
const char * uptr;
int refcnt;
};
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
const char * uptr; /* 8 8 */
int refcnt; /* 16 4 */
/* size: 24, cachelines: 1, members: 3 */
/* padding: 4 */
/* last cacheline: 24 bytes */
};
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
const char * uptr;
int refcnt;
} __packed;
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
const char * uptr; /* 8 8 */
int refcnt; /* 16 4 */
/* size: 20, cachelines: 1, members: 3 */
/* last cacheline: 20 bytes */
} __attribute__((__packed__));
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
int refcnt;
const char * uptr;
};
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
int refcnt; /* 8 4 */
/* XXX 4 bytes hole, try to pack */
const char * uptr; /* 16 8 */
/* size: 24, cachelines: 1, members: 3 */
/* sum members: 20, holes: 1, sum holes: 4 */
/* last cacheline: 24 bytes */
};
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
int refcnt;
const char * uptr;
} __packed;
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
int refcnt; /* 8 4 */
const char * uptr; /* 12 8 */
/* size: 20, cachelines: 1, members: 3 */
/* last cacheline: 20 bytes */
} __attribute__((__packed__));
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
const char * uptr;
unsigned char refcnt;
};
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
const char * uptr; /* 8 8 */
unsigned char refcnt; /* 16 1 */
/* size: 24, cachelines: 1, members: 3 */
/* padding: 7 */
/* last cacheline: 24 bytes */
};
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
const char * uptr;
unsigned char refcnt;
} __packed;
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
const char * uptr; /* 8 8 */
unsigned char refcnt; /* 16 1 */
/* size: 17, cachelines: 1, members: 3 */
/* last cacheline: 17 bytes */
} __attribute__((__packed__));
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
unsigned char refcnt;
const char * uptr;
};
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
unsigned char refcnt; /* 8 1 */
/* XXX 7 bytes hole, try to pack */
const char * uptr; /* 16 8 */
/* size: 24, cachelines: 1, members: 3 */
/* sum members: 17, holes: 1, sum holes: 7 */
/* last cacheline: 24 bytes */
};
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
unsigned char refcnt;
const char * uptr;
} __packed;
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
unsigned char refcnt; /* 8 1 */
const char * uptr; /* 9 8 */
/* size: 17, cachelines: 1, members: 3 */
/* last cacheline: 17 bytes */
} __attribute__((__packed__));
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-10 22:41:59 +02:00
|
|
|
cls->is_packed = false;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
type__for_each_member(ctype, pos) {
|
|
|
|
/* XXX for now just skip these */
|
|
|
|
if (pos->tag.tag == DW_TAG_inheritance &&
|
|
|
|
pos->virtuality == DW_VIRTUALITY_virtual)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (pos->is_static)
|
|
|
|
continue;
|
|
|
|
|
core: Improve the natural alignment calculation
We need to take more than just arrays into account when figuring out the
natural alignment of struct members, looking recursively at types till
we get to basic types and pointers.
Before this patch the 'new' struct field in the 'v' union was considered
__packed__, when in fact it is not, as the natural alignment for the
'state_id' typedef is 4, so it can start at offset 36 (or 4 considering
just its container struct), see below:
$ pahole -IC nfsd4_lock /home/acme/git/build/v5.1-rc4+/fs/nfsd/nfs4xdr.o
/* Used at: /home/acme/git/linux/fs/nfsd/nfs4xdr.c */
/* <1717a> /home/acme/git/linux/fs/nfsd/xdr4.h:156 */
struct nfsd4_lock {
u32 lk_type; /* 0 4 */
u32 lk_reclaim; /* 4 4 */
u64 lk_offset; /* 8 8 */
u64 lk_length; /* 16 8 */
u32 lk_is_new; /* 24 4 */
/* XXX 4 bytes hole, try to pack */
union {
struct {
u32 open_seqid; /* 32 4 */
stateid_t open_stateid; /* 36 16 */
u32 lock_seqid; /* 52 4 */
clientid_t clientid; /* 56 8 */
/* --- cacheline 1 boundary (64 bytes) --- */
struct xdr_netobj owner; /* 64 16 */
} __attribute__((__packed__)) new; /* 32 48 */
struct {
stateid_t lock_stateid; /* 32 16 */
u32 lock_seqid; /* 48 4 */
} __attribute__((__packed__)) old; /* 32 20 */
} v; /* 32 48 */
/* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */
union {
struct {
stateid_t stateid; /* 80 16 */
} ok; /* 80 16 */
struct nfsd4_lock_denied denied; /* 80 48 */
} u; /* 80 48 */
/* size: 128, cachelines: 2, members: 7 */
/* sum members: 124, holes: 1, sum holes: 4 */
};
$
Asking for -rEIC, i.e. relative offsets, expand types we can see that
stateid_t opaque type:
struct {
/* typedef u32 -> __u32 */ unsigned int open_seqid; /* 0 4 */
/* typedef stateid_t */ struct {
/* typedef u32 -> __u32 */ unsigned int si_generation; /* 0 4 */
/* typedef stateid_opaque_t */ struct {
/* typedef clientid_t */ struct {
/* typedef u32 -> __u32 */ unsigned int cl_boot; /* 0 4 */
/* typedef u32 -> __u32 */ unsigned int cl_id; /* 4 4 */
} so_clid; /* 0 8 */
/* typedef u32 -> __u32 */ unsigned int so_id; /* 8 4 */
} si_opaque; /* 4 12 */
} open_stateid; /* 4 16 */
With the algorithm implemented in this patch we get it correctly as not
packed:
$ pahole -IC nfsd4_lock /home/acme/git/build/v5.1-rc4+/fs/nfsd/nfs4xdr.o
/* Used at: /home/acme/git/linux/fs/nfsd/nfs4xdr.c */
/* <1717a> /home/acme/git/linux/fs/nfsd/xdr4.h:156 */
struct nfsd4_lock {
u32 lk_type; /* 0 4 */
u32 lk_reclaim; /* 4 4 */
u64 lk_offset; /* 8 8 */
u64 lk_length; /* 16 8 */
u32 lk_is_new; /* 24 4 */
/* XXX 4 bytes hole, try to pack */
union {
struct {
u32 open_seqid; /* 32 4 */
stateid_t open_stateid; /* 36 16 */
u32 lock_seqid; /* 52 4 */
clientid_t clientid; /* 56 8 */
/* --- cacheline 1 boundary (64 bytes) --- */
struct xdr_netobj owner; /* 64 16 */
} new; /* 32 48 */
struct {
stateid_t lock_stateid; /* 32 16 */
u32 lock_seqid; /* 48 4 */
} old; /* 32 20 */
} v; /* 32 48 */
/* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */
union {
struct {
stateid_t stateid; /* 80 16 */
} ok; /* 80 16 */
struct nfsd4_lock_denied denied; /* 80 48 */
} u; /* 80 48 */
/* size: 128, cachelines: 2, members: 7 */
/* sum members: 124, holes: 1, sum holes: 4 */
};
Fixes: f2641ce169d6 ("core: Take arrays into account when inferring if a struct is packed")
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-11 21:36:49 +02:00
|
|
|
struct tag *member_type = tag__strip_typedefs_and_modifiers(&pos->tag, cu);
|
|
|
|
size_t natural_alignment = tag__natural_alignment(member_type, cu);
|
core: Take arrays into account when inferring if a struct is packed
Before:
$ pahole -C qrwlock /home/acme/git/build/v5.1-rc4+/fs/ceph/dir.o
struct qrwlock {
union {
atomic_t cnts; /* 0 4 */
struct {
u8 wlocked; /* 0 1 */
u8 __lstate[3]; /* 1 3 */
} __attribute__((__packed__)); /* 0 4 */
}; /* 0 4 */
arch_spinlock_t wait_lock; /* 4 4 */
/* size: 8, cachelines: 1, members: 2 */
/* last cacheline: 8 bytes */
};
I.e. __lstate's class_member->byte_size is 3, causing the misinference that that
struct was packed, it is naturally aligned, we need to look at the size of the
array's entries to figure out its natural alignment:
After:
$ pahole -C qrwlock /home/acme/git/build/v5.1-rc4+/fs/ceph/dir.o
struct qrwlock {
union {
atomic_t cnts; /* 0 4 */
struct {
u8 wlocked; /* 0 1 */
u8 __lstate[3]; /* 1 3 */
}; /* 0 4 */
}; /* 0 4 */
arch_spinlock_t wait_lock; /* 4 4 */
/* size: 8, cachelines: 1, members: 2 */
/* last cacheline: 8 bytes */
};
$
To further test:
$ cat packed_array_struct.c
struct sarray {
short array[3];
long long first;
} __attribute__((__packed__));
void foo(struct sarray *s) {}
$ gcc -g -c packed_array_struct.c
$ pahole packed_array_struct.o
struct sarray {
short int array[3]; /* 0 6 */
long long int first; /* 6 8 */
/* size: 14, cachelines: 1, members: 2 */
/* last cacheline: 14 bytes */
} __attribute__((__packed__));
$ cat packed_array_struct.c
struct sarray {
short array[3];
long long first;
};
void foo(struct sarray *s) {}
$ gcc -g -c packed_array_struct.c
$ pahole packed_array_struct.o
struct sarray {
short int array[3]; /* 0 6 */
/* XXX 2 bytes hole, try to pack */
long long int first; /* 8 8 */
/* size: 16, cachelines: 1, members: 2 */
/* sum members: 14, holes: 1, sum holes: 2 */
/* last cacheline: 16 bytes */
};
$
One more test:
$ cat packed_array_struct.c
struct sarray {
short a;
short array[3];
long long b;
};
void foo(struct sarray *s) {}
$
Before this patch:
$ gcc -g -c packed_array_struct.c
$ pahole packed_array_struct.o
struct sarray {
short int a; /* 0 2 */
short int array[3]; /* 2 6 */
long long int b; /* 8 8 */
/* size: 16, cachelines: 1, members: 3 */
/* last cacheline: 16 bytes */
} __attribute__((__packed__));
After:
$ pahole packed_array_struct.o
struct sarray {
short int a; /* 0 2 */
short int array[3]; /* 2 6 */
long long int b; /* 8 8 */
/* size: 16, cachelines: 1, members: 3 */
/* last cacheline: 16 bytes */
};
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-11 18:14:52 +02:00
|
|
|
|
core: Infer if a struct is packed by the offsets/natural alignments
As DWARF (nor BTF) provides explicit attributes, we need to look at the
natural alignments, a byte is always alignted, etc.
This probably fails with things like __attribute__(__aligned(power-of-two)),
but with it most of the kernel data structures are full circled, i.e.
'pfunct --compile' regenerates source code from debug info that when
compiled generats debug info that end up matching the original sources.
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
const char * uptr;
int refcnt;
};
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
const char * uptr; /* 8 8 */
int refcnt; /* 16 4 */
/* size: 24, cachelines: 1, members: 3 */
/* padding: 4 */
/* last cacheline: 24 bytes */
};
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
const char * uptr;
int refcnt;
} __packed;
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
const char * uptr; /* 8 8 */
int refcnt; /* 16 4 */
/* size: 20, cachelines: 1, members: 3 */
/* last cacheline: 20 bytes */
} __attribute__((__packed__));
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
int refcnt;
const char * uptr;
};
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
int refcnt; /* 8 4 */
/* XXX 4 bytes hole, try to pack */
const char * uptr; /* 16 8 */
/* size: 24, cachelines: 1, members: 3 */
/* sum members: 20, holes: 1, sum holes: 4 */
/* last cacheline: 24 bytes */
};
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
int refcnt;
const char * uptr;
} __packed;
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
int refcnt; /* 8 4 */
const char * uptr; /* 12 8 */
/* size: 20, cachelines: 1, members: 3 */
/* last cacheline: 20 bytes */
} __attribute__((__packed__));
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
const char * uptr;
unsigned char refcnt;
};
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
const char * uptr; /* 8 8 */
unsigned char refcnt; /* 16 1 */
/* size: 24, cachelines: 1, members: 3 */
/* padding: 7 */
/* last cacheline: 24 bytes */
};
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
const char * uptr;
unsigned char refcnt;
} __packed;
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
const char * uptr; /* 8 8 */
unsigned char refcnt; /* 16 1 */
/* size: 17, cachelines: 1, members: 3 */
/* last cacheline: 17 bytes */
} __attribute__((__packed__));
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
unsigned char refcnt;
const char * uptr;
};
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
unsigned char refcnt; /* 8 1 */
/* XXX 7 bytes hole, try to pack */
const char * uptr; /* 16 8 */
/* size: 24, cachelines: 1, members: 3 */
/* sum members: 17, holes: 1, sum holes: 7 */
/* last cacheline: 24 bytes */
};
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
unsigned char refcnt;
const char * uptr;
} __packed;
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
unsigned char refcnt; /* 8 1 */
const char * uptr; /* 9 8 */
/* size: 17, cachelines: 1, members: 3 */
/* last cacheline: 17 bytes */
} __attribute__((__packed__));
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-10 22:41:59 +02:00
|
|
|
/* Always aligned: */
|
core: Improve the natural alignment calculation
We need to take more than just arrays into account when figuring out the
natural alignment of struct members, looking recursively at types till
we get to basic types and pointers.
Before this patch the 'new' struct field in the 'v' union was considered
__packed__, when in fact it is not, as the natural alignment for the
'state_id' typedef is 4, so it can start at offset 36 (or 4 considering
just its container struct), see below:
$ pahole -IC nfsd4_lock /home/acme/git/build/v5.1-rc4+/fs/nfsd/nfs4xdr.o
/* Used at: /home/acme/git/linux/fs/nfsd/nfs4xdr.c */
/* <1717a> /home/acme/git/linux/fs/nfsd/xdr4.h:156 */
struct nfsd4_lock {
u32 lk_type; /* 0 4 */
u32 lk_reclaim; /* 4 4 */
u64 lk_offset; /* 8 8 */
u64 lk_length; /* 16 8 */
u32 lk_is_new; /* 24 4 */
/* XXX 4 bytes hole, try to pack */
union {
struct {
u32 open_seqid; /* 32 4 */
stateid_t open_stateid; /* 36 16 */
u32 lock_seqid; /* 52 4 */
clientid_t clientid; /* 56 8 */
/* --- cacheline 1 boundary (64 bytes) --- */
struct xdr_netobj owner; /* 64 16 */
} __attribute__((__packed__)) new; /* 32 48 */
struct {
stateid_t lock_stateid; /* 32 16 */
u32 lock_seqid; /* 48 4 */
} __attribute__((__packed__)) old; /* 32 20 */
} v; /* 32 48 */
/* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */
union {
struct {
stateid_t stateid; /* 80 16 */
} ok; /* 80 16 */
struct nfsd4_lock_denied denied; /* 80 48 */
} u; /* 80 48 */
/* size: 128, cachelines: 2, members: 7 */
/* sum members: 124, holes: 1, sum holes: 4 */
};
$
Asking for -rEIC, i.e. relative offsets, expand types we can see that
stateid_t opaque type:
struct {
/* typedef u32 -> __u32 */ unsigned int open_seqid; /* 0 4 */
/* typedef stateid_t */ struct {
/* typedef u32 -> __u32 */ unsigned int si_generation; /* 0 4 */
/* typedef stateid_opaque_t */ struct {
/* typedef clientid_t */ struct {
/* typedef u32 -> __u32 */ unsigned int cl_boot; /* 0 4 */
/* typedef u32 -> __u32 */ unsigned int cl_id; /* 4 4 */
} so_clid; /* 0 8 */
/* typedef u32 -> __u32 */ unsigned int so_id; /* 8 4 */
} si_opaque; /* 4 12 */
} open_stateid; /* 4 16 */
With the algorithm implemented in this patch we get it correctly as not
packed:
$ pahole -IC nfsd4_lock /home/acme/git/build/v5.1-rc4+/fs/nfsd/nfs4xdr.o
/* Used at: /home/acme/git/linux/fs/nfsd/nfs4xdr.c */
/* <1717a> /home/acme/git/linux/fs/nfsd/xdr4.h:156 */
struct nfsd4_lock {
u32 lk_type; /* 0 4 */
u32 lk_reclaim; /* 4 4 */
u64 lk_offset; /* 8 8 */
u64 lk_length; /* 16 8 */
u32 lk_is_new; /* 24 4 */
/* XXX 4 bytes hole, try to pack */
union {
struct {
u32 open_seqid; /* 32 4 */
stateid_t open_stateid; /* 36 16 */
u32 lock_seqid; /* 52 4 */
clientid_t clientid; /* 56 8 */
/* --- cacheline 1 boundary (64 bytes) --- */
struct xdr_netobj owner; /* 64 16 */
} new; /* 32 48 */
struct {
stateid_t lock_stateid; /* 32 16 */
u32 lock_seqid; /* 48 4 */
} old; /* 32 20 */
} v; /* 32 48 */
/* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */
union {
struct {
stateid_t stateid; /* 80 16 */
} ok; /* 80 16 */
struct nfsd4_lock_denied denied; /* 80 48 */
} u; /* 80 48 */
/* size: 128, cachelines: 2, members: 7 */
/* sum members: 124, holes: 1, sum holes: 4 */
};
Fixes: f2641ce169d6 ("core: Take arrays into account when inferring if a struct is packed")
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-11 21:36:49 +02:00
|
|
|
if (natural_alignment == sizeof(char))
|
core: Infer if a struct is packed by the offsets/natural alignments
As DWARF (nor BTF) provides explicit attributes, we need to look at the
natural alignments, a byte is always alignted, etc.
This probably fails with things like __attribute__(__aligned(power-of-two)),
but with it most of the kernel data structures are full circled, i.e.
'pfunct --compile' regenerates source code from debug info that when
compiled generats debug info that end up matching the original sources.
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
const char * uptr;
int refcnt;
};
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
const char * uptr; /* 8 8 */
int refcnt; /* 16 4 */
/* size: 24, cachelines: 1, members: 3 */
/* padding: 4 */
/* last cacheline: 24 bytes */
};
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
const char * uptr;
int refcnt;
} __packed;
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
const char * uptr; /* 8 8 */
int refcnt; /* 16 4 */
/* size: 20, cachelines: 1, members: 3 */
/* last cacheline: 20 bytes */
} __attribute__((__packed__));
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
int refcnt;
const char * uptr;
};
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
int refcnt; /* 8 4 */
/* XXX 4 bytes hole, try to pack */
const char * uptr; /* 16 8 */
/* size: 24, cachelines: 1, members: 3 */
/* sum members: 20, holes: 1, sum holes: 4 */
/* last cacheline: 24 bytes */
};
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
int refcnt;
const char * uptr;
} __packed;
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
int refcnt; /* 8 4 */
const char * uptr; /* 12 8 */
/* size: 20, cachelines: 1, members: 3 */
/* last cacheline: 20 bytes */
} __attribute__((__packed__));
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
const char * uptr;
unsigned char refcnt;
};
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
const char * uptr; /* 8 8 */
unsigned char refcnt; /* 16 1 */
/* size: 24, cachelines: 1, members: 3 */
/* padding: 7 */
/* last cacheline: 24 bytes */
};
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
const char * uptr;
unsigned char refcnt;
} __packed;
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
const char * uptr; /* 8 8 */
unsigned char refcnt; /* 16 1 */
/* size: 17, cachelines: 1, members: 3 */
/* last cacheline: 17 bytes */
} __attribute__((__packed__));
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
unsigned char refcnt;
const char * uptr;
};
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
unsigned char refcnt; /* 8 1 */
/* XXX 7 bytes hole, try to pack */
const char * uptr; /* 16 8 */
/* size: 24, cachelines: 1, members: 3 */
/* sum members: 17, holes: 1, sum holes: 7 */
/* last cacheline: 24 bytes */
};
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
unsigned char refcnt;
const char * uptr;
} __packed;
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
unsigned char refcnt; /* 8 1 */
const char * uptr; /* 9 8 */
/* size: 17, cachelines: 1, members: 3 */
/* last cacheline: 17 bytes */
} __attribute__((__packed__));
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-10 22:41:59 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if (max_natural_alignment < natural_alignment)
|
|
|
|
max_natural_alignment = natural_alignment;
|
|
|
|
|
|
|
|
if ((pos->byte_offset % natural_alignment) == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
cls->is_packed = true;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
emit: Handle structs with DW_AT_alignment=1 meaning __packed__
In the following struct the ceph_entity_addr entries all appear marked with a
__attribute__((__aligned__(8)), which, for the first two members of this type,
'peer_addr' and 'peer_addr_for_me', don't cause the regenerated struct to
differ in layout from the original layout put in place by the compiler as per
the original source code.
But the third member of this type, 'actual_peer_addr' ends up in a different
offset, even in a different cacheline, here is how it looks like in the code generated
from the original source code, at offset 568.
char in_banner[30]; /* 472 30 */
struct ceph_msg_connect out_connect; /* 502 33 */
/* --- cacheline 8 boundary (512 bytes) was 23 bytes ago --- */
struct ceph_msg_connect_reply in_reply; /* 535 26 */
struct ceph_entity_addr actual_peer_addr __attribute__((__aligned__(1))); /* 561 136 */
/* --- cacheline 10 boundary (640 bytes) was 57 bytes ago --- */
struct ceph_msg_header out_hdr; /* 697 53 */
/* XXX 2 bytes hole, try to pack */
/* --- cacheline 11 boundary (704 bytes) was 48 bytes ago --- */
And here is how it looks like when built from the regenerated source code, at
offset 568:
$ pfunct --compile /home/acme/git/build/v5.1-rc4+/fs/ceph/super.o > ceph.c
$ gcc -g -c ceph.c
$ pahole -C ceph_connection ceph.o | head -46
struct ceph_connection {
void * private; /* 0 8 */
const struct ceph_connection_operations * ops; /* 8 8 */
struct ceph_messenger * msgr; /* 16 8 */
atomic_t sock_state; /* 24 4 */
/* XXX 4 bytes hole, try to pack */
struct socket * sock; /* 32 8 */
struct ceph_entity_addr peer_addr __attribute__((__aligned__(8))); /* 40 136 */
/* --- cacheline 2 boundary (128 bytes) was 48 bytes ago --- */
struct ceph_entity_addr peer_addr_for_me __attribute__((__aligned__(8))); /* 176 136 */
/* --- cacheline 4 boundary (256 bytes) was 56 bytes ago --- */
long unsigned int flags; /* 312 8 */
/* --- cacheline 5 boundary (320 bytes) --- */
long unsigned int state; /* 320 8 */
const char * error_msg; /* 328 8 */
struct ceph_entity_name peer_name; /* 336 9 */
/* XXX 7 bytes hole, try to pack */
u64 peer_features; /* 352 8 */
u32 connect_seq; /* 360 4 */
u32 peer_global_seq; /* 364 4 */
struct ceph_auth_handshake * auth; /* 368 8 */
int auth_retry; /* 376 4 */
/* XXX 4 bytes hole, try to pack */
/* --- cacheline 6 boundary (384 bytes) --- */
struct mutex mutex; /* 384 32 */
struct list_head out_queue; /* 416 16 */
struct list_head out_sent; /* 432 16 */
/* --- cacheline 7 boundary (448 bytes) --- */
u64 out_seq; /* 448 8 */
u64 in_seq; /* 456 8 */
u64 in_seq_acked; /* 464 8 */
char in_banner[30]; /* 472 30 */
struct ceph_msg_connect out_connect; /* 502 33 */
/* --- cacheline 8 boundary (512 bytes) was 23 bytes ago --- */
struct ceph_msg_connect_reply in_reply; /* 535 26 */
/* XXX 7 bytes hole, try to pack */
struct ceph_entity_addr actual_peer_addr __attribute__((__aligned__(8))); /* 568 136 */
/* --- cacheline 11 boundary (704 bytes) --- */
$
That happens because 'struct ceph_entity_addr' has that __attribute__
((__aligned__(8)) in the regenerated source code, above, now look at how it
gets regenerated:
$ pahole -C ceph_entity_addr ceph.o
struct ceph_entity_addr {
__le32 type; /* 0 4 */
__le32 nonce; /* 4 4 */
struct __kernel_sockaddr_storage in_addr __attribute__((__aligned__(8))); /* 8 128 */
/* size: 136, cachelines: 3, members: 3 */
/* forced alignments: 1 */
/* last cacheline: 8 bytes */
} __attribute__((__aligned__(8)));
$
While when looking at the original DWARF:
$ pahole -C ceph_entity_addr /home/acme/git/build/v5.1-rc4+/fs/ceph/super.o
struct ceph_entity_addr {
__le32 type; /* 0 4 */
__le32 nonce; /* 4 4 */
struct __kernel_sockaddr_storage in_addr __attribute__((__aligned__(1))); /* 8 128 */
/* size: 136, cachelines: 3, members: 3 */
/* forced alignments: 1 */
/* last cacheline: 8 bytes */
} __attribute__((__aligned__(1)));
$
The confusion may further come from the fact that 'struct __kernel_sockaddr_storage' has,
in the regenerated source code, the __attribute__((__aligned__8)))
$ pahole -C __kernel_sockaddr_storage ceph.o
struct __kernel_sockaddr_storage {
__kernel_sa_family_t ss_family; /* 0 2 */
char __data[126]; /* 2 126 */
/* size: 128, cachelines: 2, members: 2 */
} __attribute__((__aligned__(8)));
$
Which is the same as in the original DWARF:
$ pahole -C __kernel_sockaddr_storage /home/acme/git/build/v5.1-rc4+/fs/ceph/super.o
struct __kernel_sockaddr_storage {
__kernel_sa_family_t ss_family; /* 0 2 */
char __data[126]; /* 2 126 */
/* size: 128, cachelines: 2, members: 2 */
} __attribute__((__aligned__(8)));
$
Looking at the original original source code for 'struct ceph_entity_addr'
helps here, as it reads:
include/linux/ceph/msgr.h, line 63:
/*
* entity_addr -- network address
*/
struct ceph_entity_addr {
__le32 type;
__le32 nonce; /* unique id for process (e.g. pid) */
struct sockaddr_storage in_addr;
} __attribute__ ((packed));
So the original code has no __attribute__((__aligned__(1))), so, lets look at
what the compiler generates for 'struct ceph_entity_addr':
$ readelf -wi /home/acme/git/build/v5.1-rc4+/fs/ceph/super.o | grep ceph_entity_addr -A7
<193a6> DW_AT_name : (indirect string, offset: 0x1586): ceph_entity_addr
<193aa> DW_AT_byte_size : 136
<193ab> DW_AT_alignment : 1
<193ac> DW_AT_decl_file : 296
<193ae> DW_AT_decl_line : 63
<193af> DW_AT_decl_column : 8
<193b0> DW_AT_sibling : <0x193e0>
<2><193b4>: Abbrev Number: 5 (DW_TAG_member)
$
So the natural alignment for 'struct ceph_entity_addr' ends up being the
natural alignment for 'struct __kernel_sockaddr_storage', which is 8, but
since 'struct ceph_entity_addr' was marked in the original source code as __packed__,
the compiler added the DW_AT_alignment: 1 to override that.
The heuristic in pahole, so far, took that __attribute__((__aligned__(1)))
literally:
$ pahole -C ceph_entity_addr /home/acme/git/build/v5.1-rc4+/fs/ceph/super.o
struct ceph_entity_addr {
__le32 type; /* 0 4 */
__le32 nonce; /* 4 4 */
struct __kernel_sockaddr_storage in_addr __attribute__((__aligned__(1))); /* 8 128 */
/* size: 136, cachelines: 3, members: 3 */
/* forced alignments: 1 */
/* last cacheline: 8 bytes */
} __attribute__((__aligned__(1)));
$
which ends up making the regenerated source code (with the __aligned__((1))),
generate a different layout, the __aligned__((8)) in one of its members
overrode that __aligned__((1)).
Take this into account and when faced with a structure which natural alignment
is not one and that has a DW_AT_alignment:1 to mean it really is __packed__.
Doing that makes the regenerated source code match the original structure
layouts, i.e. after the patch we get:
$ pahole -C ceph_entity_addr /home/acme/git/build/v5.1-rc4+/fs/ceph/super.o
struct ceph_entity_addr {
__le32 type; /* 0 4 */
__le32 nonce; /* 4 4 */
struct __kernel_sockaddr_storage in_addr __attribute__((__aligned__(1))); /* 8 128 */
/* size: 136, cachelines: 3, members: 3 */
/* forced alignments: 1 */
/* last cacheline: 8 bytes */
} __attribute__((__packed__));
$
And that member in 'struct ceph_connection', in the original, continues to read:
$ pahole -C ceph_connection /home/acme/git/build/v5.1-rc4+/fs/ceph/super.o | grep -w actual_peer_addr -B4 -A6
char in_banner[30]; /* 472 30 */
struct ceph_msg_connect out_connect; /* 502 33 */
/* --- cacheline 8 boundary (512 bytes) was 23 bytes ago --- */
struct ceph_msg_connect_reply in_reply; /* 535 26 */
struct ceph_entity_addr actual_peer_addr __attribute__((__aligned__(1))); /* 561 136 */
/* --- cacheline 10 boundary (640 bytes) was 57 bytes ago --- */
struct ceph_msg_header out_hdr; /* 697 53 */
/* XXX 2 bytes hole, try to pack */
/* --- cacheline 11 boundary (704 bytes) was 48 bytes ago --- */
$
While in the regenerated DWARF from the regenerated source code reads:
$ pfunct --compile /home/acme/git/build/v5.1-rc4+/fs/ceph/super.o > ceph.c
$ gcc -g -c ceph.c
$ pahole -C ceph_connection ceph.o | grep -w actual_peer_addr -B4 -A6
char in_banner[30]; /* 472 30 */
struct ceph_msg_connect out_connect; /* 502 33 */
/* --- cacheline 8 boundary (512 bytes) was 23 bytes ago --- */
struct ceph_msg_connect_reply in_reply; /* 535 26 */
struct ceph_entity_addr actual_peer_addr __attribute__((__aligned__(1))); /* 561 136 */
/* --- cacheline 10 boundary (640 bytes) was 57 bytes ago --- */
struct ceph_msg_header out_hdr; /* 697 53 */
/* XXX 2 bytes hole, try to pack */
/* --- cacheline 11 boundary (704 bytes) was 48 bytes ago --- */
$
I.e. it now matches.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-15 18:25:48 +02:00
|
|
|
if ((max_natural_alignment != 1 && ctype->alignment == 1) ||
|
|
|
|
(class__size(cls) % max_natural_alignment) != 0)
|
core: Infer if a struct is packed by the offsets/natural alignments
As DWARF (nor BTF) provides explicit attributes, we need to look at the
natural alignments, a byte is always alignted, etc.
This probably fails with things like __attribute__(__aligned(power-of-two)),
but with it most of the kernel data structures are full circled, i.e.
'pfunct --compile' regenerates source code from debug info that when
compiled generats debug info that end up matching the original sources.
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
const char * uptr;
int refcnt;
};
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
const char * uptr; /* 8 8 */
int refcnt; /* 16 4 */
/* size: 24, cachelines: 1, members: 3 */
/* padding: 4 */
/* last cacheline: 24 bytes */
};
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
const char * uptr;
int refcnt;
} __packed;
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
const char * uptr; /* 8 8 */
int refcnt; /* 16 4 */
/* size: 20, cachelines: 1, members: 3 */
/* last cacheline: 20 bytes */
} __attribute__((__packed__));
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
int refcnt;
const char * uptr;
};
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
int refcnt; /* 8 4 */
/* XXX 4 bytes hole, try to pack */
const char * uptr; /* 16 8 */
/* size: 24, cachelines: 1, members: 3 */
/* sum members: 20, holes: 1, sum holes: 4 */
/* last cacheline: 24 bytes */
};
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
int refcnt;
const char * uptr;
} __packed;
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
int refcnt; /* 8 4 */
const char * uptr; /* 12 8 */
/* size: 20, cachelines: 1, members: 3 */
/* last cacheline: 20 bytes */
} __attribute__((__packed__));
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
const char * uptr;
unsigned char refcnt;
};
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
const char * uptr; /* 8 8 */
unsigned char refcnt; /* 16 1 */
/* size: 24, cachelines: 1, members: 3 */
/* padding: 7 */
/* last cacheline: 24 bytes */
};
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
const char * uptr;
unsigned char refcnt;
} __packed;
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
const char * uptr; /* 8 8 */
unsigned char refcnt; /* 16 1 */
/* size: 17, cachelines: 1, members: 3 */
/* last cacheline: 17 bytes */
} __attribute__((__packed__));
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
unsigned char refcnt;
const char * uptr;
};
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
unsigned char refcnt; /* 8 1 */
/* XXX 7 bytes hole, try to pack */
const char * uptr; /* 16 8 */
/* size: 24, cachelines: 1, members: 3 */
/* sum members: 17, holes: 1, sum holes: 7 */
/* last cacheline: 24 bytes */
};
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
unsigned char refcnt;
const char * uptr;
} __packed;
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
unsigned char refcnt; /* 8 1 */
const char * uptr; /* 9 8 */
/* size: 17, cachelines: 1, members: 3 */
/* last cacheline: 17 bytes */
} __attribute__((__packed__));
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-10 22:41:59 +02:00
|
|
|
cls->is_packed = true;
|
|
|
|
|
|
|
|
out:
|
2019-04-12 17:39:50 +02:00
|
|
|
ctype->packed_attributes_inferred = true;
|
core: Infer if a struct is packed by the offsets/natural alignments
As DWARF (nor BTF) provides explicit attributes, we need to look at the
natural alignments, a byte is always alignted, etc.
This probably fails with things like __attribute__(__aligned(power-of-two)),
but with it most of the kernel data structures are full circled, i.e.
'pfunct --compile' regenerates source code from debug info that when
compiled generats debug info that end up matching the original sources.
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
const char * uptr;
int refcnt;
};
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
const char * uptr; /* 8 8 */
int refcnt; /* 16 4 */
/* size: 24, cachelines: 1, members: 3 */
/* padding: 4 */
/* last cacheline: 24 bytes */
};
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
const char * uptr;
int refcnt;
} __packed;
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
const char * uptr; /* 8 8 */
int refcnt; /* 16 4 */
/* size: 20, cachelines: 1, members: 3 */
/* last cacheline: 20 bytes */
} __attribute__((__packed__));
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
int refcnt;
const char * uptr;
};
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
int refcnt; /* 8 4 */
/* XXX 4 bytes hole, try to pack */
const char * uptr; /* 16 8 */
/* size: 24, cachelines: 1, members: 3 */
/* sum members: 20, holes: 1, sum holes: 4 */
/* last cacheline: 24 bytes */
};
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
int refcnt;
const char * uptr;
} __packed;
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
int refcnt; /* 8 4 */
const char * uptr; /* 12 8 */
/* size: 20, cachelines: 1, members: 3 */
/* last cacheline: 20 bytes */
} __attribute__((__packed__));
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
const char * uptr;
unsigned char refcnt;
};
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
const char * uptr; /* 8 8 */
unsigned char refcnt; /* 16 1 */
/* size: 24, cachelines: 1, members: 3 */
/* padding: 7 */
/* last cacheline: 24 bytes */
};
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
const char * uptr;
unsigned char refcnt;
} __packed;
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
const char * uptr; /* 8 8 */
unsigned char refcnt; /* 16 1 */
/* size: 17, cachelines: 1, members: 3 */
/* last cacheline: 17 bytes */
} __attribute__((__packed__));
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
unsigned char refcnt;
const char * uptr;
};
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
unsigned char refcnt; /* 8 1 */
/* XXX 7 bytes hole, try to pack */
const char * uptr; /* 16 8 */
/* size: 24, cachelines: 1, members: 3 */
/* sum members: 17, holes: 1, sum holes: 7 */
/* last cacheline: 24 bytes */
};
$ cat a.c
#define __packed __attribute__((__packed__))
struct filename {
const char * name;
unsigned char refcnt;
const char * uptr;
} __packed;
void m(struct filename *f) {}
$ gcc -g -c a.c
$ pahole a.o
struct filename {
const char * name; /* 0 8 */
unsigned char refcnt; /* 8 1 */
const char * uptr; /* 9 8 */
/* size: 17, cachelines: 1, members: 3 */
/* last cacheline: 17 bytes */
} __attribute__((__packed__));
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-10 22:41:59 +02:00
|
|
|
|
|
|
|
return cls->is_packed;
|
|
|
|
}
|
|
|
|
|
2019-04-12 22:08:41 +02:00
|
|
|
/*
|
|
|
|
* If structs embedded in unions, nameless or not, have a size which isn't
|
|
|
|
* isn't a multiple of the union size, then it must be packed, even if
|
|
|
|
* it has no holes nor padding, as an array of such unions would have the
|
|
|
|
* natural alignments of non-multiple structs inside it broken.
|
|
|
|
*/
|
|
|
|
void union__infer_packed_attributes(struct type *type, const struct cu *cu)
|
|
|
|
{
|
|
|
|
const uint32_t union_size = type->size;
|
|
|
|
struct class_member *member;
|
|
|
|
|
|
|
|
if (type->packed_attributes_inferred)
|
|
|
|
return;
|
|
|
|
|
|
|
|
type__for_each_member(type, member) {
|
|
|
|
struct tag *member_type = tag__strip_typedefs_and_modifiers(&member->tag, cu);
|
|
|
|
|
|
|
|
if (!tag__is_struct(member_type))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
size_t natural_alignment = tag__natural_alignment(member_type, cu);
|
|
|
|
|
|
|
|
/* Would this break the natural alignment */
|
|
|
|
if ((union_size % natural_alignment) != 0) {
|
|
|
|
struct class *cls = tag__class(member_type);
|
|
|
|
|
|
|
|
cls->is_packed = true;
|
|
|
|
cls->type.packed_attributes_inferred = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type->packed_attributes_inferred = true;
|
|
|
|
}
|
|
|
|
|
[LIB]: Introduce class__has_hole_ge()
That returns if the class has a hole greater or equal to the size specified.
Pahole now has a --hole_size_ge command line option to use it.
Example on a linux kernel built for x86_64 where we list the structs that have
holes bigger than 32 bytes, that provides an approximation of structs with
____cacheline_aligned_in_smp annotated members:
[acme@filo pahole]$ pahole --hole_size_ge 32 examples/vmlinux-x86_64
inet_hashinfo
rcu_ctrlblk
hh_cache
net_device
files_struct
module
zone
For instance, look at struct zone clever use of such construct:
_pad1_ is defined with ZONE_PADDING(_pad1_), that is:
/* <40e> /home/acme/git/net-2.6.22/include/linux/mmzone.h:179 */
struct zone {
long unsigned int pages_min; /* 0 8 */
long unsigned int pages_low; /* 8 8 */
long unsigned int pages_high; /* 16 8 */
long unsigned int lowmem_reserve[3]; /* 24 24 */
int node; /* 48 4 */
/* XXX 4 bytes hole, try to pack */
long unsigned int min_unmapped_pages; /* 56 8 */
/* --- cacheline 1 boundary (64 bytes) --- */
long unsigned int min_slab_pages; /* 64 8 */
struct per_cpu_pageset * pageset[255]; /* 72 2040 */
/* --- cacheline 33 boundary (2112 bytes) --- */
spinlock_t lock; /* 2112 4 */
/* XXX 4 bytes hole, try to pack */
struct free_area free_area[11]; /* 2120 264 */
/* XXX 48 bytes hole, try to pack */
/* --- cacheline 38 boundary (2432 bytes) --- */
struct zone_padding _pad1_; /* 2432 0 */
spinlock_t lru_lock; /* 2432 4 */
/* XXX 4 bytes hole, try to pack */
struct list_head active_list; /* 2440 16 */
struct list_head inactive_list; /* 2456 16 */
long unsigned int nr_scan_active; /* 2472 8 */
long unsigned int nr_scan_inactive; /* 2480 8 */
long unsigned int pages_scanned; /* 2488 8 */
/* --- cacheline 39 boundary (2496 bytes) --- */
int all_unreclaimable; /* 2496 4 */
atomic_t reclaim_in_progress; /* 2500 4 */
atomic_long_t vm_stat[20]; /* 2504 160 */
/* --- cacheline 41 boundary (2624 bytes) was 40 bytes ago --- */
int prev_priority; /* 2664 4 */
/* XXX 20 bytes hole, try to pack */
/* --- cacheline 42 boundary (2688 bytes) --- */
struct zone_padding _pad2_; /* 2688 0 */
wait_queue_head_t * wait_table; /* 2688 8 */
long unsigned int wait_table_hash_nr_entries; /* 2696 8 */
long unsigned int wait_table_bits; /* 2704 8 */
struct pglist_data * zone_pgdat; /* 2712 8 */
long unsigned int zone_start_pfn; /* 2720 8 */
long unsigned int spanned_pages; /* 2728 8 */
long unsigned int present_pages; /* 2736 8 */
const char * name; /* 2744 8 */
/* --- cacheline 43 boundary (2752 bytes) --- */
}; /* size: 2752, cachelines: 43 */
/* sum members: 2672, holes: 5, sum holes: 80 */
/* definitions: 933 */
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-05-11 18:32:53 +02:00
|
|
|
/** class__has_hole_ge - check if class has a hole greater or equal to @size
|
2012-08-17 23:47:15 +02:00
|
|
|
* @class - class instance
|
[LIB]: Introduce class__has_hole_ge()
That returns if the class has a hole greater or equal to the size specified.
Pahole now has a --hole_size_ge command line option to use it.
Example on a linux kernel built for x86_64 where we list the structs that have
holes bigger than 32 bytes, that provides an approximation of structs with
____cacheline_aligned_in_smp annotated members:
[acme@filo pahole]$ pahole --hole_size_ge 32 examples/vmlinux-x86_64
inet_hashinfo
rcu_ctrlblk
hh_cache
net_device
files_struct
module
zone
For instance, look at struct zone clever use of such construct:
_pad1_ is defined with ZONE_PADDING(_pad1_), that is:
/* <40e> /home/acme/git/net-2.6.22/include/linux/mmzone.h:179 */
struct zone {
long unsigned int pages_min; /* 0 8 */
long unsigned int pages_low; /* 8 8 */
long unsigned int pages_high; /* 16 8 */
long unsigned int lowmem_reserve[3]; /* 24 24 */
int node; /* 48 4 */
/* XXX 4 bytes hole, try to pack */
long unsigned int min_unmapped_pages; /* 56 8 */
/* --- cacheline 1 boundary (64 bytes) --- */
long unsigned int min_slab_pages; /* 64 8 */
struct per_cpu_pageset * pageset[255]; /* 72 2040 */
/* --- cacheline 33 boundary (2112 bytes) --- */
spinlock_t lock; /* 2112 4 */
/* XXX 4 bytes hole, try to pack */
struct free_area free_area[11]; /* 2120 264 */
/* XXX 48 bytes hole, try to pack */
/* --- cacheline 38 boundary (2432 bytes) --- */
struct zone_padding _pad1_; /* 2432 0 */
spinlock_t lru_lock; /* 2432 4 */
/* XXX 4 bytes hole, try to pack */
struct list_head active_list; /* 2440 16 */
struct list_head inactive_list; /* 2456 16 */
long unsigned int nr_scan_active; /* 2472 8 */
long unsigned int nr_scan_inactive; /* 2480 8 */
long unsigned int pages_scanned; /* 2488 8 */
/* --- cacheline 39 boundary (2496 bytes) --- */
int all_unreclaimable; /* 2496 4 */
atomic_t reclaim_in_progress; /* 2500 4 */
atomic_long_t vm_stat[20]; /* 2504 160 */
/* --- cacheline 41 boundary (2624 bytes) was 40 bytes ago --- */
int prev_priority; /* 2664 4 */
/* XXX 20 bytes hole, try to pack */
/* --- cacheline 42 boundary (2688 bytes) --- */
struct zone_padding _pad2_; /* 2688 0 */
wait_queue_head_t * wait_table; /* 2688 8 */
long unsigned int wait_table_hash_nr_entries; /* 2696 8 */
long unsigned int wait_table_bits; /* 2704 8 */
struct pglist_data * zone_pgdat; /* 2712 8 */
long unsigned int zone_start_pfn; /* 2720 8 */
long unsigned int spanned_pages; /* 2728 8 */
long unsigned int present_pages; /* 2736 8 */
const char * name; /* 2744 8 */
/* --- cacheline 43 boundary (2752 bytes) --- */
}; /* size: 2752, cachelines: 43 */
/* sum members: 2672, holes: 5, sum holes: 80 */
/* definitions: 933 */
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-05-11 18:32:53 +02:00
|
|
|
* @size - hole size to check
|
|
|
|
*/
|
2012-08-17 23:47:15 +02:00
|
|
|
int class__has_hole_ge(const struct class *class, const uint16_t size)
|
[LIB]: Introduce class__has_hole_ge()
That returns if the class has a hole greater or equal to the size specified.
Pahole now has a --hole_size_ge command line option to use it.
Example on a linux kernel built for x86_64 where we list the structs that have
holes bigger than 32 bytes, that provides an approximation of structs with
____cacheline_aligned_in_smp annotated members:
[acme@filo pahole]$ pahole --hole_size_ge 32 examples/vmlinux-x86_64
inet_hashinfo
rcu_ctrlblk
hh_cache
net_device
files_struct
module
zone
For instance, look at struct zone clever use of such construct:
_pad1_ is defined with ZONE_PADDING(_pad1_), that is:
/* <40e> /home/acme/git/net-2.6.22/include/linux/mmzone.h:179 */
struct zone {
long unsigned int pages_min; /* 0 8 */
long unsigned int pages_low; /* 8 8 */
long unsigned int pages_high; /* 16 8 */
long unsigned int lowmem_reserve[3]; /* 24 24 */
int node; /* 48 4 */
/* XXX 4 bytes hole, try to pack */
long unsigned int min_unmapped_pages; /* 56 8 */
/* --- cacheline 1 boundary (64 bytes) --- */
long unsigned int min_slab_pages; /* 64 8 */
struct per_cpu_pageset * pageset[255]; /* 72 2040 */
/* --- cacheline 33 boundary (2112 bytes) --- */
spinlock_t lock; /* 2112 4 */
/* XXX 4 bytes hole, try to pack */
struct free_area free_area[11]; /* 2120 264 */
/* XXX 48 bytes hole, try to pack */
/* --- cacheline 38 boundary (2432 bytes) --- */
struct zone_padding _pad1_; /* 2432 0 */
spinlock_t lru_lock; /* 2432 4 */
/* XXX 4 bytes hole, try to pack */
struct list_head active_list; /* 2440 16 */
struct list_head inactive_list; /* 2456 16 */
long unsigned int nr_scan_active; /* 2472 8 */
long unsigned int nr_scan_inactive; /* 2480 8 */
long unsigned int pages_scanned; /* 2488 8 */
/* --- cacheline 39 boundary (2496 bytes) --- */
int all_unreclaimable; /* 2496 4 */
atomic_t reclaim_in_progress; /* 2500 4 */
atomic_long_t vm_stat[20]; /* 2504 160 */
/* --- cacheline 41 boundary (2624 bytes) was 40 bytes ago --- */
int prev_priority; /* 2664 4 */
/* XXX 20 bytes hole, try to pack */
/* --- cacheline 42 boundary (2688 bytes) --- */
struct zone_padding _pad2_; /* 2688 0 */
wait_queue_head_t * wait_table; /* 2688 8 */
long unsigned int wait_table_hash_nr_entries; /* 2696 8 */
long unsigned int wait_table_bits; /* 2704 8 */
struct pglist_data * zone_pgdat; /* 2712 8 */
long unsigned int zone_start_pfn; /* 2720 8 */
long unsigned int spanned_pages; /* 2728 8 */
long unsigned int present_pages; /* 2736 8 */
const char * name; /* 2744 8 */
/* --- cacheline 43 boundary (2752 bytes) --- */
}; /* size: 2752, cachelines: 43 */
/* sum members: 2672, holes: 5, sum holes: 80 */
/* definitions: 933 */
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-05-11 18:32:53 +02:00
|
|
|
{
|
|
|
|
struct class_member *pos;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
if (class->nr_holes == 0)
|
[LIB]: Introduce class__has_hole_ge()
That returns if the class has a hole greater or equal to the size specified.
Pahole now has a --hole_size_ge command line option to use it.
Example on a linux kernel built for x86_64 where we list the structs that have
holes bigger than 32 bytes, that provides an approximation of structs with
____cacheline_aligned_in_smp annotated members:
[acme@filo pahole]$ pahole --hole_size_ge 32 examples/vmlinux-x86_64
inet_hashinfo
rcu_ctrlblk
hh_cache
net_device
files_struct
module
zone
For instance, look at struct zone clever use of such construct:
_pad1_ is defined with ZONE_PADDING(_pad1_), that is:
/* <40e> /home/acme/git/net-2.6.22/include/linux/mmzone.h:179 */
struct zone {
long unsigned int pages_min; /* 0 8 */
long unsigned int pages_low; /* 8 8 */
long unsigned int pages_high; /* 16 8 */
long unsigned int lowmem_reserve[3]; /* 24 24 */
int node; /* 48 4 */
/* XXX 4 bytes hole, try to pack */
long unsigned int min_unmapped_pages; /* 56 8 */
/* --- cacheline 1 boundary (64 bytes) --- */
long unsigned int min_slab_pages; /* 64 8 */
struct per_cpu_pageset * pageset[255]; /* 72 2040 */
/* --- cacheline 33 boundary (2112 bytes) --- */
spinlock_t lock; /* 2112 4 */
/* XXX 4 bytes hole, try to pack */
struct free_area free_area[11]; /* 2120 264 */
/* XXX 48 bytes hole, try to pack */
/* --- cacheline 38 boundary (2432 bytes) --- */
struct zone_padding _pad1_; /* 2432 0 */
spinlock_t lru_lock; /* 2432 4 */
/* XXX 4 bytes hole, try to pack */
struct list_head active_list; /* 2440 16 */
struct list_head inactive_list; /* 2456 16 */
long unsigned int nr_scan_active; /* 2472 8 */
long unsigned int nr_scan_inactive; /* 2480 8 */
long unsigned int pages_scanned; /* 2488 8 */
/* --- cacheline 39 boundary (2496 bytes) --- */
int all_unreclaimable; /* 2496 4 */
atomic_t reclaim_in_progress; /* 2500 4 */
atomic_long_t vm_stat[20]; /* 2504 160 */
/* --- cacheline 41 boundary (2624 bytes) was 40 bytes ago --- */
int prev_priority; /* 2664 4 */
/* XXX 20 bytes hole, try to pack */
/* --- cacheline 42 boundary (2688 bytes) --- */
struct zone_padding _pad2_; /* 2688 0 */
wait_queue_head_t * wait_table; /* 2688 8 */
long unsigned int wait_table_hash_nr_entries; /* 2696 8 */
long unsigned int wait_table_bits; /* 2704 8 */
struct pglist_data * zone_pgdat; /* 2712 8 */
long unsigned int zone_start_pfn; /* 2720 8 */
long unsigned int spanned_pages; /* 2728 8 */
long unsigned int present_pages; /* 2736 8 */
const char * name; /* 2744 8 */
/* --- cacheline 43 boundary (2752 bytes) --- */
}; /* size: 2752, cachelines: 43 */
/* sum members: 2672, holes: 5, sum holes: 80 */
/* definitions: 933 */
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-05-11 18:32:53 +02:00
|
|
|
return 0;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
type__for_each_data_member(&class->type, pos)
|
[LIB]: Introduce class__has_hole_ge()
That returns if the class has a hole greater or equal to the size specified.
Pahole now has a --hole_size_ge command line option to use it.
Example on a linux kernel built for x86_64 where we list the structs that have
holes bigger than 32 bytes, that provides an approximation of structs with
____cacheline_aligned_in_smp annotated members:
[acme@filo pahole]$ pahole --hole_size_ge 32 examples/vmlinux-x86_64
inet_hashinfo
rcu_ctrlblk
hh_cache
net_device
files_struct
module
zone
For instance, look at struct zone clever use of such construct:
_pad1_ is defined with ZONE_PADDING(_pad1_), that is:
/* <40e> /home/acme/git/net-2.6.22/include/linux/mmzone.h:179 */
struct zone {
long unsigned int pages_min; /* 0 8 */
long unsigned int pages_low; /* 8 8 */
long unsigned int pages_high; /* 16 8 */
long unsigned int lowmem_reserve[3]; /* 24 24 */
int node; /* 48 4 */
/* XXX 4 bytes hole, try to pack */
long unsigned int min_unmapped_pages; /* 56 8 */
/* --- cacheline 1 boundary (64 bytes) --- */
long unsigned int min_slab_pages; /* 64 8 */
struct per_cpu_pageset * pageset[255]; /* 72 2040 */
/* --- cacheline 33 boundary (2112 bytes) --- */
spinlock_t lock; /* 2112 4 */
/* XXX 4 bytes hole, try to pack */
struct free_area free_area[11]; /* 2120 264 */
/* XXX 48 bytes hole, try to pack */
/* --- cacheline 38 boundary (2432 bytes) --- */
struct zone_padding _pad1_; /* 2432 0 */
spinlock_t lru_lock; /* 2432 4 */
/* XXX 4 bytes hole, try to pack */
struct list_head active_list; /* 2440 16 */
struct list_head inactive_list; /* 2456 16 */
long unsigned int nr_scan_active; /* 2472 8 */
long unsigned int nr_scan_inactive; /* 2480 8 */
long unsigned int pages_scanned; /* 2488 8 */
/* --- cacheline 39 boundary (2496 bytes) --- */
int all_unreclaimable; /* 2496 4 */
atomic_t reclaim_in_progress; /* 2500 4 */
atomic_long_t vm_stat[20]; /* 2504 160 */
/* --- cacheline 41 boundary (2624 bytes) was 40 bytes ago --- */
int prev_priority; /* 2664 4 */
/* XXX 20 bytes hole, try to pack */
/* --- cacheline 42 boundary (2688 bytes) --- */
struct zone_padding _pad2_; /* 2688 0 */
wait_queue_head_t * wait_table; /* 2688 8 */
long unsigned int wait_table_hash_nr_entries; /* 2696 8 */
long unsigned int wait_table_bits; /* 2704 8 */
struct pglist_data * zone_pgdat; /* 2712 8 */
long unsigned int zone_start_pfn; /* 2720 8 */
long unsigned int spanned_pages; /* 2728 8 */
long unsigned int present_pages; /* 2736 8 */
const char * name; /* 2744 8 */
/* --- cacheline 43 boundary (2752 bytes) --- */
}; /* size: 2752, cachelines: 43 */
/* sum members: 2672, holes: 5, sum holes: 80 */
/* definitions: 933 */
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-05-11 18:32:53 +02:00
|
|
|
if (pos->hole >= size)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
struct class_member *type__find_member_by_name(const struct type *type,
|
2009-04-02 23:46:54 +02:00
|
|
|
const struct cu *cu,
|
2007-01-09 13:00:47 +01:00
|
|
|
const char *name)
|
[CODIFF]: Detect and print all sorts of changes in structs
[acme@newtoy examples]$ cat struct.c
static struct foo {
char a:2;
unsigned int b;
unsigned long c;
unsigned long d;
unsigned long e;
} bar;
int main(int argc, char *argv[])
{
printf("%d", bar.a);
}
[acme@newtoy examples]$
Then change "a:2" to "a:4":
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
1 struct changed
Now, on top of that move a after b:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 4(4) 1(4) */
b;
from: unsigned int /* 4(0) 4(0) */
to: unsigned int /* 0(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Move it back a to before b and change the type of e without changing its size,
i.e. from unsigned long to long:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 16(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Now on top of this lets delete the c member:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | -4
nr_members: -1
-long unsigned int c; /* 8 4 */
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
d;
from: long unsigned int /* 12(0) 4(0) */
to: long unsigned int /* 8(0) 4(0) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 12(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
WOW, many changes, what an ABI breakage, no? :-)
It started as:
[acme@newtoy examples]$ pahole old_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:2; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int c; /* 8 4 */
long unsigned int d; /* 12 4 */
long unsigned int e; /* 16 4 */
}; /* size: 20, sum members: 17, holes: 1, sum holes: 3 */
And ended up as:
[acme@newtoy examples]$ pahole new_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:4; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int d; /* 8 4 */
long int e; /* 12 4 */
}; /* size: 16, sum members: 13, holes: 1, sum holes: 3 */
[acme@newtoy examples]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 18:07:21 +01:00
|
|
|
{
|
2009-03-06 16:41:29 +01:00
|
|
|
if (name == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
struct class_member *pos;
|
2012-08-17 23:47:15 +02:00
|
|
|
type__for_each_data_member(type, pos) {
|
2009-04-02 23:46:54 +02:00
|
|
|
const char *curr_name = class_member__name(pos, cu);
|
|
|
|
if (curr_name && strcmp(curr_name, name) == 0)
|
2009-03-06 16:41:29 +01:00
|
|
|
return pos;
|
2009-04-02 23:46:54 +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
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-03-07 22:04:20 +01:00
|
|
|
uint32_t type__nr_members_of_type(const struct type *type, const type_id_t type_id)
|
2007-05-10 20:28:00 +02:00
|
|
|
{
|
|
|
|
struct class_member *pos;
|
|
|
|
uint32_t nr_members_of_type = 0;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
type__for_each_member(type, pos)
|
|
|
|
if (pos->tag.type == type_id)
|
2007-05-10 20:28:00 +02:00
|
|
|
++nr_members_of_type;
|
|
|
|
|
|
|
|
return nr_members_of_type;
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void lexblock__account_inline_expansions(struct lexblock *block,
|
2007-01-03 01:26:01 +01:00
|
|
|
const struct cu *cu)
|
[PFUNCT]: Improve --cu_inline_expansions_stats
Now it shows the number that each of the inline functions were expanded in an
object file:
Top 10 inline functions expanded more than once in kernel/sched.o, by total
size of inline expansions:
[acme@newtoy guinea_pig-2.6]$ pfunct --cu_inline_expansions_stats kernel/sched.o | sort -k3 -nr | grep -v ': 1 ' | head -11
kernel/sched.c: 318 10217
get_current: 38 325
finish_task_switch: 2 238
normal_prio: 2 167
__cpus_and: 14 164
find_process_by_pid: 6 152
current_thread_info: 21 149
sched_find_first_bit: 2 148
update_cpu_clock: 2 140
task_rq_unlock: 14 137
variable_test_bit: 14 121
[acme@newtoy guinea_pig-2.6]$
Now we have these options:
[acme@newtoy guinea_pig-2.6]$ pfunct --help
usage: pfunct [options] <file_name> {<function_name>}
where:
-c, --class=<class> functions that have <class> pointer parameters
-g, --goto_labels show number of goto labels
-i, --show_inline_expansions show inline expansions
-C, --cu_inline_expansions_stats show CU inline expansions stats
-s, --sizes show size of functions
-N, --function_name_len show size of functions
-p, --nr_parameters show number or parameters
-S, --variables show number of variables
-V, --verbose be verbose
[acme@newtoy guinea_pig-2.6]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-03 19:22:12 +01:00
|
|
|
{
|
2007-01-04 00:29:24 +01:00
|
|
|
struct tag *pos, *type;
|
[PFUNCT]: Improve --cu_inline_expansions_stats
Now it shows the number that each of the inline functions were expanded in an
object file:
Top 10 inline functions expanded more than once in kernel/sched.o, by total
size of inline expansions:
[acme@newtoy guinea_pig-2.6]$ pfunct --cu_inline_expansions_stats kernel/sched.o | sort -k3 -nr | grep -v ': 1 ' | head -11
kernel/sched.c: 318 10217
get_current: 38 325
finish_task_switch: 2 238
normal_prio: 2 167
__cpus_and: 14 164
find_process_by_pid: 6 152
current_thread_info: 21 149
sched_find_first_bit: 2 148
update_cpu_clock: 2 140
task_rq_unlock: 14 137
variable_test_bit: 14 121
[acme@newtoy guinea_pig-2.6]$
Now we have these options:
[acme@newtoy guinea_pig-2.6]$ pfunct --help
usage: pfunct [options] <file_name> {<function_name>}
where:
-c, --class=<class> functions that have <class> pointer parameters
-g, --goto_labels show number of goto labels
-i, --show_inline_expansions show inline expansions
-C, --cu_inline_expansions_stats show CU inline expansions stats
-s, --sizes show size of functions
-N, --function_name_len show size of functions
-p, --nr_parameters show number or parameters
-S, --variables show number of variables
-V, --verbose be verbose
[acme@newtoy guinea_pig-2.6]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-03 19:22:12 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
if (block->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;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
list_for_each_entry(pos, &block->tags, node) {
|
2007-01-03 01:26:01 +01:00
|
|
|
if (pos->tag == DW_TAG_lexical_block) {
|
|
|
|
lexblock__account_inline_expansions(tag__lexblock(pos),
|
|
|
|
cu);
|
|
|
|
continue;
|
|
|
|
} else if (pos->tag != DW_TAG_inlined_subroutine)
|
|
|
|
continue;
|
|
|
|
|
2009-03-25 00:12:59 +01:00
|
|
|
type = cu__function(cu, pos->type);
|
2006-11-18 17:33:48 +01:00
|
|
|
if (type != NULL) {
|
2007-01-04 00:29:24 +01:00
|
|
|
struct function *ftype = tag__function(type);
|
|
|
|
|
|
|
|
ftype->cu_total_nr_inline_expansions++;
|
|
|
|
ftype->cu_total_size_inline_expansions +=
|
2007-01-03 01:26:01 +01:00
|
|
|
tag__inline_expansion(pos)->size;
|
[PFUNCT]: Improve --cu_inline_expansions_stats
Now it shows the number that each of the inline functions were expanded in an
object file:
Top 10 inline functions expanded more than once in kernel/sched.o, by total
size of inline expansions:
[acme@newtoy guinea_pig-2.6]$ pfunct --cu_inline_expansions_stats kernel/sched.o | sort -k3 -nr | grep -v ': 1 ' | head -11
kernel/sched.c: 318 10217
get_current: 38 325
finish_task_switch: 2 238
normal_prio: 2 167
__cpus_and: 14 164
find_process_by_pid: 6 152
current_thread_info: 21 149
sched_find_first_bit: 2 148
update_cpu_clock: 2 140
task_rq_unlock: 14 137
variable_test_bit: 14 121
[acme@newtoy guinea_pig-2.6]$
Now we have these options:
[acme@newtoy guinea_pig-2.6]$ pfunct --help
usage: pfunct [options] <file_name> {<function_name>}
where:
-c, --class=<class> functions that have <class> pointer parameters
-g, --goto_labels show number of goto labels
-i, --show_inline_expansions show inline expansions
-C, --cu_inline_expansions_stats show CU inline expansions stats
-s, --sizes show size of functions
-N, --function_name_len show size of functions
-p, --nr_parameters show number or parameters
-S, --variables show number of variables
-V, --verbose be verbose
[acme@newtoy guinea_pig-2.6]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-03 19:22:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
2006-11-03 18:38:43 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
void cu__account_inline_expansions(struct cu *cu)
|
2006-11-03 18:38:43 +01:00
|
|
|
{
|
2007-01-04 00:29:24 +01:00
|
|
|
struct tag *pos;
|
|
|
|
struct function *fpos;
|
2006-11-03 18:38:43 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
list_for_each_entry(pos, &cu->tags, node) {
|
2009-03-06 15:14:26 +01:00
|
|
|
if (!tag__is_function(pos))
|
2007-01-04 00:29:24 +01:00
|
|
|
continue;
|
|
|
|
fpos = tag__function(pos);
|
2012-08-17 23:47:15 +02:00
|
|
|
lexblock__account_inline_expansions(&fpos->lexblock, cu);
|
|
|
|
cu->nr_inline_expansions += fpos->lexblock.nr_inline_expansions;
|
|
|
|
cu->size_inline_expansions += fpos->lexblock.size_inline_expansions;
|
2006-11-03 18:38:43 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static int list__for_all_tags(struct list_head *list, struct cu *cu,
|
2009-03-08 14:36:24 +01:00
|
|
|
int (*iterator)(struct tag *tag,
|
|
|
|
struct cu *cu, void *cookie),
|
|
|
|
void *cookie)
|
|
|
|
{
|
2009-03-11 16:31:17 +01:00
|
|
|
struct tag *pos, *n;
|
2009-03-08 14:36:24 +01:00
|
|
|
|
2020-02-12 20:04:31 +01:00
|
|
|
if (list_empty(list) || !list->next)
|
|
|
|
return 0;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
list_for_each_entry_safe_reverse(pos, n, list, node) {
|
2009-03-08 14:36:24 +01:00
|
|
|
if (tag__has_namespace(pos)) {
|
2009-03-20 16:53:43 +01:00
|
|
|
struct namespace *space = tag__namespace(pos);
|
|
|
|
|
2009-04-03 14:19:19 +02:00
|
|
|
/*
|
|
|
|
* See comment in type__for_each_enumerator, the
|
|
|
|
* enumerators (enum entries) are shared, but the
|
|
|
|
* enumeration tag must be deleted.
|
|
|
|
*/
|
|
|
|
if (!space->shared_tags &&
|
|
|
|
list__for_all_tags(&space->tags, cu,
|
2009-03-20 16:53:43 +01:00
|
|
|
iterator, cookie))
|
2009-03-08 14:36:24 +01:00
|
|
|
return 1;
|
2009-03-15 02:40:56 +01:00
|
|
|
/*
|
|
|
|
* vtable functions are already in the class tags list
|
|
|
|
*/
|
2009-03-11 16:31:17 +01:00
|
|
|
} else if (tag__is_function(pos)) {
|
2009-03-08 14:36:24 +01:00
|
|
|
if (list__for_all_tags(&tag__ftype(pos)->parms,
|
|
|
|
cu, iterator, cookie))
|
|
|
|
return 1;
|
|
|
|
if (list__for_all_tags(&tag__function(pos)->lexblock.tags,
|
|
|
|
cu, iterator, cookie))
|
|
|
|
return 1;
|
2009-03-11 16:31:17 +01:00
|
|
|
} else if (pos->tag == DW_TAG_subroutine_type) {
|
2009-03-08 14:36:24 +01:00
|
|
|
if (list__for_all_tags(&tag__ftype(pos)->parms,
|
|
|
|
cu, iterator, cookie))
|
|
|
|
return 1;
|
2009-03-11 16:31:17 +01:00
|
|
|
} else if (pos->tag == DW_TAG_lexical_block) {
|
|
|
|
if (list__for_all_tags(&tag__lexblock(pos)->tags,
|
|
|
|
cu, iterator, cookie))
|
|
|
|
return 1;
|
2009-03-08 14:36:24 +01:00
|
|
|
}
|
2009-03-11 16:31:17 +01:00
|
|
|
|
2009-03-08 14:36:24 +01:00
|
|
|
if (iterator(pos, cu, cookie))
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
int cu__for_all_tags(struct cu *cu,
|
2009-03-08 14:36:24 +01:00
|
|
|
int (*iterator)(struct tag *tag,
|
|
|
|
struct cu *cu, void *cookie),
|
|
|
|
void *cookie)
|
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
return list__for_all_tags(&cu->tags, cu, iterator, cookie);
|
2009-03-08 14:36:24 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
void cus__for_each_cu(struct cus *cus,
|
2006-11-11 19:31:04 +01:00
|
|
|
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;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
list_for_each_entry(pos, &cus->cus, node) {
|
2006-12-01 02:48:34 +01:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
int cus__load_dir(struct cus *cus, struct conf_load *conf,
|
2009-03-13 13:31:48 +01:00
|
|
|
const char *dirname, const char *filename_mask,
|
|
|
|
const int recursive)
|
2006-12-27 17:57:19 +01:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
dwarves: Avoid truncation when concatenating paths for dir entries
To cope with this warning on s390x:
/usr/bin/cc -DDWARVES_VERSION=\"v1.16\" -D_GNU_SOURCE -Ddwarves_EXPORTS -I/builddir/build/BUILD/dwarves-1.16 -I/builddir/build/BUILD/dwarves-1.16/lib/bpf/include/uapi -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -march=zEC12 -mtune=z13 -fasynchronous-unwind-tables -fstack-clash-protection -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Wall -Werror -ggdb -O2 -fPIC -o CMakeFiles/dwarves.dir/libctf.c.o -c /builddir/build/BUILD/dwarves-1.16/libctf.c
/builddir/build/BUILD/dwarves-1.16/dwarves.h: In function 'cus__load_dir':
/builddir/build/BUILD/dwarves-1.16/dwarves.c:1663:44: error: '%s' directive output may be truncated writing up to 255 bytes into a region of size between 0 and 4095 [-Werror=format-truncation=]
1663 | snprintf(pathname, sizeof(pathname), "%s/%s",
| ^~
In file included from /usr/include/stdio.h:867,
from /builddir/build/BUILD/dwarves-1.16/dwarves.c:18:
/usr/include/bits/stdio2.h:67:10: note: '__builtin___snprintf_chk' output between 2 and 4352 bytes into a destination of size 4096
67 | return __builtin___snprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1,
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
68 | __bos (__s), __fmt, __va_arg_pack ());
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/builddir/build/BUILD/dwarves-1.16/dwarves.c:1663:44: error: '%s' directive output may be truncated writing up to 255 bytes into a region of size between 0 and 4095 [-Werror=format-truncation=]
1663 | snprintf(pathname, sizeof(pathname), "%s/%s",
| ^~
In file included from /usr/include/stdio.h:867,
from /builddir/build/BUILD/dwarves-1.16/dwarves.c:18:
/usr/include/bits/stdio2.h:67:10: note: '__builtin___snprintf_chk' output between 2 and 4352 bytes into a destination of size 4096
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-02-12 20:28:49 +01:00
|
|
|
snprintf(pathname, sizeof(pathname), "%.*s/%s",
|
|
|
|
(int)(sizeof(pathname) - sizeof(entry->d_name) - 1), dirname, entry->d_name);
|
2006-12-27 17:57:19 +01:00
|
|
|
|
|
|
|
err = lstat(pathname, &st);
|
|
|
|
if (err != 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (S_ISDIR(st.st_mode)) {
|
|
|
|
if (!recursive)
|
|
|
|
continue;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
err = cus__load_dir(cus, conf, pathname,
|
2006-12-27 17:57:19 +01:00
|
|
|
filename_mask, recursive);
|
|
|
|
if (err != 0)
|
|
|
|
break;
|
|
|
|
} else if (fnmatch(filename_mask, entry->d_name, 0) == 0) {
|
2012-08-17 23:47:15 +02:00
|
|
|
err = cus__load_file(cus, conf, pathname);
|
2006-12-27 17:57:19 +01:00
|
|
|
if (err != 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err == -1)
|
|
|
|
puts(dirname);
|
|
|
|
closedir(dir);
|
|
|
|
out:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2009-03-19 16:13:00 +01:00
|
|
|
/*
|
|
|
|
* This should really do demand loading of DSOs, STABS anyone? 8-)
|
|
|
|
*/
|
2019-02-14 14:47:32 +01:00
|
|
|
extern struct debug_fmt_ops dwarf__ops, ctf__ops, btf_elf__ops;
|
2009-04-04 19:56:39 +02:00
|
|
|
|
|
|
|
static struct debug_fmt_ops *debug_fmt_table[] = {
|
|
|
|
&dwarf__ops,
|
2019-02-14 14:47:32 +01:00
|
|
|
&btf_elf__ops,
|
dwarves: Move BTF loader ahead of the CTF one
When we call the tools without specifying a file format, all the
available format loaders are called, in sequence, till we find the
relevant information, now that we support raw BTF we better move it in
front of the CTF one, as it is way more common in the Linux community.
With this we will not see this warning anymore:
$ pahole -C list_head /sys/kernel/btf/vmlinux
ctf__new: cannot get elf header.
struct list_head {
struct list_head * next; /* 0 8 */
struct list_head * prev; /* 8 8 */
/* size: 16, cachelines: 1, members: 2 */
/* last cacheline: 16 bytes */
};
$
That warning has to go, so that other formats, if present after the CTF
one, can be tried.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-01-03 14:45:04 +01:00
|
|
|
&ctf__ops,
|
2009-04-04 19:56:39 +02:00
|
|
|
NULL,
|
2009-03-19 16:13:00 +01:00
|
|
|
};
|
|
|
|
|
2009-04-04 19:56:39 +02:00
|
|
|
static int debugging_formats__loader(const char *name)
|
2009-03-19 16:13:00 +01:00
|
|
|
{
|
|
|
|
int i = 0;
|
2009-04-04 19:56:39 +02:00
|
|
|
while (debug_fmt_table[i] != NULL) {
|
|
|
|
if (strcmp(debug_fmt_table[i]->name, name) == 0)
|
|
|
|
return i;
|
2009-03-19 16:13:00 +01:00
|
|
|
++i;
|
|
|
|
}
|
2009-04-04 19:56:39 +02:00
|
|
|
return -1;
|
2009-03-19 16:13:00 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
int cus__load_file(struct cus *cus, struct conf_load *conf,
|
2009-06-08 19:17:23 +02:00
|
|
|
const char *filename)
|
2007-03-30 18:22:28 +02:00
|
|
|
{
|
2009-03-19 16:19:37 +01:00
|
|
|
int i = 0, err = 0;
|
2009-04-04 19:56:39 +02:00
|
|
|
int loader;
|
2009-03-19 16:13:00 +01:00
|
|
|
|
|
|
|
if (conf && conf->format_path != NULL) {
|
2009-03-19 16:19:37 +01:00
|
|
|
char *fpath = strdup(conf->format_path);
|
|
|
|
if (fpath == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
char *fp = fpath;
|
|
|
|
while (1) {
|
|
|
|
char *sep = strchr(fp, ',');
|
|
|
|
|
|
|
|
if (sep != NULL)
|
|
|
|
*sep = '\0';
|
|
|
|
|
|
|
|
err = -ENOTSUP;
|
|
|
|
loader = debugging_formats__loader(fp);
|
2009-04-04 19:56:39 +02:00
|
|
|
if (loader == -1)
|
2009-03-19 16:19:37 +01:00
|
|
|
break;
|
|
|
|
|
2019-04-15 18:51:28 +02:00
|
|
|
if (conf->conf_fprintf)
|
|
|
|
conf->conf_fprintf->has_alignment_info = debug_fmt_table[loader]->has_alignment_info;
|
|
|
|
|
2009-03-19 16:19:37 +01:00
|
|
|
err = 0;
|
2012-08-17 23:47:15 +02:00
|
|
|
if (debug_fmt_table[loader]->load_file(cus, conf,
|
2009-06-05 04:15:52 +02:00
|
|
|
filename) == 0)
|
2009-03-19 16:19:37 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
err = -EINVAL;
|
|
|
|
if (sep == NULL)
|
|
|
|
break;
|
|
|
|
|
|
|
|
fp = sep + 1;
|
2009-03-19 16:13:00 +01:00
|
|
|
}
|
2009-03-19 16:19:37 +01:00
|
|
|
free(fpath);
|
|
|
|
return err;
|
2009-03-19 16:13:00 +01:00
|
|
|
}
|
2008-03-04 19:37:02 +01:00
|
|
|
|
2009-04-04 19:56:39 +02:00
|
|
|
while (debug_fmt_table[i] != NULL) {
|
2019-07-02 15:18:58 +02:00
|
|
|
if (conf && conf->conf_fprintf)
|
2019-04-15 18:51:28 +02:00
|
|
|
conf->conf_fprintf->has_alignment_info = debug_fmt_table[i]->has_alignment_info;
|
2012-08-17 23:47:15 +02:00
|
|
|
if (debug_fmt_table[i]->load_file(cus, conf, filename) == 0)
|
2009-03-19 16:13:00 +01:00
|
|
|
return 0;
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -EINVAL;
|
2007-03-30 18:22:28 +02:00
|
|
|
}
|
|
|
|
|
2017-11-24 15:24:16 +01:00
|
|
|
#define BUILD_ID_SIZE 20
|
|
|
|
#define SBUILD_ID_SIZE (BUILD_ID_SIZE * 2 + 1)
|
|
|
|
|
|
|
|
#define NOTE_ALIGN(sz) (((sz) + 3) & ~3)
|
|
|
|
|
|
|
|
#define NT_GNU_BUILD_ID 3
|
|
|
|
|
|
|
|
#ifndef min
|
|
|
|
#define min(x, y) ({ \
|
|
|
|
typeof(x) _min1 = (x); \
|
|
|
|
typeof(y) _min2 = (y); \
|
|
|
|
(void) (&_min1 == &_min2); \
|
|
|
|
_min1 < _min2 ? _min1 : _min2; })
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Force a compilation error if condition is true, but also produce a
|
|
|
|
result (of value 0 and type size_t), so the expression can be used
|
|
|
|
e.g. in a structure initializer (or where-ever else comma expressions
|
|
|
|
aren't permitted). */
|
|
|
|
#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
|
|
|
|
|
|
|
|
/* Are two types/vars the same type (ignoring qualifiers)? */
|
|
|
|
#ifndef __same_type
|
|
|
|
# define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* &a[0] degrades to a pointer: a different type from an array */
|
|
|
|
#define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))
|
|
|
|
|
|
|
|
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
|
|
|
|
|
|
|
|
static int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
|
|
|
|
{
|
|
|
|
int fd, err = -1;
|
|
|
|
|
|
|
|
if (size < BUILD_ID_SIZE)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
fd = open(filename, O_RDONLY);
|
|
|
|
if (fd < 0)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
char bf[BUFSIZ];
|
|
|
|
GElf_Nhdr nhdr;
|
|
|
|
size_t namesz, descsz;
|
|
|
|
|
|
|
|
if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
|
|
|
|
break;
|
|
|
|
|
|
|
|
namesz = NOTE_ALIGN(nhdr.n_namesz);
|
|
|
|
descsz = NOTE_ALIGN(nhdr.n_descsz);
|
|
|
|
if (nhdr.n_type == NT_GNU_BUILD_ID &&
|
|
|
|
nhdr.n_namesz == sizeof("GNU")) {
|
|
|
|
if (read(fd, bf, namesz) != (ssize_t)namesz)
|
|
|
|
break;
|
|
|
|
if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
|
|
|
|
size_t sz = min(descsz, size);
|
|
|
|
if (read(fd, build_id, sz) == (ssize_t)sz) {
|
|
|
|
memset(build_id + sz, 0, size - sz);
|
|
|
|
err = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else if (read(fd, bf, descsz) != (ssize_t)descsz)
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
int n = namesz + descsz;
|
|
|
|
|
|
|
|
if (n > (int)sizeof(bf)) {
|
|
|
|
n = sizeof(bf);
|
|
|
|
fprintf(stderr, "%s: truncating reading of build id in sysfs file %s: n_namesz=%u, n_descsz=%u.\n",
|
|
|
|
__func__, filename, nhdr.n_namesz, nhdr.n_descsz);
|
|
|
|
}
|
|
|
|
if (read(fd, bf, n) != n)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
close(fd);
|
|
|
|
out:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int elf_read_build_id(Elf *elf, void *bf, size_t size)
|
|
|
|
{
|
|
|
|
int err = -1;
|
|
|
|
GElf_Ehdr ehdr;
|
|
|
|
GElf_Shdr shdr;
|
|
|
|
Elf_Data *data;
|
|
|
|
Elf_Scn *sec;
|
|
|
|
Elf_Kind ek;
|
|
|
|
void *ptr;
|
|
|
|
|
|
|
|
if (size < BUILD_ID_SIZE)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
ek = elf_kind(elf);
|
|
|
|
if (ek != ELF_K_ELF)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
if (gelf_getehdr(elf, &ehdr) == NULL) {
|
|
|
|
fprintf(stderr, "%s: cannot get elf header.\n", __func__);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check following sections for notes:
|
|
|
|
* '.note.gnu.build-id'
|
|
|
|
* '.notes'
|
|
|
|
* '.note' (VDSO specific)
|
|
|
|
*/
|
|
|
|
do {
|
|
|
|
sec = elf_section_by_name(elf, &ehdr, &shdr,
|
|
|
|
".note.gnu.build-id", NULL);
|
|
|
|
if (sec)
|
|
|
|
break;
|
|
|
|
|
|
|
|
sec = elf_section_by_name(elf, &ehdr, &shdr,
|
|
|
|
".notes", NULL);
|
|
|
|
if (sec)
|
|
|
|
break;
|
|
|
|
|
|
|
|
sec = elf_section_by_name(elf, &ehdr, &shdr,
|
|
|
|
".note", NULL);
|
|
|
|
if (sec)
|
|
|
|
break;
|
|
|
|
|
|
|
|
return err;
|
|
|
|
|
|
|
|
} while (0);
|
|
|
|
|
|
|
|
data = elf_getdata(sec, NULL);
|
|
|
|
if (data == NULL)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
ptr = data->d_buf;
|
|
|
|
while (ptr < (data->d_buf + data->d_size)) {
|
|
|
|
GElf_Nhdr *nhdr = ptr;
|
|
|
|
size_t namesz = NOTE_ALIGN(nhdr->n_namesz),
|
|
|
|
descsz = NOTE_ALIGN(nhdr->n_descsz);
|
|
|
|
const char *name;
|
|
|
|
|
|
|
|
ptr += sizeof(*nhdr);
|
|
|
|
name = ptr;
|
|
|
|
ptr += namesz;
|
|
|
|
if (nhdr->n_type == NT_GNU_BUILD_ID &&
|
|
|
|
nhdr->n_namesz == sizeof("GNU")) {
|
|
|
|
if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
|
|
|
|
size_t sz = min(size, descsz);
|
|
|
|
memcpy(bf, ptr, sz);
|
|
|
|
memset(bf + sz, 0, size - sz);
|
|
|
|
err = descsz;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ptr += descsz;
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int filename__read_build_id(const char *filename, void *bf, size_t size)
|
|
|
|
{
|
|
|
|
int fd, err = -1;
|
|
|
|
Elf *elf;
|
|
|
|
|
|
|
|
if (size < BUILD_ID_SIZE)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
fd = open(filename, O_RDONLY);
|
|
|
|
if (fd < 0)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
elf = elf_begin(fd, ELF_C_READ, NULL);
|
|
|
|
if (elf == NULL) {
|
|
|
|
fprintf(stderr, "%s: cannot read %s ELF file.\n", __func__, filename);
|
|
|
|
goto out_close;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = elf_read_build_id(elf, bf, size);
|
|
|
|
|
|
|
|
elf_end(elf);
|
|
|
|
out_close:
|
|
|
|
close(fd);
|
|
|
|
out:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int build_id__sprintf(const unsigned char *build_id, int len, char *bf)
|
|
|
|
{
|
|
|
|
char *bid = bf;
|
|
|
|
const unsigned char *raw = build_id;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < len; ++i) {
|
|
|
|
sprintf(bid, "%02x", *raw);
|
|
|
|
++raw;
|
|
|
|
bid += 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (bid - bf) + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sysfs__sprintf_build_id(const char *root_dir, char *sbuild_id)
|
|
|
|
{
|
|
|
|
char notes[PATH_MAX];
|
|
|
|
unsigned char build_id[BUILD_ID_SIZE];
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!root_dir)
|
|
|
|
root_dir = "";
|
|
|
|
|
|
|
|
snprintf(notes, sizeof(notes), "%s/sys/kernel/notes", root_dir);
|
|
|
|
|
|
|
|
ret = sysfs__read_build_id(notes, build_id, sizeof(build_id));
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
return build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int filename__sprintf_build_id(const char *pathname, char *sbuild_id)
|
|
|
|
{
|
|
|
|
unsigned char build_id[BUILD_ID_SIZE];
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = filename__read_build_id(pathname, build_id, sizeof(build_id));
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
else if (ret != sizeof(build_id))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
return build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define zfree(ptr) ({ free(*ptr); *ptr = NULL; })
|
|
|
|
|
|
|
|
static int vmlinux_path__nr_entries;
|
|
|
|
static char **vmlinux_path;
|
|
|
|
|
|
|
|
static void vmlinux_path__exit(void)
|
|
|
|
{
|
|
|
|
while (--vmlinux_path__nr_entries >= 0)
|
|
|
|
zfree(&vmlinux_path[vmlinux_path__nr_entries]);
|
|
|
|
vmlinux_path__nr_entries = 0;
|
|
|
|
|
|
|
|
zfree(&vmlinux_path);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char * const vmlinux_paths[] = {
|
|
|
|
"vmlinux",
|
|
|
|
"/boot/vmlinux"
|
|
|
|
};
|
|
|
|
|
|
|
|
static const char * const vmlinux_paths_upd[] = {
|
|
|
|
"/boot/vmlinux-%s",
|
|
|
|
"/usr/lib/debug/boot/vmlinux-%s",
|
|
|
|
"/lib/modules/%s/build/vmlinux",
|
|
|
|
"/usr/lib/debug/lib/modules/%s/vmlinux",
|
|
|
|
"/usr/lib/debug/boot/vmlinux-%s.debug"
|
|
|
|
};
|
|
|
|
|
|
|
|
static int vmlinux_path__add(const char *new_entry)
|
|
|
|
{
|
|
|
|
vmlinux_path[vmlinux_path__nr_entries] = strdup(new_entry);
|
|
|
|
if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
|
|
|
|
return -1;
|
|
|
|
++vmlinux_path__nr_entries;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int vmlinux_path__init(void)
|
|
|
|
{
|
|
|
|
struct utsname uts;
|
|
|
|
char bf[PATH_MAX];
|
|
|
|
char *kernel_version;
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
vmlinux_path = malloc(sizeof(char *) * (ARRAY_SIZE(vmlinux_paths) +
|
|
|
|
ARRAY_SIZE(vmlinux_paths_upd)));
|
|
|
|
if (vmlinux_path == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(vmlinux_paths); i++)
|
|
|
|
if (vmlinux_path__add(vmlinux_paths[i]) < 0)
|
|
|
|
goto out_fail;
|
|
|
|
|
|
|
|
if (uname(&uts) < 0)
|
|
|
|
goto out_fail;
|
|
|
|
|
|
|
|
kernel_version = uts.release;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(vmlinux_paths_upd); i++) {
|
|
|
|
snprintf(bf, sizeof(bf), vmlinux_paths_upd[i], kernel_version);
|
|
|
|
if (vmlinux_path__add(bf) < 0)
|
|
|
|
goto out_fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
out_fail:
|
|
|
|
vmlinux_path__exit();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cus__load_running_kernel(struct cus *cus, struct conf_load *conf)
|
|
|
|
{
|
|
|
|
int i, err = 0;
|
|
|
|
char running_sbuild_id[SBUILD_ID_SIZE];
|
|
|
|
|
btf loader: Support raw BTF as available in /sys/kernel/btf/vmlinux
Be it automatically when no -F option is passed and
/sys/kernel/btf/vmlinux is available, or when /sys/kernel/btf/vmlinux is
passed as the filename to the tool, i.e.:
$ pahole -C list_head
struct list_head {
struct list_head * next; /* 0 8 */
struct list_head * prev; /* 8 8 */
/* size: 16, cachelines: 1, members: 2 */
/* last cacheline: 16 bytes */
};
$ strace -e openat pahole -C list_head |& grep /sys/kernel/btf/
openat(AT_FDCWD, "/sys/kernel/btf/vmlinux", O_RDONLY) = 3
$
$ pahole -C list_head /sys/kernel/btf/vmlinux
struct list_head {
struct list_head * next; /* 0 8 */
struct list_head * prev; /* 8 8 */
/* size: 16, cachelines: 1, members: 2 */
/* last cacheline: 16 bytes */
};
$
If one wants to grab the matching vmlinux to use its DWARF info instead,
which is useful to compare the results with what we have from BTF, for
instance, its just a matter of using '-F dwarf'.
This in turn shows something that at first came as a surprise, but then
has a simple explanation:
For very common data structures, that will probably appear in all of the
DWARF CUs (Compilation Units), like 'struct list_head', using '-F dwarf'
is faster:
[acme@quaco pahole]$ perf stat -e cycles pahole -F btf -C list_head > /dev/null
Performance counter stats for 'pahole -F btf -C list_head':
45,722,518 cycles:u
0.023717300 seconds time elapsed
0.016474000 seconds user
0.007212000 seconds sys
[acme@quaco pahole]$ perf stat -e cycles pahole -F dwarf -C list_head > /dev/null
Performance counter stats for 'pahole -F dwarf -C list_head':
14,170,321 cycles:u
0.006668904 seconds time elapsed
0.005562000 seconds user
0.001109000 seconds sys
[acme@quaco pahole]$
But for something that is more specific to a subsystem, the DWARF loader
will have to process way more stuff till it gets to that struct:
$ perf stat -e cycles pahole -F dwarf -C tcp_sock > /dev/null
Performance counter stats for 'pahole -F dwarf -C tcp_sock':
31,579,795,238 cycles:u
8.332272930 seconds time elapsed
8.032124000 seconds user
0.286537000 seconds sys
$
While using the BTF loader the time should be constant, as it loads
everything from /sys/kernel/btf/vmlinux:
$ perf stat -e cycles pahole -F btf -C tcp_sock > /dev/null
Performance counter stats for 'pahole -F btf -C tcp_sock':
48,823,488 cycles:u
0.024102760 seconds time elapsed
0.012035000 seconds user
0.012046000 seconds sys
$
Above I used '-F btf' just to show that it can be used, but its not
really needed, i.e. those are equivalent:
$ strace -e openat pahole -F btf -C list_head |& grep /sys/kernel/btf/vmlinux
openat(AT_FDCWD, "/sys/kernel/btf/vmlinux", O_RDONLY) = 3
$ strace -e openat pahole -C list_head |& grep /sys/kernel/btf/vmlinux
openat(AT_FDCWD, "/sys/kernel/btf/vmlinux", O_RDONLY) = 3
$
The btf_raw__load() function that ends up being grafted into the
preexisting btf_elf routines was based on libbpf's btf_load_raw().
Acked-by: Alexei Starovoitov <ast@fb.com>
Cc: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-01-02 19:22:23 +01:00
|
|
|
if ((!conf || conf->format_path == NULL || strncmp(conf->format_path, "btf", 3) == 0) &&
|
|
|
|
access("/sys/kernel/btf/vmlinux", R_OK) == 0) {
|
|
|
|
int loader = debugging_formats__loader("btf");
|
|
|
|
if (loader == -1)
|
|
|
|
goto try_elf;
|
|
|
|
|
2020-02-12 20:10:09 +01:00
|
|
|
if (conf && conf->conf_fprintf)
|
btf loader: Support raw BTF as available in /sys/kernel/btf/vmlinux
Be it automatically when no -F option is passed and
/sys/kernel/btf/vmlinux is available, or when /sys/kernel/btf/vmlinux is
passed as the filename to the tool, i.e.:
$ pahole -C list_head
struct list_head {
struct list_head * next; /* 0 8 */
struct list_head * prev; /* 8 8 */
/* size: 16, cachelines: 1, members: 2 */
/* last cacheline: 16 bytes */
};
$ strace -e openat pahole -C list_head |& grep /sys/kernel/btf/
openat(AT_FDCWD, "/sys/kernel/btf/vmlinux", O_RDONLY) = 3
$
$ pahole -C list_head /sys/kernel/btf/vmlinux
struct list_head {
struct list_head * next; /* 0 8 */
struct list_head * prev; /* 8 8 */
/* size: 16, cachelines: 1, members: 2 */
/* last cacheline: 16 bytes */
};
$
If one wants to grab the matching vmlinux to use its DWARF info instead,
which is useful to compare the results with what we have from BTF, for
instance, its just a matter of using '-F dwarf'.
This in turn shows something that at first came as a surprise, but then
has a simple explanation:
For very common data structures, that will probably appear in all of the
DWARF CUs (Compilation Units), like 'struct list_head', using '-F dwarf'
is faster:
[acme@quaco pahole]$ perf stat -e cycles pahole -F btf -C list_head > /dev/null
Performance counter stats for 'pahole -F btf -C list_head':
45,722,518 cycles:u
0.023717300 seconds time elapsed
0.016474000 seconds user
0.007212000 seconds sys
[acme@quaco pahole]$ perf stat -e cycles pahole -F dwarf -C list_head > /dev/null
Performance counter stats for 'pahole -F dwarf -C list_head':
14,170,321 cycles:u
0.006668904 seconds time elapsed
0.005562000 seconds user
0.001109000 seconds sys
[acme@quaco pahole]$
But for something that is more specific to a subsystem, the DWARF loader
will have to process way more stuff till it gets to that struct:
$ perf stat -e cycles pahole -F dwarf -C tcp_sock > /dev/null
Performance counter stats for 'pahole -F dwarf -C tcp_sock':
31,579,795,238 cycles:u
8.332272930 seconds time elapsed
8.032124000 seconds user
0.286537000 seconds sys
$
While using the BTF loader the time should be constant, as it loads
everything from /sys/kernel/btf/vmlinux:
$ perf stat -e cycles pahole -F btf -C tcp_sock > /dev/null
Performance counter stats for 'pahole -F btf -C tcp_sock':
48,823,488 cycles:u
0.024102760 seconds time elapsed
0.012035000 seconds user
0.012046000 seconds sys
$
Above I used '-F btf' just to show that it can be used, but its not
really needed, i.e. those are equivalent:
$ strace -e openat pahole -F btf -C list_head |& grep /sys/kernel/btf/vmlinux
openat(AT_FDCWD, "/sys/kernel/btf/vmlinux", O_RDONLY) = 3
$ strace -e openat pahole -C list_head |& grep /sys/kernel/btf/vmlinux
openat(AT_FDCWD, "/sys/kernel/btf/vmlinux", O_RDONLY) = 3
$
The btf_raw__load() function that ends up being grafted into the
preexisting btf_elf routines was based on libbpf's btf_load_raw().
Acked-by: Alexei Starovoitov <ast@fb.com>
Cc: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-01-02 19:22:23 +01:00
|
|
|
conf->conf_fprintf->has_alignment_info = debug_fmt_table[loader]->has_alignment_info;
|
|
|
|
|
|
|
|
if (debug_fmt_table[loader]->load_file(cus, conf, "/sys/kernel/btf/vmlinux") == 0)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
try_elf:
|
2017-11-24 15:24:16 +01:00
|
|
|
elf_version(EV_CURRENT);
|
|
|
|
vmlinux_path__init();
|
|
|
|
|
|
|
|
sysfs__sprintf_build_id(NULL, running_sbuild_id);
|
|
|
|
|
|
|
|
for (i = 0; i < vmlinux_path__nr_entries; ++i) {
|
|
|
|
char sbuild_id[SBUILD_ID_SIZE];
|
|
|
|
|
|
|
|
if (filename__sprintf_build_id(vmlinux_path[i], sbuild_id) > 0 &&
|
|
|
|
strcmp(sbuild_id, running_sbuild_id) == 0) {
|
|
|
|
err = cus__load_file(cus, conf, vmlinux_path[i]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
vmlinux_path__exit();
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
int cus__load_files(struct cus *cus, struct conf_load *conf,
|
2009-03-13 14:49:01 +01:00
|
|
|
char *filenames[])
|
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
while (filenames[i] != NULL) {
|
2012-08-17 23:47:15 +02:00
|
|
|
if (cus__load_file(cus, conf, filenames[i]))
|
2016-03-15 16:16:46 +01:00
|
|
|
return -++i;
|
2009-03-13 14:49:01 +01:00
|
|
|
++i;
|
|
|
|
}
|
|
|
|
|
2017-12-14 18:14:56 +01:00
|
|
|
return i ? 0 : cus__load_running_kernel(cus, conf);
|
2009-03-13 14:49:01 +01:00
|
|
|
}
|
|
|
|
|
2016-03-15 18:25:58 +01:00
|
|
|
int cus__fprintf_load_files_err(struct cus *cus, const char *tool, char *argv[], int err, FILE *output)
|
|
|
|
{
|
|
|
|
/* errno is not properly preserved in some cases, sigh */
|
|
|
|
return fprintf(output, "%s: %s: %s\n", tool, argv[-err - 1],
|
|
|
|
errno ? strerror(errno) : "No debugging information found");
|
|
|
|
}
|
|
|
|
|
2008-10-01 17:47:42 +02:00
|
|
|
struct cus *cus__new(void)
|
2006-11-11 19:31:04 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
struct cus *cus = malloc(sizeof(*cus));
|
2006-11-11 19:31:04 +01:00
|
|
|
|
2019-04-08 16:54:06 +02:00
|
|
|
if (cus != NULL) {
|
|
|
|
cus->nr_entries = 0;
|
2012-08-17 23:47:15 +02:00
|
|
|
INIT_LIST_HEAD(&cus->cus);
|
2019-04-08 16:54:06 +02:00
|
|
|
}
|
2006-11-11 19:31:04 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
return cus;
|
2006-11-11 19:31:04 +01:00
|
|
|
}
|
2006-12-23 22:29:27 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
void cus__delete(struct cus *cus)
|
2009-03-11 16:31:17 +01:00
|
|
|
{
|
|
|
|
struct cu *pos, *n;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
if (cus == NULL)
|
2009-03-11 16:31:17 +01:00
|
|
|
return;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
list_for_each_entry_safe(pos, n, &cus->cus, node) {
|
2009-03-11 16:31:17 +01:00
|
|
|
list_del_init(&pos->node);
|
|
|
|
cu__delete(pos);
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
free(cus);
|
2009-03-11 16:31:17 +01:00
|
|
|
}
|
|
|
|
|
2009-04-19 18:48:51 +02:00
|
|
|
void dwarves__fprintf_init(uint16_t user_cacheline_size);
|
|
|
|
|
2009-03-07 20:45:09 +01:00
|
|
|
int dwarves__init(uint16_t user_cacheline_size)
|
2007-01-19 00:41:25 +01:00
|
|
|
{
|
2009-04-19 18:48:51 +02:00
|
|
|
dwarves__fprintf_init(user_cacheline_size);
|
2008-10-02 19:34:42 +02:00
|
|
|
|
2009-04-03 14:05:36 +02:00
|
|
|
int i = 0;
|
|
|
|
int err = 0;
|
|
|
|
|
2009-04-04 19:56:39 +02:00
|
|
|
while (debug_fmt_table[i] != NULL) {
|
|
|
|
if (debug_fmt_table[i]->init) {
|
|
|
|
err = debug_fmt_table[i]->init();
|
2009-04-03 14:05:36 +02:00
|
|
|
if (err)
|
|
|
|
goto out_fail;
|
|
|
|
}
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
|
2008-10-02 19:34:42 +02:00
|
|
|
return 0;
|
2009-04-03 14:05:36 +02:00
|
|
|
out_fail:
|
|
|
|
while (i-- != 0)
|
2009-04-04 19:56:39 +02:00
|
|
|
if (debug_fmt_table[i]->exit)
|
|
|
|
debug_fmt_table[i]->exit();
|
2009-04-03 14:05:36 +02:00
|
|
|
return err;
|
2007-01-19 00:41:25 +01:00
|
|
|
}
|
2009-02-13 13:57:23 +01:00
|
|
|
|
2009-03-11 16:31:17 +01:00
|
|
|
void dwarves__exit(void)
|
|
|
|
{
|
2009-04-03 14:05:36 +02:00
|
|
|
int i = 0;
|
|
|
|
|
2009-04-04 19:56:39 +02:00
|
|
|
while (debug_fmt_table[i] != NULL) {
|
|
|
|
if (debug_fmt_table[i]->exit)
|
|
|
|
debug_fmt_table[i]->exit();
|
2009-04-03 14:05:36 +02:00
|
|
|
++i;
|
|
|
|
}
|
2009-03-11 16:31:17 +01:00
|
|
|
}
|
|
|
|
|
2009-02-13 13:57:23 +01:00
|
|
|
struct argp_state;
|
|
|
|
|
|
|
|
void dwarves_print_version(FILE *fp, struct argp_state *state __unused)
|
|
|
|
{
|
|
|
|
fprintf(fp, "%s\n", DWARVES_VERSION);
|
|
|
|
}
|