2007-01-29 14:18:46 +01:00
|
|
|
/*
|
2019-01-15 18:28:24 +01:00
|
|
|
SPDX-License-Identifier: GPL-2.0-only
|
|
|
|
|
2006-10-25 17:49:47 +02:00
|
|
|
Copyright (C) 2006 Mandriva Conectiva S.A.
|
|
|
|
Copyright (C) 2006 Arnaldo Carvalho de Melo <acme@mandriva.com>
|
2008-02-07 12:16:22 +01:00
|
|
|
Copyright (C) 2007-2008 Arnaldo Carvalho de Melo <acme@redhat.com>
|
2006-10-25 01:42:39 +02:00
|
|
|
*/
|
|
|
|
|
2007-03-30 15:07:01 +02:00
|
|
|
#include <argp.h>
|
2008-10-28 21:56:47 +01:00
|
|
|
#include <assert.h>
|
2006-10-25 01:42:39 +02:00
|
|
|
#include <stdio.h>
|
2006-10-28 23:22:42 +02:00
|
|
|
#include <dwarf.h>
|
2008-10-28 21:56:47 +01:00
|
|
|
#include <search.h>
|
2006-12-18 13:47:39 +01:00
|
|
|
#include <stdarg.h>
|
2006-10-25 01:42:39 +02:00
|
|
|
#include <stdlib.h>
|
2006-11-11 17:15:50 +01:00
|
|
|
#include <string.h>
|
2006-10-25 01:42:39 +02:00
|
|
|
|
2007-05-07 05:30:02 +02:00
|
|
|
#include "dwarves_reorganize.h"
|
2007-01-11 19:07:05 +01:00
|
|
|
#include "dwarves.h"
|
2007-12-16 17:47:59 +01:00
|
|
|
#include "dutil.h"
|
2009-03-19 16:16:07 +01:00
|
|
|
#include "ctf_encoder.h"
|
2018-03-06 01:53:50 +01:00
|
|
|
#include "btf_encoder.h"
|
2009-03-19 16:16:07 +01:00
|
|
|
|
2018-03-06 01:53:50 +01:00
|
|
|
static bool btf_encode;
|
2009-03-19 16:16:07 +01:00
|
|
|
static bool ctf_encode;
|
2009-08-24 20:13:58 +02:00
|
|
|
static bool first_obj_only;
|
2006-10-25 01:42:39 +02:00
|
|
|
|
2007-01-28 14:07:22 +01:00
|
|
|
static uint8_t class__include_anonymous;
|
|
|
|
static uint8_t class__include_nested_anonymous;
|
2008-01-12 16:14:40 +01:00
|
|
|
static uint8_t word_size, original_word_size;
|
2007-01-28 14:07:22 +01:00
|
|
|
|
2006-12-01 02:23:41 +01:00
|
|
|
static char *class__exclude_prefix;
|
|
|
|
static size_t class__exclude_prefix_len;
|
2006-12-01 02:12:21 +01:00
|
|
|
|
2008-04-21 17:41:44 +02:00
|
|
|
static char *class__include_prefix;
|
|
|
|
static size_t class__include_prefix_len;
|
|
|
|
|
2006-12-01 02:36:55 +01:00
|
|
|
static char *cu__exclude_prefix;
|
|
|
|
static size_t cu__exclude_prefix_len;
|
|
|
|
|
2006-12-01 03:08:10 +01:00
|
|
|
static char *decl_exclude_prefix;
|
|
|
|
static size_t decl_exclude_prefix_len;
|
|
|
|
|
2006-12-28 14:18:43 +01:00
|
|
|
static uint16_t nr_holes;
|
|
|
|
static uint16_t nr_bit_holes;
|
[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
|
|
|
static uint16_t hole_size_ge;
|
2006-12-18 19:27:14 +01:00
|
|
|
static uint8_t show_packable;
|
[PAHOLE]: Reorganize bitfields
This cset also does a fixup for cases where the compiler keeps the type
specified by the programmer for a bitfield but uses less space to combine with
the next, non-bitfield member, these cases can be caught using plain pahole and
will appear with this comment:
/* --- cacheline 1 boundary (64 bytes) --- */
int bitfield1:1; /* 64 4 */
int bitfield2:1; /* 64 4 */
/* XXX 14 bits hole, try to pack */
/* Bitfield WARNING: DWARF size=4, real size=2 */
short int d; /* 66 2 */
The fixup is done prior to reorganizing the fields.
Now an example of this code in action:
[acme@filo examples]$ cat swiss_cheese.c
<SNIP>
struct cheese {
char id;
short number;
char name[52];
int a:1;
int b;
int bitfield1:1;
int bitfield2:1;
short d;
short e;
short last:5;
};
<SNIP>
[acme@filo examples]$
Lets look at the layout:
[acme@filo examples]$ pahole swiss_cheese cheese
/* <11b> /home/acme/git/pahole/examples/swiss_cheese.c:3 */
struct cheese {
char id; /* 0 1 */
/* XXX 1 byte hole, try to pack */
short int number; /* 2 2 */
char name[52]; /* 4 52 */
int a:1; /* 56 4 */
/* XXX 31 bits hole, try to pack */
int b; /* 60 4 */
/* --- cacheline 1 boundary (64 bytes) --- */
int bitfield1:1; /* 64 4 */
int bitfield2:1; /* 64 4 */
/* XXX 14 bits hole, try to pack */
/* Bitfield WARNING: DWARF size=4, real size=2 */
short int d; /* 66 2 */
short int e; /* 68 2 */
short int last:5; /* 70 2 */
}; /* size: 72, cachelines: 2 */
/* sum members: 71, holes: 1, sum holes: 1 */
/* bit holes: 2, sum bit holes: 45 bits */
/* bit_padding: 11 bits */
/* last cacheline: 8 bytes */
[acme@filo examples]$
Full of holes, has bit padding and uses more than one 64 bytes cacheline.
Now lets ask pahole to reorganize it:
[acme@filo examples]$ pahole --reorganize --verbose swiss_cheese cheese
/* Demoting bitfield ('a' ... 'a') from 'int' to 'unsigned char' */
/* Demoting bitfield ('bitfield1' ... 'bitfield2') from 'short unsigned int' to 'unsigned char' */
/* Demoting bitfield ('last') from 'short int' to 'unsigned char' */
/* Moving 'bitfield2:1' from after 'bitfield1' to after 'a:1' */
/* Moving 'bitfield1:1' from after 'b' to after 'bitfield2:1' */
/* Moving 'last:5' from after 'e' to after 'bitfield1:1' */
/* Moving bitfield('a' ... 'last') from after 'name' to after 'id' */
/* Moving 'e' from after 'd' to after 'b' */
/* <11b> /home/acme/git/pahole/examples/swiss_cheese.c:3 */
struct cheese {
char id; /* 0 1 */
unsigned char a:1; /* 1 1 */
unsigned char bitfield2:1; /* 1 1 */
unsigned char bitfield1:1; /* 1 1 */
unsigned char last:5; /* 1 1 */
short int number; /* 2 2 */
char name[52]; /* 4 52 */
int b; /* 56 4 */
short int e; /* 60 2 */
short int d; /* 62 2 */
/* --- cacheline 1 boundary (64 bytes) --- */
}; /* size: 64, cachelines: 1 */
/* saved 8 bytes and 1 cacheline! */
[acme@filo examples]$
Instant karma, it gets completely packed, and look ma, no
__attribute__((packed)) :-)
With this struct task_struct in the linux kernel is shrunk by 12 bytes, there
is more 4 bytes to save with another technique that involves not combining
holes, but using the last single hole to fill it with members at the tail of
the struct.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2007-02-01 13:51:16 +01:00
|
|
|
static uint8_t global_verbose;
|
2007-05-11 00:11:51 +02:00
|
|
|
static uint8_t recursive;
|
2007-03-30 15:07:01 +02:00
|
|
|
static size_t cacheline_size;
|
2007-05-10 20:28:00 +02:00
|
|
|
static uint8_t find_containers;
|
2007-11-16 21:18:08 +01:00
|
|
|
static uint8_t find_pointers_in_structs;
|
2007-03-30 15:07:01 +02:00
|
|
|
static int reorganize;
|
2009-03-20 15:37:22 +01:00
|
|
|
static bool show_private_classes;
|
2008-02-07 12:16:22 +01:00
|
|
|
static bool defined_in;
|
pahole: Introduce --unions to consider just unions
Most filters can be used together with it, for instance to see the
biggest unions in the kernel:
$ pahole --unions --sizes | sort -k2 -nr | head
thread_union 16384 0
swap_header 4096 0
fpregs_state 4096 0
autofs_v5_packet_union 304 0
autofs_packet_union 272 0
pptp_ctrl_union 208 0
acpi_parse_object 200 0
acpi_descriptor 200 0
bpf_attr 120 0
phy_configure_opts 112 0
$
Or just some unions that have some specific prefix:
$ pahole --unions --prefix tcp
union tcp_md5_addr {
struct in_addr a4; /* 0 4 */
struct in6_addr a6; /* 0 16 */
};
union tcp_word_hdr {
struct tcphdr hdr; /* 0 20 */
__be32 words[5]; /* 0 20 */
};
union tcp_cc_info {
struct tcpvegas_info vegas; /* 0 16 */
struct tcp_dctcp_info dctcp; /* 0 16 */
struct tcp_bbr_info bbr; /* 0 20 */
};
$
What are the biggest unions in terms of number of members?
$ pahole --unions --nr_members | sort -k2 -nr | head
security_list_options 218
aml_resource 36
acpi_resource_data 29
acpi_operand_object 26
iwreq_data 18
sctp_params 15
ib_flow_spec 14
ethtool_flow_union 14
pptp_ctrl_union 13
bpf_attr 12
$
If you want to script most of the queries can change the separator:
$ pahole --unions --nr_members -t, | sort -t, -k2 -nr | head
security_list_options,218
aml_resource,36
acpi_resource_data,29
acpi_operand_object,26
iwreq_data,18
sctp_params,15
ib_flow_spec,14
ethtool_flow_union,14
pptp_ctrl_union,13
bpf_attr,12
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-01-15 15:35:25 +01:00
|
|
|
static bool just_unions;
|
2020-01-15 16:41:28 +01:00
|
|
|
static bool just_structs;
|
2007-03-30 15:07:01 +02:00
|
|
|
static int show_reorg_steps;
|
2007-04-24 21:09:34 +02:00
|
|
|
static char *class_name;
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
static struct strlist *class_names;
|
2007-05-23 21:15:21 +02:00
|
|
|
static char separator = '\t';
|
2006-12-07 19:14:15 +01:00
|
|
|
|
2007-06-22 21:43:29 +02:00
|
|
|
static struct conf_fprintf conf = {
|
2007-05-24 22:18:32 +02:00
|
|
|
.emit_stats = 1,
|
|
|
|
};
|
|
|
|
|
2019-04-15 18:51:28 +02:00
|
|
|
static struct conf_load conf_load = {
|
|
|
|
.conf_fprintf = &conf,
|
|
|
|
};
|
2009-03-09 18:43:47 +01:00
|
|
|
|
2006-11-04 00:24:37 +01:00
|
|
|
struct structure {
|
2007-05-24 23:45:34 +02:00
|
|
|
struct list_head node;
|
2009-06-19 05:42:42 +02:00
|
|
|
struct rb_node rb_node;
|
2009-04-03 14:04:26 +02:00
|
|
|
char *name;
|
2007-05-24 23:45:34 +02:00
|
|
|
uint32_t nr_files;
|
|
|
|
uint32_t nr_methods;
|
2006-11-04 00:24:37 +01:00
|
|
|
};
|
|
|
|
|
2009-04-02 21:46:37 +02:00
|
|
|
static struct structure *structure__new(const char *name)
|
2006-11-04 00:24:37 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
struct structure *st = malloc(sizeof(*st));
|
2006-11-04 00:24:37 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
if (st != NULL) {
|
|
|
|
st->name = strdup(name);
|
|
|
|
if (st->name == NULL) {
|
|
|
|
free(st);
|
2009-04-02 21:46:37 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
2012-08-17 23:47:15 +02:00
|
|
|
st->nr_files = 1;
|
|
|
|
st->nr_methods = 0;
|
2006-11-04 00:24:37 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
return st;
|
2006-11-04 00:24:37 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void structure__delete(struct structure *st)
|
2009-03-11 16:31:17 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
free(st->name);
|
|
|
|
free(st);
|
2009-03-11 16:31:17 +01:00
|
|
|
}
|
|
|
|
|
2009-06-19 05:42:42 +02:00
|
|
|
static struct rb_root structures__tree = RB_ROOT;
|
2009-03-13 19:05:19 +01:00
|
|
|
static LIST_HEAD(structures__list);
|
2008-10-28 21:56:47 +01:00
|
|
|
|
2009-06-22 23:40:39 +02:00
|
|
|
static struct structure *structures__add(struct class *class,
|
|
|
|
const struct cu *cu,
|
|
|
|
bool *existing_entry)
|
2008-10-28 21:56:47 +01:00
|
|
|
{
|
2009-06-19 05:42:42 +02:00
|
|
|
struct rb_node **p = &structures__tree.rb_node;
|
|
|
|
struct rb_node *parent = NULL;
|
2008-10-28 21:56:47 +01:00
|
|
|
struct structure *str;
|
2009-06-19 05:42:42 +02:00
|
|
|
const char *new_class_name = class__name(class, cu);
|
2008-10-28 21:56:47 +01:00
|
|
|
|
2009-06-19 05:42:42 +02:00
|
|
|
while (*p != NULL) {
|
|
|
|
int rc;
|
2008-10-28 21:56:47 +01:00
|
|
|
|
2009-06-19 05:42:42 +02:00
|
|
|
parent = *p;
|
|
|
|
str = rb_entry(parent, struct structure, rb_node);
|
|
|
|
rc = strcmp(str->name, new_class_name);
|
|
|
|
|
|
|
|
if (rc > 0)
|
|
|
|
p = &(*p)->rb_left;
|
|
|
|
else if (rc < 0)
|
|
|
|
p = &(*p)->rb_right;
|
2009-06-22 23:40:39 +02:00
|
|
|
else {
|
|
|
|
*existing_entry = true;
|
2009-06-19 05:42:42 +02:00
|
|
|
return str;
|
2009-06-22 23:40:39 +02:00
|
|
|
}
|
2009-06-19 05:42:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
str = structure__new(new_class_name);
|
2008-10-28 21:56:47 +01:00
|
|
|
if (str == NULL)
|
2009-03-13 19:05:19 +01:00
|
|
|
return NULL;
|
2008-10-28 21:56:47 +01:00
|
|
|
|
2009-06-22 23:40:39 +02:00
|
|
|
*existing_entry = false;
|
2009-06-19 05:42:42 +02:00
|
|
|
rb_link_node(&str->rb_node, parent, p);
|
|
|
|
rb_insert_color(&str->rb_node, &structures__tree);
|
2007-01-28 14:07:22 +01:00
|
|
|
|
2008-10-28 21:56:47 +01:00
|
|
|
/* For linear traversals */
|
2009-03-13 19:05:19 +01:00
|
|
|
list_add_tail(&str->node, &structures__list);
|
2009-06-19 05:42:42 +02:00
|
|
|
|
2009-03-13 19:05:19 +01:00
|
|
|
return str;
|
2006-11-04 00:24:37 +01:00
|
|
|
}
|
|
|
|
|
2009-03-11 16:31:17 +01:00
|
|
|
void structures__delete(void)
|
|
|
|
{
|
2009-06-19 05:42:42 +02:00
|
|
|
struct rb_node *next = rb_first(&structures__tree);
|
|
|
|
|
|
|
|
while (next) {
|
|
|
|
struct structure *pos = rb_entry(next, struct structure, rb_node);
|
|
|
|
next = rb_next(&pos->rb_node);
|
|
|
|
rb_erase(&pos->rb_node, &structures__tree);
|
|
|
|
structure__delete(pos);
|
|
|
|
}
|
2009-03-11 16:31:17 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void nr_definitions_formatter(struct structure *st)
|
2006-12-18 13:47:39 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
printf("%s%c%u\n", st->name, separator, st->nr_files);
|
2006-11-04 00:24:37 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void nr_members_formatter(struct class *class,
|
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
|
|
|
struct cu *cu, uint32_t id __unused)
|
2006-11-04 00:24:37 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
printf("%s%c%u\n", class__name(class, cu), separator,
|
|
|
|
class__nr_members(class));
|
2006-11-04 00:24:37 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void nr_methods_formatter(struct structure *st)
|
2007-01-13 16:59:32 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
printf("%s%c%u\n", st->name, separator, st->nr_methods);
|
2007-01-13 16:59:32 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void size_formatter(struct class *class,
|
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
|
|
|
struct cu *cu, uint32_t id __unused)
|
2006-12-18 13:47:39 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
printf("%s%c%d%c%u\n", class__name(class, cu), separator,
|
2020-01-15 15:41:10 +01:00
|
|
|
class__size(class), separator, tag__is_union(class__tag(class)) ? 0 : class->nr_holes);
|
2006-12-18 13:47:39 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void class_name_len_formatter(struct class *class, struct cu *cu,
|
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 __unused)
|
2006-12-18 13:47:39 +01:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
const char *name = class__name(class, cu);
|
2007-05-23 21:15:21 +02:00
|
|
|
printf("%s%c%zd\n", name, separator, strlen(name));
|
2006-12-18 13:47:39 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void class_name_formatter(struct class *class,
|
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
|
|
|
struct cu *cu, uint32_t id __unused)
|
[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
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
puts(class__name(class, cu));
|
[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
|
|
|
}
|
|
|
|
|
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
|
|
|
static void class_formatter(struct class *class, struct cu *cu, uint32_t id)
|
2006-12-18 13:47:39 +01:00
|
|
|
{
|
2007-01-28 14:07:22 +01:00
|
|
|
struct tag *typedef_alias = NULL;
|
2012-08-17 23:47:15 +02:00
|
|
|
struct tag *tag = class__tag(class);
|
|
|
|
const char *name = class__name(class, cu);
|
2007-01-28 14:07:22 +01:00
|
|
|
|
|
|
|
if (name == NULL) {
|
|
|
|
/*
|
|
|
|
* Find the first typedef for this struct, this is enough
|
|
|
|
* as if we optimize the struct all the typedefs will be
|
|
|
|
* affected.
|
|
|
|
*/
|
2009-03-13 19:05:19 +01:00
|
|
|
typedef_alias = cu__find_first_typedef_of_type(cu, id);
|
2007-01-28 14:07:22 +01:00
|
|
|
/*
|
|
|
|
* If there is no typedefs for this anonymous struct it is
|
|
|
|
* found just inside another struct, and in this case it'll
|
|
|
|
* be printed when the type it is in is printed, but if
|
|
|
|
* the user still wants to see its statistics, just use
|
|
|
|
* --nested_anon_include.
|
|
|
|
*/
|
|
|
|
if (typedef_alias == NULL && !class__include_nested_anonymous)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (typedef_alias != NULL) {
|
2007-05-24 23:45:34 +02:00
|
|
|
struct type *tdef = tag__type(typedef_alias);
|
2007-04-28 21:13:35 +02:00
|
|
|
|
|
|
|
conf.prefix = "typedef";
|
2009-04-02 22:54:43 +02:00
|
|
|
conf.suffix = type__name(tdef, cu);
|
2007-05-24 22:18:32 +02:00
|
|
|
} else
|
|
|
|
conf.prefix = conf.suffix = NULL;
|
2007-04-28 21:13:35 +02:00
|
|
|
|
2009-03-13 19:05:19 +01:00
|
|
|
tag__fprintf(tag, cu, &conf, stdout);
|
2007-06-22 21:43:29 +02:00
|
|
|
|
2006-12-18 13:47:39 +01:00
|
|
|
putchar('\n');
|
|
|
|
}
|
|
|
|
|
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
|
|
|
static void print_packable_info(struct class *c, struct cu *cu, uint32_t id)
|
2008-10-28 21:56:47 +01:00
|
|
|
{
|
|
|
|
const struct tag *t = class__tag(c);
|
|
|
|
const size_t orig_size = class__size(c);
|
|
|
|
const size_t new_size = class__size(c->priv);
|
|
|
|
const size_t savings = orig_size - new_size;
|
2009-04-02 22:54:43 +02:00
|
|
|
const char *name = class__name(c, cu);
|
2008-10-28 21:56:47 +01:00
|
|
|
|
|
|
|
/* Anonymous struct? Try finding a typedef */
|
|
|
|
if (name == NULL) {
|
|
|
|
const struct tag *tdef =
|
2009-03-13 19:05:19 +01:00
|
|
|
cu__find_first_typedef_of_type(cu, id);
|
2008-10-28 21:56:47 +01:00
|
|
|
|
|
|
|
if (tdef != NULL)
|
2009-04-02 22:54:43 +02:00
|
|
|
name = class__name(tag__class(tdef), cu);
|
2008-10-28 21:56:47 +01:00
|
|
|
}
|
|
|
|
if (name != NULL)
|
|
|
|
printf("%s%c%zd%c%zd%c%zd\n",
|
|
|
|
name, separator,
|
|
|
|
orig_size, separator,
|
|
|
|
new_size, separator,
|
|
|
|
savings);
|
|
|
|
else
|
|
|
|
printf("%s(%d)%c%zd%c%zd%c%zd\n",
|
2009-03-13 19:05:19 +01:00
|
|
|
tag__decl_file(t, cu),
|
|
|
|
tag__decl_line(t, cu),
|
2008-10-28 21:56:47 +01:00
|
|
|
separator,
|
|
|
|
orig_size, separator,
|
|
|
|
new_size, separator,
|
|
|
|
savings);
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void (*stats_formatter)(struct structure *st);
|
2009-03-13 19:05:19 +01:00
|
|
|
|
|
|
|
static void print_stats(void)
|
2006-11-04 00:24:37 +01:00
|
|
|
{
|
|
|
|
struct structure *pos;
|
|
|
|
|
2009-03-13 19:05:19 +01:00
|
|
|
list_for_each_entry(pos, &structures__list, node)
|
|
|
|
stats_formatter(pos);
|
|
|
|
}
|
2008-10-28 21:56:47 +01:00
|
|
|
|
2009-03-13 19:05:19 +01:00
|
|
|
static struct class *class__filter(struct class *class, struct cu *cu,
|
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 tag_id);
|
2009-03-13 19:05:19 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void (*formatter)(struct class *class,
|
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
|
|
|
struct cu *cu, uint32_t id) = class_formatter;
|
2009-03-13 19:05:19 +01:00
|
|
|
|
|
|
|
static void print_classes(struct cu *cu)
|
|
|
|
{
|
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-13 19:05:19 +01:00
|
|
|
struct class *pos;
|
|
|
|
|
2018-12-03 16:51:30 +01:00
|
|
|
cu__for_each_struct_or_union(cu, id, pos) {
|
2009-06-22 23:40:39 +02:00
|
|
|
bool existing_entry;
|
|
|
|
struct structure *str;
|
|
|
|
|
2009-03-13 19:05:19 +01:00
|
|
|
if (pos->type.namespace.name == 0 &&
|
|
|
|
!(class__include_anonymous ||
|
|
|
|
class__include_nested_anonymous))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!class__filter(pos, cu, id))
|
|
|
|
continue;
|
2009-05-08 06:05:31 +02:00
|
|
|
/*
|
|
|
|
* FIXME: No sense in adding an anonymous struct to the list of
|
|
|
|
* structs already printed, as we look for the name... The
|
|
|
|
* right fix probably will be to call class__fprintf on a
|
|
|
|
* in-memory FILE, do a hash, and look it by full contents, not
|
|
|
|
* by name. And this is needed for CTF as well, but its late now
|
|
|
|
* and I'm sleepy, will leave for later...
|
|
|
|
*/
|
2009-06-27 16:59:58 +02:00
|
|
|
if (pos->type.namespace.name != 0) {
|
|
|
|
str = structures__add(pos, cu, &existing_entry);
|
|
|
|
if (str == NULL) {
|
|
|
|
fprintf(stderr, "pahole: insufficient memory for "
|
|
|
|
"processing %s, skipping it...\n", cu->name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Already printed... */
|
|
|
|
if (existing_entry) {
|
|
|
|
str->nr_files++;
|
|
|
|
continue;
|
|
|
|
}
|
2009-06-22 23:40:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (show_packable && !global_verbose)
|
|
|
|
print_packable_info(pos, cu, id);
|
|
|
|
else if (formatter != NULL)
|
|
|
|
formatter(pos, cu, id);
|
2009-03-13 19:05:19 +01:00
|
|
|
}
|
2006-11-04 00:24:37 +01:00
|
|
|
}
|
|
|
|
|
2006-12-05 17:58:27 +01:00
|
|
|
static struct cu *cu__filter(struct cu *cu)
|
2006-12-01 02:36:55 +01:00
|
|
|
{
|
|
|
|
if (cu__exclude_prefix != NULL &&
|
|
|
|
(cu->name == NULL ||
|
|
|
|
strncmp(cu__exclude_prefix, cu->name,
|
|
|
|
cu__exclude_prefix_len) == 0))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return cu;
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static int class__packable(struct class *class, struct cu *cu)
|
2006-12-07 19:14:15 +01:00
|
|
|
{
|
2009-03-14 17:50:36 +01:00
|
|
|
struct class *clone;
|
2006-12-07 19:14:15 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
if (class->nr_holes == 0 && class->nr_bit_holes == 0)
|
2006-12-07 19:14:15 +01:00
|
|
|
return 0;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
clone = class__clone(class, NULL, cu);
|
2009-03-14 17:50:36 +01:00
|
|
|
if (clone == NULL)
|
2007-04-01 14:31:35 +02:00
|
|
|
return 0;
|
2009-03-14 17:50:36 +01:00
|
|
|
class__reorganize(clone, cu, 0, stdout);
|
2012-08-17 23:47:15 +02:00
|
|
|
if (class__size(class) > class__size(clone)) {
|
|
|
|
class->priv = clone;
|
2007-04-01 15:03:04 +02:00
|
|
|
return 1;
|
|
|
|
}
|
2009-09-20 21:46:32 +02:00
|
|
|
/* FIXME: we need to free in the right order,
|
|
|
|
* cu->obstack is being corrupted...
|
2009-08-18 23:21:20 +02:00
|
|
|
class__delete(clone, cu);
|
2009-09-20 21:46:32 +02:00
|
|
|
*/
|
2007-04-01 15:03:04 +02:00
|
|
|
return 0;
|
2006-12-07 19:14:15 +01:00
|
|
|
}
|
|
|
|
|
2009-03-13 19:05:19 +01:00
|
|
|
static struct class *class__filter(struct class *class, struct cu *cu,
|
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 tag_id)
|
2006-12-01 02:12:21 +01:00
|
|
|
{
|
2009-03-13 19:05:19 +01:00
|
|
|
struct tag *tag = class__tag(class);
|
2007-01-07 15:30:58 +01:00
|
|
|
const char *name;
|
2006-12-18 13:47:39 +01:00
|
|
|
|
pahole: Introduce --unions to consider just unions
Most filters can be used together with it, for instance to see the
biggest unions in the kernel:
$ pahole --unions --sizes | sort -k2 -nr | head
thread_union 16384 0
swap_header 4096 0
fpregs_state 4096 0
autofs_v5_packet_union 304 0
autofs_packet_union 272 0
pptp_ctrl_union 208 0
acpi_parse_object 200 0
acpi_descriptor 200 0
bpf_attr 120 0
phy_configure_opts 112 0
$
Or just some unions that have some specific prefix:
$ pahole --unions --prefix tcp
union tcp_md5_addr {
struct in_addr a4; /* 0 4 */
struct in6_addr a6; /* 0 16 */
};
union tcp_word_hdr {
struct tcphdr hdr; /* 0 20 */
__be32 words[5]; /* 0 20 */
};
union tcp_cc_info {
struct tcpvegas_info vegas; /* 0 16 */
struct tcp_dctcp_info dctcp; /* 0 16 */
struct tcp_bbr_info bbr; /* 0 20 */
};
$
What are the biggest unions in terms of number of members?
$ pahole --unions --nr_members | sort -k2 -nr | head
security_list_options 218
aml_resource 36
acpi_resource_data 29
acpi_operand_object 26
iwreq_data 18
sctp_params 15
ib_flow_spec 14
ethtool_flow_union 14
pptp_ctrl_union 13
bpf_attr 12
$
If you want to script most of the queries can change the separator:
$ pahole --unions --nr_members -t, | sort -t, -k2 -nr | head
security_list_options,218
aml_resource,36
acpi_resource_data,29
acpi_operand_object,26
iwreq_data,18
sctp_params,15
ib_flow_spec,14
ethtool_flow_union,14
pptp_ctrl_union,13
bpf_attr,12
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-01-15 15:35:25 +01:00
|
|
|
if (just_unions && !tag__is_union(tag))
|
|
|
|
return NULL;
|
|
|
|
|
2020-01-15 16:41:28 +01:00
|
|
|
if (just_structs && !tag__is_struct(tag))
|
|
|
|
return NULL;
|
|
|
|
|
2009-06-22 23:40:39 +02:00
|
|
|
if (!tag->top_level) {
|
|
|
|
class__find_holes(class);
|
|
|
|
|
|
|
|
if (!show_private_classes)
|
|
|
|
return 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
|
|
|
|
2009-04-02 22:54:43 +02:00
|
|
|
name = class__name(class, cu);
|
2006-12-01 03:00:24 +01:00
|
|
|
|
2007-01-09 13:00:47 +01:00
|
|
|
if (class__is_declaration(class))
|
2006-12-18 13:47:39 +01:00
|
|
|
return NULL;
|
|
|
|
|
2007-01-28 14:07:22 +01:00
|
|
|
if (!class__include_anonymous && name == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2007-04-04 19:21:41 +02:00
|
|
|
if (class__exclude_prefix != NULL) {
|
|
|
|
if (name == NULL) {
|
|
|
|
const struct tag *tdef =
|
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
|
|
|
cu__find_first_typedef_of_type(cu, tag_id);
|
2008-10-28 21:56:47 +01:00
|
|
|
if (tdef != NULL) {
|
|
|
|
struct class *c = tag__class(tdef);
|
|
|
|
|
2009-04-02 22:54:43 +02:00
|
|
|
name = class__name(c, cu);
|
2008-10-28 21:56:47 +01:00
|
|
|
}
|
2007-04-04 19:21:41 +02:00
|
|
|
}
|
|
|
|
if (name != NULL && strncmp(class__exclude_prefix, name,
|
|
|
|
class__exclude_prefix_len) == 0)
|
|
|
|
return NULL;
|
|
|
|
}
|
2006-12-01 02:12:21 +01:00
|
|
|
|
2008-04-21 17:41:44 +02:00
|
|
|
if (class__include_prefix != NULL) {
|
|
|
|
if (name == NULL) {
|
|
|
|
const struct tag *tdef =
|
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
|
|
|
cu__find_first_typedef_of_type(cu, tag_id);
|
2008-10-28 21:56:47 +01:00
|
|
|
if (tdef != NULL) {
|
|
|
|
struct class *c = tag__class(tdef);
|
|
|
|
|
2009-04-02 22:54:43 +02:00
|
|
|
name = class__name(c, cu);
|
2008-10-28 21:56:47 +01:00
|
|
|
}
|
2008-04-21 17:41:44 +02:00
|
|
|
}
|
|
|
|
if (name != NULL && strncmp(class__include_prefix, name,
|
|
|
|
class__include_prefix_len) != 0)
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2006-12-01 03:08:10 +01:00
|
|
|
if (decl_exclude_prefix != 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
|
|
|
(!tag__decl_file(tag, cu) ||
|
|
|
|
strncmp(decl_exclude_prefix, tag__decl_file(tag, cu),
|
2006-12-01 03:08:10 +01:00
|
|
|
decl_exclude_prefix_len) == 0))
|
|
|
|
return NULL;
|
pahole: Introduce --unions to consider just unions
Most filters can be used together with it, for instance to see the
biggest unions in the kernel:
$ pahole --unions --sizes | sort -k2 -nr | head
thread_union 16384 0
swap_header 4096 0
fpregs_state 4096 0
autofs_v5_packet_union 304 0
autofs_packet_union 272 0
pptp_ctrl_union 208 0
acpi_parse_object 200 0
acpi_descriptor 200 0
bpf_attr 120 0
phy_configure_opts 112 0
$
Or just some unions that have some specific prefix:
$ pahole --unions --prefix tcp
union tcp_md5_addr {
struct in_addr a4; /* 0 4 */
struct in6_addr a6; /* 0 16 */
};
union tcp_word_hdr {
struct tcphdr hdr; /* 0 20 */
__be32 words[5]; /* 0 20 */
};
union tcp_cc_info {
struct tcpvegas_info vegas; /* 0 16 */
struct tcp_dctcp_info dctcp; /* 0 16 */
struct tcp_bbr_info bbr; /* 0 20 */
};
$
What are the biggest unions in terms of number of members?
$ pahole --unions --nr_members | sort -k2 -nr | head
security_list_options 218
aml_resource 36
acpi_resource_data 29
acpi_operand_object 26
iwreq_data 18
sctp_params 15
ib_flow_spec 14
ethtool_flow_union 14
pptp_ctrl_union 13
bpf_attr 12
$
If you want to script most of the queries can change the separator:
$ pahole --unions --nr_members -t, | sort -t, -k2 -nr | head
security_list_options,218
aml_resource,36
acpi_resource_data,29
acpi_operand_object,26
iwreq_data,18
sctp_params,15
ib_flow_spec,14
ethtool_flow_union,14
pptp_ctrl_union,13
bpf_attr,12
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-01-15 15:35:25 +01:00
|
|
|
/*
|
|
|
|
* if --unions was used and we got here, its a union and we satisfy the other
|
|
|
|
* filters/options, so don't filter it.
|
|
|
|
*/
|
|
|
|
if (just_unions)
|
|
|
|
return class;
|
2018-12-21 18:20:58 +01:00
|
|
|
/*
|
|
|
|
* The following only make sense for structs, i.e. 'struct class',
|
|
|
|
* and as we can get here with a union, that is represented by a 'struct type',
|
2020-01-15 15:10:12 +01:00
|
|
|
* bail out if we get here with an union and we are not looking for things
|
|
|
|
* that need finding holes, like --packable, --nr_holes, etc
|
2018-12-21 18:20:58 +01:00
|
|
|
*/
|
2020-01-15 15:10:12 +01:00
|
|
|
if (!tag__is_struct(tag))
|
2020-01-15 16:41:28 +01:00
|
|
|
return (just_structs || show_packable || nr_holes || nr_bit_holes || hole_size_ge) ? NULL : class;
|
2006-12-01 03:08:10 +01:00
|
|
|
|
2009-06-22 23:40:39 +02:00
|
|
|
if (tag->top_level)
|
|
|
|
class__find_holes(class);
|
|
|
|
|
2006-12-18 13:47:39 +01:00
|
|
|
if (class->nr_holes < nr_holes ||
|
[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->nr_bit_holes < nr_bit_holes ||
|
|
|
|
(hole_size_ge != 0 && !class__has_hole_ge(class, hole_size_ge)))
|
2006-12-18 13:47:39 +01:00
|
|
|
return NULL;
|
|
|
|
|
2007-04-01 14:31:35 +02:00
|
|
|
if (show_packable && !class__packable(class, cu))
|
2006-12-07 19:14:15 +01:00
|
|
|
return NULL;
|
|
|
|
|
2009-03-13 19:05:19 +01:00
|
|
|
return class;
|
2006-11-04 00:24:37 +01:00
|
|
|
}
|
|
|
|
|
2008-01-12 18:25:12 +01:00
|
|
|
static void union__find_new_size(struct tag *tag, struct cu *cu);
|
|
|
|
|
2008-01-12 16:14:40 +01:00
|
|
|
static void class__resize_LP(struct tag *tag, struct cu *cu)
|
|
|
|
{
|
|
|
|
struct tag *tag_pos;
|
2012-08-17 23:47:15 +02:00
|
|
|
struct class *class = tag__class(tag);
|
2008-01-12 16:14:40 +01:00
|
|
|
size_t word_size_diff;
|
2012-08-17 23:47:15 +02:00
|
|
|
size_t orig_size = class->type.size;
|
2008-01-12 16:14:40 +01:00
|
|
|
|
2008-01-12 18:25:12 +01:00
|
|
|
if (tag__type(tag)->resized)
|
|
|
|
return;
|
|
|
|
|
|
|
|
tag__type(tag)->resized = 1;
|
|
|
|
|
2008-01-12 16:14:40 +01:00
|
|
|
if (original_word_size > word_size)
|
|
|
|
word_size_diff = original_word_size - word_size;
|
|
|
|
else
|
|
|
|
word_size_diff = word_size - original_word_size;
|
|
|
|
|
|
|
|
type__for_each_tag(tag__type(tag), tag_pos) {
|
|
|
|
struct tag *type;
|
|
|
|
size_t diff = 0;
|
2008-01-12 23:06:46 +01:00
|
|
|
size_t array_multiplier = 1;
|
2008-01-12 16:14:40 +01:00
|
|
|
|
|
|
|
/* we want only data members, i.e. with byte_offset attr */
|
|
|
|
if (tag_pos->tag != DW_TAG_member &&
|
|
|
|
tag_pos->tag != DW_TAG_inheritance)
|
|
|
|
continue;
|
|
|
|
|
2009-03-18 16:17:07 +01:00
|
|
|
type = cu__type(cu, tag_pos->type);
|
2008-04-20 23:56:36 +02:00
|
|
|
tag__assert_search_result(type);
|
2008-01-12 23:06:46 +01:00
|
|
|
if (type->tag == DW_TAG_array_type) {
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < tag__array_type(type)->dimensions; ++i)
|
|
|
|
array_multiplier *= tag__array_type(type)->nr_entries[i];
|
|
|
|
|
2009-03-18 16:17:07 +01:00
|
|
|
type = cu__type(cu, type->type);
|
2008-04-20 23:56:36 +02:00
|
|
|
tag__assert_search_result(type);
|
2008-01-12 23:06:46 +01:00
|
|
|
}
|
|
|
|
|
2008-09-30 19:21:03 +02:00
|
|
|
if (tag__is_typedef(type)) {
|
2008-01-12 22:21:46 +01:00
|
|
|
type = tag__follow_typedef(type, cu);
|
2008-04-20 23:56:36 +02:00
|
|
|
tag__assert_search_result(type);
|
|
|
|
}
|
2008-01-12 23:06:46 +01:00
|
|
|
|
2008-01-12 16:14:40 +01:00
|
|
|
switch (type->tag) {
|
|
|
|
case DW_TAG_base_type: {
|
|
|
|
struct base_type *bt = tag__base_type(type);
|
2009-04-02 21:46:37 +02:00
|
|
|
char bf[64];
|
2009-04-02 22:54:43 +02:00
|
|
|
const char *name = base_type__name(bt, cu, bf,
|
|
|
|
sizeof(bf));
|
2009-04-02 21:46:37 +02:00
|
|
|
if (strcmp(name, "long int") != 0 &&
|
|
|
|
strcmp(name, "long unsigned int") != 0)
|
2008-01-12 16:14:40 +01:00
|
|
|
break;
|
|
|
|
/* fallthru */
|
|
|
|
}
|
|
|
|
case DW_TAG_pointer_type:
|
|
|
|
diff = word_size_diff;
|
|
|
|
break;
|
|
|
|
case DW_TAG_structure_type:
|
|
|
|
case DW_TAG_union_type:
|
2008-09-30 19:43:22 +02:00
|
|
|
if (tag__is_union(type))
|
2008-01-12 18:25:12 +01:00
|
|
|
union__find_new_size(type, cu);
|
|
|
|
else
|
|
|
|
class__resize_LP(type, cu);
|
2008-01-12 16:14:40 +01:00
|
|
|
diff = tag__type(type)->size_diff;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-01-12 23:06:46 +01:00
|
|
|
diff *= array_multiplier;
|
|
|
|
|
2008-01-12 16:14:40 +01:00
|
|
|
if (diff != 0) {
|
|
|
|
struct class_member *m = tag__class_member(tag_pos);
|
|
|
|
if (original_word_size > word_size) {
|
2012-08-17 23:47:15 +02:00
|
|
|
class->type.size -= diff;
|
|
|
|
class__subtract_offsets_from(class, m, diff);
|
2008-01-12 16:14:40 +01:00
|
|
|
} else {
|
2012-08-17 23:47:15 +02:00
|
|
|
class->type.size += diff;
|
|
|
|
class__add_offsets_from(class, m, diff);
|
2008-01-12 16:14:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (original_word_size > word_size)
|
2012-08-17 23:47:15 +02:00
|
|
|
tag__type(tag)->size_diff = orig_size - class->type.size;
|
2008-01-12 16:14:40 +01:00
|
|
|
else
|
2012-08-17 23:47:15 +02:00
|
|
|
tag__type(tag)->size_diff = class->type.size - orig_size;
|
2008-01-12 16:14:40 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
class__find_holes(class);
|
|
|
|
class__fixup_alignment(class, cu);
|
2008-01-12 16:14:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void union__find_new_size(struct tag *tag, struct cu *cu)
|
|
|
|
{
|
|
|
|
struct tag *tag_pos;
|
2012-08-17 23:47:15 +02:00
|
|
|
struct type *type = tag__type(tag);
|
2008-01-12 16:14:40 +01:00
|
|
|
size_t max_size = 0;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
if (type->resized)
|
2008-01-12 18:25:12 +01:00
|
|
|
return;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
type->resized = 1;
|
2008-01-12 18:25:12 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
type__for_each_tag(type, tag_pos) {
|
2008-01-12 16:14:40 +01:00
|
|
|
struct tag *type;
|
|
|
|
size_t size;
|
|
|
|
|
|
|
|
/* we want only data members, i.e. with byte_offset attr */
|
|
|
|
if (tag_pos->tag != DW_TAG_member &&
|
|
|
|
tag_pos->tag != DW_TAG_inheritance)
|
|
|
|
continue;
|
|
|
|
|
2009-03-18 16:17:07 +01:00
|
|
|
type = cu__type(cu, tag_pos->type);
|
2008-04-20 23:56:36 +02:00
|
|
|
tag__assert_search_result(type);
|
2008-09-30 19:21:03 +02:00
|
|
|
if (tag__is_typedef(type))
|
2008-01-12 22:40:10 +01:00
|
|
|
type = tag__follow_typedef(type, cu);
|
2008-01-12 18:25:12 +01:00
|
|
|
|
2008-09-30 19:43:22 +02:00
|
|
|
if (tag__is_union(type))
|
2008-01-12 18:25:12 +01:00
|
|
|
union__find_new_size(type, cu);
|
2008-09-30 19:43:22 +02:00
|
|
|
else if (tag__is_struct(type))
|
2008-01-12 18:25:12 +01:00
|
|
|
class__resize_LP(type, cu);
|
|
|
|
|
2008-01-12 16:14:40 +01:00
|
|
|
size = tag__size(type, cu);
|
|
|
|
if (size > max_size)
|
|
|
|
max_size = size;
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
if (max_size > type->size)
|
|
|
|
type->size_diff = max_size - type->size;
|
2008-01-12 16:14:40 +01:00
|
|
|
else
|
2012-08-17 23:47:15 +02:00
|
|
|
type->size_diff = type->size - max_size;
|
2008-01-12 16:14:40 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
type->size = max_size;
|
2008-01-12 16:14:40 +01:00
|
|
|
}
|
|
|
|
|
2009-04-01 15:58:25 +02:00
|
|
|
static void tag__fixup_word_size(struct tag *tag, struct cu *cu)
|
2008-01-12 16:14:40 +01:00
|
|
|
{
|
2008-09-30 19:43:22 +02:00
|
|
|
if (tag__is_struct(tag) || tag__is_union(tag)) {
|
2008-01-12 16:14:40 +01:00
|
|
|
struct tag *pos;
|
|
|
|
|
|
|
|
namespace__for_each_tag(tag__namespace(tag), pos)
|
2009-04-01 15:58:25 +02:00
|
|
|
tag__fixup_word_size(pos, cu);
|
2008-01-12 16:14:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
switch (tag->tag) {
|
|
|
|
case DW_TAG_base_type: {
|
|
|
|
struct base_type *bt = tag__base_type(tag);
|
|
|
|
|
2008-02-01 22:53:47 +01:00
|
|
|
/*
|
|
|
|
* This shouldn't happen, but at least on a tcp_ipv6.c
|
|
|
|
* built with GNU C 4.3.0 20080130 (Red Hat 4.3.0-0.7),
|
|
|
|
* one was found, so just bail out.
|
|
|
|
*/
|
2008-10-02 19:34:42 +02:00
|
|
|
if (!bt->name)
|
2009-04-01 15:58:25 +02:00
|
|
|
return;
|
2009-04-02 21:46:37 +02:00
|
|
|
char bf[64];
|
2009-04-02 22:54:43 +02:00
|
|
|
const char *name = base_type__name(bt, cu, bf, sizeof(bf));
|
2008-02-01 22:53:47 +01:00
|
|
|
|
2009-04-02 21:46:37 +02:00
|
|
|
if (strcmp(name, "long int") == 0 ||
|
|
|
|
strcmp(name, "long unsigned int") == 0)
|
2008-03-04 22:38:21 +01:00
|
|
|
bt->bit_size = word_size * 8;
|
2008-01-12 16:14:40 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case DW_TAG_structure_type:
|
|
|
|
class__resize_LP(tag, cu);
|
|
|
|
break;
|
|
|
|
case DW_TAG_union_type:
|
|
|
|
union__find_new_size(tag, cu);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-04-01 15:58:25 +02:00
|
|
|
return;
|
2008-01-12 16:14:40 +01:00
|
|
|
}
|
|
|
|
|
2009-03-13 19:05:19 +01:00
|
|
|
static void cu_fixup_word_size_iterator(struct cu *cu)
|
2008-01-12 16:14:40 +01:00
|
|
|
{
|
|
|
|
original_word_size = cu->addr_size;
|
|
|
|
cu->addr_size = word_size;
|
2009-04-01 15:58:25 +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;
|
2009-04-01 15:58:25 +02:00
|
|
|
struct tag *pos;
|
|
|
|
cu__for_each_type(cu, id, pos)
|
|
|
|
tag__fixup_word_size(pos, cu);
|
2007-01-13 16:59:32 +01:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void cu__account_nr_methods(struct cu *cu)
|
2007-01-13 16:59:32 +01:00
|
|
|
{
|
2009-03-13 19:05:19 +01:00
|
|
|
struct function *pos_function;
|
2007-01-13 16:59:32 +01:00
|
|
|
struct structure *str;
|
2009-03-13 19:05:19 +01:00
|
|
|
uint32_t id;
|
2007-01-13 16:59:32 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
cu__for_each_function(cu, id, pos_function) {
|
2009-03-13 19:05:19 +01:00
|
|
|
struct class_member *pos;
|
2020-01-08 15:52:37 +01:00
|
|
|
|
2020-01-14 18:01:30 +01:00
|
|
|
function__for_each_parameter(pos_function, cu, pos) {
|
2012-08-17 23:47:15 +02:00
|
|
|
struct tag *type = cu__type(cu, pos->tag.type);
|
2007-01-13 16:59:32 +01:00
|
|
|
|
2019-04-05 20:21:55 +02:00
|
|
|
if (type == NULL || !tag__is_pointer(type))
|
2009-03-13 19:05:19 +01:00
|
|
|
continue;
|
2007-01-13 16:59:32 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
type = cu__type(cu, type->type);
|
2009-03-13 19:05:19 +01:00
|
|
|
if (type == NULL || !tag__is_struct(type))
|
|
|
|
continue;
|
2007-01-13 16:59:32 +01:00
|
|
|
|
2009-03-13 19:05:19 +01:00
|
|
|
struct type *ctype = tag__type(type);
|
|
|
|
if (ctype->namespace.name == 0)
|
|
|
|
continue;
|
2007-01-13 16:59:32 +01:00
|
|
|
|
2009-06-22 23:40:39 +02:00
|
|
|
struct class *class = tag__class(type);
|
2009-03-13 19:05:19 +01:00
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
if (!class__filter(class, cu, 0))
|
2009-06-22 23:40:39 +02:00
|
|
|
continue;
|
2009-03-14 17:50:36 +01:00
|
|
|
|
2009-06-22 23:40:39 +02:00
|
|
|
bool existing_entry;
|
2012-08-17 23:47:15 +02:00
|
|
|
str = structures__add(class, cu, &existing_entry);
|
2009-06-22 23:40:39 +02:00
|
|
|
if (str == NULL) {
|
|
|
|
fprintf(stderr, "pahole: insufficient memory "
|
|
|
|
"for processing %s, skipping it...\n",
|
2012-08-17 23:47:15 +02:00
|
|
|
cu->name);
|
2009-06-22 23:40:39 +02:00
|
|
|
return;
|
2009-03-13 19:05:19 +01:00
|
|
|
}
|
2009-06-22 23:40:39 +02:00
|
|
|
|
|
|
|
if (!existing_entry)
|
|
|
|
class__find_holes(class);
|
2007-01-13 16:59:32 +01:00
|
|
|
++str->nr_methods;
|
2009-03-13 19:05:19 +01:00
|
|
|
}
|
2007-01-13 16:59:32 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-05-11 00:11:51 +02:00
|
|
|
static char tab[128];
|
|
|
|
|
2020-01-15 16:16:49 +01:00
|
|
|
static void print_structs_with_pointer_to(struct cu *cu, uint32_t type)
|
2007-11-16 21:18:08 +01:00
|
|
|
{
|
2009-03-13 19:05:19 +01:00
|
|
|
struct class *pos;
|
|
|
|
struct class_member *pos_member;
|
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-11-16 21:18:08 +01:00
|
|
|
|
2020-01-15 16:00:05 +01:00
|
|
|
cu__for_each_struct_or_union(cu, id, pos) {
|
2009-06-22 23:40:39 +02:00
|
|
|
bool looked = false;
|
|
|
|
struct structure *str;
|
|
|
|
|
2009-03-13 19:05:19 +01:00
|
|
|
if (pos->type.namespace.name == 0)
|
|
|
|
continue;
|
|
|
|
|
2020-01-15 16:16:49 +01:00
|
|
|
if (!class__filter(pos, cu, id))
|
|
|
|
continue;
|
|
|
|
|
2009-03-13 19:05:19 +01:00
|
|
|
type__for_each_member(&pos->type, pos_member) {
|
2009-03-18 16:17:07 +01:00
|
|
|
struct tag *ctype = cu__type(cu, pos_member->tag.type);
|
2007-11-16 21:18:08 +01:00
|
|
|
|
2008-04-20 23:56:36 +02:00
|
|
|
tag__assert_search_result(ctype);
|
2019-04-05 20:28:55 +02:00
|
|
|
if (!tag__is_pointer_to(ctype, type))
|
2009-03-13 19:05:19 +01:00
|
|
|
continue;
|
|
|
|
|
2009-06-22 23:40:39 +02:00
|
|
|
if (!looked) {
|
|
|
|
bool existing_entry;
|
2009-03-13 19:05:19 +01:00
|
|
|
|
2009-06-22 23:40:39 +02:00
|
|
|
str = structures__add(pos, cu, &existing_entry);
|
|
|
|
if (str == NULL) {
|
|
|
|
fprintf(stderr, "pahole: insufficient memory for "
|
|
|
|
"processing %s, skipping it...\n",
|
|
|
|
cu->name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* We already printed this struct in another CU
|
|
|
|
*/
|
|
|
|
if (existing_entry)
|
|
|
|
break;
|
|
|
|
looked = true;
|
2009-03-13 19:05:19 +01:00
|
|
|
}
|
2009-06-19 05:42:42 +02:00
|
|
|
printf("%s: %s\n", str->name,
|
2009-04-02 22:54:43 +02:00
|
|
|
class_member__name(pos_member, cu));
|
2007-11-16 21:18:08 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-15 16:16:49 +01:00
|
|
|
static void print_containers(struct cu *cu, uint32_t type, int ident)
|
2007-05-10 20:28:00 +02:00
|
|
|
{
|
2009-03-13 19:05:19 +01:00
|
|
|
struct class *pos;
|
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-05-10 20:28:00 +02:00
|
|
|
|
2020-01-15 15:54:31 +01:00
|
|
|
cu__for_each_struct_or_union(cu, id, pos) {
|
2009-03-13 19:05:19 +01:00
|
|
|
if (pos->type.namespace.name == 0)
|
|
|
|
continue;
|
2007-05-10 20:28:00 +02:00
|
|
|
|
2020-01-15 16:16:49 +01:00
|
|
|
if (!class__filter(pos, cu, id))
|
|
|
|
continue;
|
|
|
|
|
2009-03-13 19:05:19 +01:00
|
|
|
const uint32_t n = type__nr_members_of_type(&pos->type, type);
|
|
|
|
if (n == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (ident == 0) {
|
2009-06-22 23:40:39 +02:00
|
|
|
bool existing_entry;
|
|
|
|
struct structure *str = structures__add(pos, cu, &existing_entry);
|
|
|
|
if (str == NULL) {
|
2009-03-13 19:05:19 +01:00
|
|
|
fprintf(stderr, "pahole: insufficient memory for "
|
|
|
|
"processing %s, skipping it...\n",
|
|
|
|
cu->name);
|
|
|
|
return;
|
|
|
|
}
|
2009-06-22 23:40:39 +02:00
|
|
|
/*
|
|
|
|
* We already printed this struct in another CU
|
|
|
|
*/
|
|
|
|
if (existing_entry)
|
|
|
|
break;
|
2007-05-10 20:28:00 +02:00
|
|
|
}
|
2009-03-13 19:05:19 +01:00
|
|
|
|
2009-04-02 22:54:43 +02:00
|
|
|
printf("%.*s%s", ident * 2, tab, class__name(pos, cu));
|
2009-03-13 19:05:19 +01:00
|
|
|
if (global_verbose)
|
|
|
|
printf(": %u", n);
|
|
|
|
putchar('\n');
|
|
|
|
if (recursive)
|
|
|
|
print_containers(cu, id, ident + 1);
|
2007-05-10 20:28:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-13 13:57:23 +01:00
|
|
|
/* Name and version of program. */
|
|
|
|
ARGP_PROGRAM_VERSION_HOOK_DEF = dwarves_print_version;
|
|
|
|
|
2009-03-20 17:54:04 +01:00
|
|
|
#define ARGP_flat_arrays 300
|
|
|
|
#define ARGP_show_private_classes 301
|
|
|
|
#define ARGP_fixup_silly_bitfields 302
|
2009-08-24 20:13:58 +02:00
|
|
|
#define ARGP_first_obj_only 303
|
2009-08-24 22:22:43 +02:00
|
|
|
#define ARGP_classes_as_structs 304
|
2009-10-20 17:59:12 +02:00
|
|
|
#define ARGP_hex_fmt 305
|
2019-04-03 18:08:02 +02:00
|
|
|
#define ARGP_suppress_aligned_attribute 306
|
2019-04-15 19:34:25 +02:00
|
|
|
#define ARGP_suppress_force_paddings 307
|
2019-04-15 20:01:53 +02:00
|
|
|
#define ARGP_suppress_packed 308
|
pahole: Introduce --unions to consider just unions
Most filters can be used together with it, for instance to see the
biggest unions in the kernel:
$ pahole --unions --sizes | sort -k2 -nr | head
thread_union 16384 0
swap_header 4096 0
fpregs_state 4096 0
autofs_v5_packet_union 304 0
autofs_packet_union 272 0
pptp_ctrl_union 208 0
acpi_parse_object 200 0
acpi_descriptor 200 0
bpf_attr 120 0
phy_configure_opts 112 0
$
Or just some unions that have some specific prefix:
$ pahole --unions --prefix tcp
union tcp_md5_addr {
struct in_addr a4; /* 0 4 */
struct in6_addr a6; /* 0 16 */
};
union tcp_word_hdr {
struct tcphdr hdr; /* 0 20 */
__be32 words[5]; /* 0 20 */
};
union tcp_cc_info {
struct tcpvegas_info vegas; /* 0 16 */
struct tcp_dctcp_info dctcp; /* 0 16 */
struct tcp_bbr_info bbr; /* 0 20 */
};
$
What are the biggest unions in terms of number of members?
$ pahole --unions --nr_members | sort -k2 -nr | head
security_list_options 218
aml_resource 36
acpi_resource_data 29
acpi_operand_object 26
iwreq_data 18
sctp_params 15
ib_flow_spec 14
ethtool_flow_union 14
pptp_ctrl_union 13
bpf_attr 12
$
If you want to script most of the queries can change the separator:
$ pahole --unions --nr_members -t, | sort -t, -k2 -nr | head
security_list_options,218
aml_resource,36
acpi_resource_data,29
acpi_operand_object,26
iwreq_data,18
sctp_params,15
ib_flow_spec,14
ethtool_flow_union,14
pptp_ctrl_union,13
bpf_attr,12
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-01-15 15:35:25 +01:00
|
|
|
#define ARGP_just_unions 309
|
2020-01-15 16:41:28 +01:00
|
|
|
#define ARGP_just_structs 310
|
2009-03-20 14:29:50 +01:00
|
|
|
|
2007-03-30 15:07:01 +02:00
|
|
|
static const struct argp_option pahole__options[] = {
|
|
|
|
{
|
|
|
|
.name = "bit_holes",
|
|
|
|
.key = 'B',
|
|
|
|
.arg = "NR_HOLES",
|
|
|
|
.doc = "Show only structs at least NR_HOLES bit holes"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "cacheline_size",
|
|
|
|
.key = 'c',
|
|
|
|
.arg = "SIZE",
|
|
|
|
.doc = "set cacheline size to SIZE"
|
|
|
|
},
|
2007-04-24 21:09:34 +02:00
|
|
|
{
|
|
|
|
.name = "class_name",
|
|
|
|
.key = 'C',
|
|
|
|
.arg = "CLASS_NAME",
|
|
|
|
.doc = "Show just this class"
|
|
|
|
},
|
2007-11-16 21:18:08 +01:00
|
|
|
{
|
|
|
|
.name = "find_pointers_to",
|
|
|
|
.key = 'f',
|
|
|
|
.arg = "CLASS_NAME",
|
|
|
|
.doc = "Find pointers to CLASS_NAME"
|
|
|
|
},
|
2009-03-19 16:19:37 +01:00
|
|
|
{
|
|
|
|
.name = "format_path",
|
|
|
|
.key = 'F',
|
|
|
|
.arg = "FORMAT_LIST",
|
|
|
|
.doc = "List of debugging formats to try"
|
|
|
|
},
|
2007-05-10 20:28:00 +02:00
|
|
|
{
|
|
|
|
.name = "contains",
|
|
|
|
.key = 'i',
|
|
|
|
.arg = "CLASS_NAME",
|
|
|
|
.doc = "Show classes that contains CLASS_NAME"
|
|
|
|
},
|
2007-05-30 16:28:16 +02:00
|
|
|
{
|
|
|
|
.name = "show_decl_info",
|
|
|
|
.key = 'I',
|
|
|
|
.doc = "Show the file and line number where the tags were defined"
|
|
|
|
},
|
2007-03-30 15:07:01 +02:00
|
|
|
{
|
|
|
|
.name = "holes",
|
|
|
|
.key = 'H',
|
|
|
|
.arg = "NR_HOLES",
|
[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
|
|
|
.doc = "show only structs with at least NR_HOLES holes",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "hole_size_ge",
|
|
|
|
.key = 'z',
|
|
|
|
.arg = "HOLE_SIZE",
|
|
|
|
.doc = "show only structs with at least one hole greater "
|
|
|
|
"or equal to HOLE_SIZE",
|
2007-03-30 15:07:01 +02:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "packable",
|
[PAHOLE]: Use cus__loadfl, i.e. libdwfl
Now we have:
[acme@filo pahole]$ pahole --help
Usage: pahole [OPTION...] [FILE] {[CLASS]}
-a, --anon_include include anonymous classes
-A, --nested_anon_include include nested (inside other structs) anonymous
classes
-B, --bit_holes=NR_HOLES Show only structs at least NR_HOLES bit holes
-c, --cacheline_size=SIZE set cacheline size to SIZE
-D, --decl_exclude=PREFIX exclude classes declared in files with PREFIX
-E, --expand_types expand class members
-H, --holes=NR_HOLES show only structs at least NR_HOLES holes
-m, --nr_methods show number of methods
-n, --nr_members show number of members
-N, --class_name_len show size of classes
-P, --packable show only structs that has holes that can be
packed
-R, --reorganize reorg struct trying to kill holes
-s, --sizes show size of classes
-S, --show_reorg_steps show the struct layout at each reorganization step
-t, --nr_definitions show how many times struct was defined
-V, --verbose be verbose
-x, --exclude=PREFIX exclude PREFIXed classes
-X, --cu_exclude=PREFIX exclude PREFIXed compilation units
Input Selection:
--debuginfo-path=PATH Search path for separate debuginfo files
-e, --executable=FILE Find addresses in FILE
-k, --kernel Find addresses in the running kernel
-K, --offline-kernel[=RELEASE] Kernel with all modules
-M, --linux-process-map=FILE Find addresses in files mapped as read from
FILE in Linux /proc/PID/maps format
-p, --pid=PID Find addresses in files mapped into process PID
-?, --help Give this help list
--usage Give a short usage message
Mandatory or optional arguments to long options are also mandatory or optional
for any corresponding short options.
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-03-30 18:25:51 +02:00
|
|
|
.key = 'P',
|
2007-03-30 15:07:01 +02:00
|
|
|
.doc = "show only structs that has holes that can be packed",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "expand_types",
|
[PAHOLE]: Use cus__loadfl, i.e. libdwfl
Now we have:
[acme@filo pahole]$ pahole --help
Usage: pahole [OPTION...] [FILE] {[CLASS]}
-a, --anon_include include anonymous classes
-A, --nested_anon_include include nested (inside other structs) anonymous
classes
-B, --bit_holes=NR_HOLES Show only structs at least NR_HOLES bit holes
-c, --cacheline_size=SIZE set cacheline size to SIZE
-D, --decl_exclude=PREFIX exclude classes declared in files with PREFIX
-E, --expand_types expand class members
-H, --holes=NR_HOLES show only structs at least NR_HOLES holes
-m, --nr_methods show number of methods
-n, --nr_members show number of members
-N, --class_name_len show size of classes
-P, --packable show only structs that has holes that can be
packed
-R, --reorganize reorg struct trying to kill holes
-s, --sizes show size of classes
-S, --show_reorg_steps show the struct layout at each reorganization step
-t, --nr_definitions show how many times struct was defined
-V, --verbose be verbose
-x, --exclude=PREFIX exclude PREFIXed classes
-X, --cu_exclude=PREFIX exclude PREFIXed compilation units
Input Selection:
--debuginfo-path=PATH Search path for separate debuginfo files
-e, --executable=FILE Find addresses in FILE
-k, --kernel Find addresses in the running kernel
-K, --offline-kernel[=RELEASE] Kernel with all modules
-M, --linux-process-map=FILE Find addresses in files mapped as read from
FILE in Linux /proc/PID/maps format
-p, --pid=PID Find addresses in files mapped into process PID
-?, --help Give this help list
--usage Give a short usage message
Mandatory or optional arguments to long options are also mandatory or optional
for any corresponding short options.
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-03-30 18:25:51 +02:00
|
|
|
.key = 'E',
|
2007-03-30 15:07:01 +02:00
|
|
|
.doc = "expand class members",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "nr_members",
|
|
|
|
.key = 'n',
|
|
|
|
.doc = "show number of members",
|
|
|
|
},
|
2007-05-02 21:14:20 +02:00
|
|
|
{
|
|
|
|
.name = "rel_offset",
|
|
|
|
.key = 'r',
|
|
|
|
.doc = "show relative offsets of members in inner structs"
|
|
|
|
},
|
2007-05-11 00:11:51 +02:00
|
|
|
{
|
|
|
|
.name = "recursive",
|
|
|
|
.key = 'd',
|
|
|
|
.doc = "recursive mode, affects several other flags",
|
|
|
|
},
|
2007-03-30 15:07:01 +02:00
|
|
|
{
|
|
|
|
.name = "reorganize",
|
[PAHOLE]: Use cus__loadfl, i.e. libdwfl
Now we have:
[acme@filo pahole]$ pahole --help
Usage: pahole [OPTION...] [FILE] {[CLASS]}
-a, --anon_include include anonymous classes
-A, --nested_anon_include include nested (inside other structs) anonymous
classes
-B, --bit_holes=NR_HOLES Show only structs at least NR_HOLES bit holes
-c, --cacheline_size=SIZE set cacheline size to SIZE
-D, --decl_exclude=PREFIX exclude classes declared in files with PREFIX
-E, --expand_types expand class members
-H, --holes=NR_HOLES show only structs at least NR_HOLES holes
-m, --nr_methods show number of methods
-n, --nr_members show number of members
-N, --class_name_len show size of classes
-P, --packable show only structs that has holes that can be
packed
-R, --reorganize reorg struct trying to kill holes
-s, --sizes show size of classes
-S, --show_reorg_steps show the struct layout at each reorganization step
-t, --nr_definitions show how many times struct was defined
-V, --verbose be verbose
-x, --exclude=PREFIX exclude PREFIXed classes
-X, --cu_exclude=PREFIX exclude PREFIXed compilation units
Input Selection:
--debuginfo-path=PATH Search path for separate debuginfo files
-e, --executable=FILE Find addresses in FILE
-k, --kernel Find addresses in the running kernel
-K, --offline-kernel[=RELEASE] Kernel with all modules
-M, --linux-process-map=FILE Find addresses in files mapped as read from
FILE in Linux /proc/PID/maps format
-p, --pid=PID Find addresses in files mapped into process PID
-?, --help Give this help list
--usage Give a short usage message
Mandatory or optional arguments to long options are also mandatory or optional
for any corresponding short options.
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-03-30 18:25:51 +02:00
|
|
|
.key = 'R',
|
2007-03-30 15:07:01 +02:00
|
|
|
.doc = "reorg struct trying to kill holes",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "show_reorg_steps",
|
|
|
|
.key = 'S',
|
|
|
|
.doc = "show the struct layout at each reorganization step",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "class_name_len",
|
|
|
|
.key = 'N',
|
|
|
|
.doc = "show size of classes",
|
|
|
|
},
|
2008-01-13 18:20:06 +01:00
|
|
|
{
|
|
|
|
.name = "show_first_biggest_size_base_type_member",
|
|
|
|
.key = 'l',
|
|
|
|
.doc = "show first biggest size base_type member",
|
|
|
|
},
|
2007-03-30 15:07:01 +02:00
|
|
|
{
|
|
|
|
.name = "nr_methods",
|
|
|
|
.key = 'm',
|
|
|
|
.doc = "show number of methods",
|
|
|
|
},
|
2007-05-30 16:36:54 +02:00
|
|
|
{
|
|
|
|
.name = "show_only_data_members",
|
|
|
|
.key = 'M',
|
|
|
|
.doc = "show only the members that use space in the class layout",
|
|
|
|
},
|
2007-07-05 01:36:28 +02:00
|
|
|
{
|
|
|
|
.name = "expand_pointers",
|
|
|
|
.key = 'p',
|
|
|
|
.doc = "expand class pointer members",
|
|
|
|
},
|
2007-03-30 15:07:01 +02:00
|
|
|
{
|
|
|
|
.name = "sizes",
|
|
|
|
.key = 's',
|
|
|
|
.doc = "show size of classes",
|
|
|
|
},
|
|
|
|
{
|
[PAHOLE]: Introduce --separator/-t
[acme@filo pahole]$ pahole -t, --packable examples/ipv6.ko.debug.x86-64 | sort -t, -k2 -n | tail
inode,1008,1000,8
hh_cache,256,128,128
proto,8512,8504,8
super_block,1184,1168,16
task_struct,3776,3704,72
module,8832,8800,32
pglist_data,10752,10744,8
zone,1536,1352,184
net_device,1664,1208,456
softnet_data,1920,1792,128
[acme@filo pahole]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-05-23 21:26:39 +02:00
|
|
|
.name = "separator",
|
2007-03-30 15:07:01 +02:00
|
|
|
.key = 't',
|
[PAHOLE]: Introduce --separator/-t
[acme@filo pahole]$ pahole -t, --packable examples/ipv6.ko.debug.x86-64 | sort -t, -k2 -n | tail
inode,1008,1000,8
hh_cache,256,128,128
proto,8512,8504,8
super_block,1184,1168,16
task_struct,3776,3704,72
module,8832,8800,32
pglist_data,10752,10744,8
zone,1536,1352,184
net_device,1664,1208,456
softnet_data,1920,1792,128
[acme@filo pahole]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-05-23 21:26:39 +02:00
|
|
|
.arg = "SEP",
|
|
|
|
.doc = "use SEP as the field separator",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "nr_definitions",
|
|
|
|
.key = 'T',
|
2007-03-30 15:07:01 +02:00
|
|
|
.doc = "show how many times struct was defined",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "decl_exclude",
|
|
|
|
.key = 'D',
|
|
|
|
.arg = "PREFIX",
|
|
|
|
.doc = "exclude classes declared in files with PREFIX",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "exclude",
|
|
|
|
.key = 'x',
|
|
|
|
.arg = "PREFIX",
|
|
|
|
.doc = "exclude PREFIXed classes",
|
|
|
|
},
|
2008-04-21 17:41:44 +02:00
|
|
|
{
|
|
|
|
.name = "prefix_filter",
|
|
|
|
.key = 'y',
|
|
|
|
.arg = "PREFIX",
|
|
|
|
.doc = "include PREFIXed classes",
|
|
|
|
},
|
2007-03-30 15:07:01 +02:00
|
|
|
{
|
|
|
|
.name = "cu_exclude",
|
|
|
|
.key = 'X',
|
|
|
|
.arg = "PREFIX",
|
|
|
|
.doc = "exclude PREFIXed compilation units",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "anon_include",
|
|
|
|
.key = 'a',
|
|
|
|
.doc = "include anonymous classes",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "nested_anon_include",
|
|
|
|
.key = 'A',
|
|
|
|
.doc = "include nested (inside other structs) anonymous classes",
|
|
|
|
},
|
2007-06-22 21:43:29 +02:00
|
|
|
{
|
|
|
|
.name = "quiet",
|
|
|
|
.key = 'q',
|
|
|
|
.doc = "be quieter",
|
|
|
|
},
|
2008-02-07 12:16:22 +01:00
|
|
|
{
|
|
|
|
.name = "defined_in",
|
|
|
|
.key = 'u',
|
|
|
|
.doc = "show CUs where CLASS_NAME (-C) is defined",
|
|
|
|
},
|
2007-03-30 15:07:01 +02:00
|
|
|
{
|
|
|
|
.name = "verbose",
|
|
|
|
.key = 'V',
|
|
|
|
.doc = "be verbose",
|
|
|
|
},
|
2008-01-12 16:14:40 +01:00
|
|
|
{
|
|
|
|
.name = "word_size",
|
|
|
|
.key = 'w',
|
|
|
|
.arg = "WORD_SIZE",
|
|
|
|
.doc = "change the arch word size to WORD_SIZE"
|
|
|
|
},
|
2009-03-19 16:16:07 +01:00
|
|
|
{
|
|
|
|
.name = "ctf_encode",
|
|
|
|
.key = 'Z',
|
|
|
|
.doc = "Encode as CTF",
|
|
|
|
},
|
2009-03-20 14:29:50 +01:00
|
|
|
{
|
|
|
|
.name = "flat_arrays",
|
|
|
|
.key = ARGP_flat_arrays,
|
|
|
|
.doc = "Flat arrays",
|
|
|
|
},
|
2019-04-03 18:08:02 +02:00
|
|
|
{
|
|
|
|
.name = "suppress_aligned_attribute",
|
|
|
|
.key = ARGP_suppress_aligned_attribute,
|
|
|
|
.doc = "Suppress __attribute__((aligned(N))",
|
|
|
|
},
|
2019-04-15 19:34:25 +02:00
|
|
|
{
|
|
|
|
.name = "suppress_force_paddings",
|
|
|
|
.key = ARGP_suppress_force_paddings,
|
|
|
|
.doc = "Suppress int :N paddings at the end",
|
|
|
|
},
|
2019-04-15 20:01:53 +02:00
|
|
|
{
|
|
|
|
.name = "suppress_packed",
|
|
|
|
.key = ARGP_suppress_packed,
|
|
|
|
.doc = "Suppress output of inferred __attribute__((__packed__))",
|
|
|
|
},
|
2009-03-20 15:37:22 +01:00
|
|
|
{
|
|
|
|
.name = "show_private_classes",
|
|
|
|
.key = ARGP_show_private_classes,
|
|
|
|
.doc = "Show classes that are defined inside other classes or in functions",
|
|
|
|
},
|
2009-03-20 17:54:04 +01:00
|
|
|
{
|
|
|
|
.name = "fixup_silly_bitfields",
|
|
|
|
.key = ARGP_fixup_silly_bitfields,
|
|
|
|
.doc = "Fix silly bitfields such as int foo:32",
|
|
|
|
},
|
2009-08-24 20:13:58 +02:00
|
|
|
{
|
|
|
|
.name = "first_obj_only",
|
|
|
|
.key = ARGP_first_obj_only,
|
|
|
|
.doc = "Only process the first object file in the binary",
|
|
|
|
},
|
2009-08-24 22:22:43 +02:00
|
|
|
{
|
|
|
|
.name = "classes_as_structs",
|
|
|
|
.key = ARGP_classes_as_structs,
|
|
|
|
.doc = "Use 'struct' when printing classes",
|
|
|
|
},
|
2009-10-20 17:59:12 +02:00
|
|
|
{
|
|
|
|
.name = "hex",
|
|
|
|
.key = ARGP_hex_fmt,
|
|
|
|
.doc = "Print offsets and sizes in hexadecimal",
|
|
|
|
},
|
2018-03-06 01:53:50 +01:00
|
|
|
{
|
|
|
|
.name = "btf_encode",
|
|
|
|
.key = 'J',
|
|
|
|
.doc = "Encode as BTF",
|
|
|
|
},
|
2020-01-15 16:41:28 +01:00
|
|
|
{
|
|
|
|
.name = "structs",
|
|
|
|
.key = ARGP_just_structs,
|
|
|
|
.doc = "Show just structs",
|
|
|
|
},
|
pahole: Introduce --unions to consider just unions
Most filters can be used together with it, for instance to see the
biggest unions in the kernel:
$ pahole --unions --sizes | sort -k2 -nr | head
thread_union 16384 0
swap_header 4096 0
fpregs_state 4096 0
autofs_v5_packet_union 304 0
autofs_packet_union 272 0
pptp_ctrl_union 208 0
acpi_parse_object 200 0
acpi_descriptor 200 0
bpf_attr 120 0
phy_configure_opts 112 0
$
Or just some unions that have some specific prefix:
$ pahole --unions --prefix tcp
union tcp_md5_addr {
struct in_addr a4; /* 0 4 */
struct in6_addr a6; /* 0 16 */
};
union tcp_word_hdr {
struct tcphdr hdr; /* 0 20 */
__be32 words[5]; /* 0 20 */
};
union tcp_cc_info {
struct tcpvegas_info vegas; /* 0 16 */
struct tcp_dctcp_info dctcp; /* 0 16 */
struct tcp_bbr_info bbr; /* 0 20 */
};
$
What are the biggest unions in terms of number of members?
$ pahole --unions --nr_members | sort -k2 -nr | head
security_list_options 218
aml_resource 36
acpi_resource_data 29
acpi_operand_object 26
iwreq_data 18
sctp_params 15
ib_flow_spec 14
ethtool_flow_union 14
pptp_ctrl_union 13
bpf_attr 12
$
If you want to script most of the queries can change the separator:
$ pahole --unions --nr_members -t, | sort -t, -k2 -nr | head
security_list_options,218
aml_resource,36
acpi_resource_data,29
acpi_operand_object,26
iwreq_data,18
sctp_params,15
ib_flow_spec,14
ethtool_flow_union,14
pptp_ctrl_union,13
bpf_attr,12
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-01-15 15:35:25 +01:00
|
|
|
{
|
|
|
|
.name = "unions",
|
|
|
|
.key = ARGP_just_unions,
|
|
|
|
.doc = "Show just unions",
|
|
|
|
},
|
2007-03-30 15:07:01 +02:00
|
|
|
{
|
|
|
|
.name = NULL,
|
|
|
|
}
|
2006-11-02 17:47:37 +01:00
|
|
|
};
|
|
|
|
|
2007-03-30 15:07:01 +02:00
|
|
|
static error_t pahole__options_parser(int key, char *arg,
|
[PAHOLE]: Use cus__loadfl, i.e. libdwfl
Now we have:
[acme@filo pahole]$ pahole --help
Usage: pahole [OPTION...] [FILE] {[CLASS]}
-a, --anon_include include anonymous classes
-A, --nested_anon_include include nested (inside other structs) anonymous
classes
-B, --bit_holes=NR_HOLES Show only structs at least NR_HOLES bit holes
-c, --cacheline_size=SIZE set cacheline size to SIZE
-D, --decl_exclude=PREFIX exclude classes declared in files with PREFIX
-E, --expand_types expand class members
-H, --holes=NR_HOLES show only structs at least NR_HOLES holes
-m, --nr_methods show number of methods
-n, --nr_members show number of members
-N, --class_name_len show size of classes
-P, --packable show only structs that has holes that can be
packed
-R, --reorganize reorg struct trying to kill holes
-s, --sizes show size of classes
-S, --show_reorg_steps show the struct layout at each reorganization step
-t, --nr_definitions show how many times struct was defined
-V, --verbose be verbose
-x, --exclude=PREFIX exclude PREFIXed classes
-X, --cu_exclude=PREFIX exclude PREFIXed compilation units
Input Selection:
--debuginfo-path=PATH Search path for separate debuginfo files
-e, --executable=FILE Find addresses in FILE
-k, --kernel Find addresses in the running kernel
-K, --offline-kernel[=RELEASE] Kernel with all modules
-M, --linux-process-map=FILE Find addresses in files mapped as read from
FILE in Linux /proc/PID/maps format
-p, --pid=PID Find addresses in files mapped into process PID
-?, --help Give this help list
--usage Give a short usage message
Mandatory or optional arguments to long options are also mandatory or optional
for any corresponding short options.
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-03-30 18:25:51 +02:00
|
|
|
struct argp_state *state)
|
2006-11-02 17:47:37 +01:00
|
|
|
{
|
2007-03-30 15:07:01 +02:00
|
|
|
switch (key) {
|
2008-10-08 15:46:34 +02:00
|
|
|
case ARGP_KEY_INIT:
|
|
|
|
if (state->child_inputs != NULL)
|
|
|
|
state->child_inputs[0] = state->input;
|
|
|
|
break;
|
2007-11-16 19:01:26 +01:00
|
|
|
case 'A': class__include_nested_anonymous = 1; break;
|
|
|
|
case 'a': class__include_anonymous = 1; break;
|
|
|
|
case 'B': nr_bit_holes = atoi(arg); break;
|
2007-04-24 21:09:34 +02:00
|
|
|
case 'C': class_name = arg; break;
|
2007-11-16 19:01:26 +01:00
|
|
|
case 'c': cacheline_size = atoi(arg); break;
|
|
|
|
case 'D': decl_exclude_prefix = arg;
|
|
|
|
decl_exclude_prefix_len = strlen(decl_exclude_prefix);
|
2009-03-09 18:43:47 +01:00
|
|
|
conf_load.extra_dbg_info = 1; break;
|
2007-05-11 00:11:51 +02:00
|
|
|
case 'd': recursive = 1; break;
|
2007-11-16 19:01:26 +01:00
|
|
|
case 'E': conf.expand_types = 1; break;
|
2007-11-16 21:18:08 +01:00
|
|
|
case 'f': find_pointers_in_structs = 1;
|
|
|
|
class_name = arg; break;
|
2009-03-19 16:19:37 +01:00
|
|
|
case 'F': conf_load.format_path = arg; break;
|
2007-11-16 19:01:26 +01:00
|
|
|
case 'H': nr_holes = atoi(arg); break;
|
2009-03-09 18:43:47 +01:00
|
|
|
case 'I': conf.show_decl_info = 1;
|
|
|
|
conf_load.extra_dbg_info = 1; break;
|
2007-05-10 20:28:00 +02:00
|
|
|
case 'i': find_containers = 1;
|
|
|
|
class_name = arg; break;
|
btf: fix struct/union/fwd types with kind_flag
This patch fixed two issues with BTF. One is related to struct/union
bitfield encoding and the other is related to forward type.
Issue #1 and solution:
======================
Current btf encoding of bitfield follows what pahole generates.
For each bitfield, pahole will duplicate the type chain and
put the bitfield size at the final int or enum type.
Since the BTF enum type cannot encode bit size,
commit b18354f64cc2 ("btf: Generate correct struct bitfield
member types") workarounds the issue by generating
an int type whenever the enum bit size is not 32.
The above workaround is not ideal as we lost original type
in BTF. Another undesiable fact is the type duplication
as the pahole duplicates the type chain.
To fix this issue, this patch implemented a compatible
change for BTF struct type encoding:
. the bit 31 of type->info, previously reserved,
now is used to indicate whether bitfield_size is
encoded in btf_member or not.
. if bit 31 of struct_type->info is set,
btf_member->offset will encode like:
bit 0 - 23: bit offset
bit 24 - 31: bitfield size
if bit 31 is not set, the old behavior is preserved:
bit 0 - 31: bit offset
So if the struct contains a bit field, the maximum bit offset
will be reduced to (2^24 - 1) instead of MAX_UINT. The maximum
bitfield size will be 255 which is enough for today as maximum
bitfield in compiler can be 128 where int128 type is supported.
A new global, no_bitfield_type_recode, is introduced and which
will be set to true if BTF encoding is enabled. This global
will prevent pahole duplicating the bitfield types to avoid
type duplication in BTF.
Issue #2 and solution:
======================
Current forward type in BTF does not specify whether the original
type is struct or union. This will not work for type pretty print
and BTF-to-header-file conversion as struct/union must be specified.
To fix this issue, similar to issue #1, type->info bit 31
is used. If the bit is set, it is union type. Otherwise, it is
a struct type.
Examples:
=========
-bash-4.4$ cat t.c
struct s;
union u;
typedef int ___int;
enum A { A1, A2, A3 };
struct t {
int a[5];
___int b:4;
volatile enum A c:4;
struct s *p1;
union u *p2;
} g;
-bash-4.4$ gcc -c -O2 -g t.c
Without this patch:
$ pahole -JV t.o
[1] TYPEDEF ___int type_id=2
[2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
[3] ENUM A size=4 vlen=3
A1 val=0
A2 val=1
A3 val=2
[4] STRUCT t size=40 vlen=5
a type_id=5 bits_offset=0
b type_id=13 bits_offset=160
c type_id=15 bits_offset=164
p1 type_id=9 bits_offset=192
p2 type_id=11 bits_offset=256
[5] ARRAY (anon) type_id=2 index_type_id=2 nr_elems=5
[6] INT sizetype size=8 bit_offset=0 nr_bits=64 encoding=(none)
[7] VOLATILE (anon) type_id=3
[8] FWD s type_id=0
[9] PTR (anon) type_id=8
[10] FWD u type_id=0
[11] PTR (anon) type_id=10
[12] INT int size=1 bit_offset=0 nr_bits=4 encoding=(none)
[13] TYPEDEF ___int type_id=12
[14] INT (anon) size=1 bit_offset=0 nr_bits=4 encoding=SIGNED
[15] VOLATILE (anon) type_id=14
With this patch:
$ pahole -JV t.o
File t.o:
[1] TYPEDEF ___int type_id=2
[2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
[3] ENUM A size=4 vlen=3
A1 val=0
A2 val=1
A3 val=2
[4] STRUCT t kind_flag=1 size=40 vlen=5
a type_id=5 bitfield_size=0 bits_offset=0
b type_id=1 bitfield_size=4 bits_offset=160
c type_id=7 bitfield_size=4 bits_offset=164
p1 type_id=9 bitfield_size=0 bits_offset=192
p2 type_id=11 bitfield_size=0 bits_offset=256
[5] ARRAY (anon) type_id=2 index_type_id=2 nr_elems=5
[6] INT sizetype size=8 bit_offset=0 nr_bits=64 encoding=(none)
[7] VOLATILE (anon) type_id=3
[8] FWD s struct
[9] PTR (anon) type_id=8
[10] FWD u union
[11] PTR (anon) type_id=10
The fix removed the type duplication, preserved the enum type for the
bitfield, and have correct struct/union information for the forward
type.
Signed-off-by: Yonghong Song <yhs@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-18 23:09:41 +01:00
|
|
|
case 'J': btf_encode = 1;
|
|
|
|
no_bitfield_type_recode = true; break;
|
2008-01-13 18:20:06 +01:00
|
|
|
case 'l': conf.show_first_biggest_size_base_type_member = 1; break;
|
2007-11-16 19:01:26 +01:00
|
|
|
case 'M': conf.show_only_data_members = 1; break;
|
2009-03-13 19:05:19 +01:00
|
|
|
case 'm': stats_formatter = nr_methods_formatter; break;
|
2007-11-16 19:01:26 +01:00
|
|
|
case 'N': formatter = class_name_len_formatter; break;
|
|
|
|
case 'n': formatter = nr_members_formatter; break;
|
2009-03-09 18:43:47 +01:00
|
|
|
case 'P': show_packable = 1;
|
|
|
|
conf_load.extra_dbg_info = 1; break;
|
2007-07-05 01:36:28 +02:00
|
|
|
case 'p': conf.expand_pointers = 1; break;
|
2007-11-16 19:01:26 +01:00
|
|
|
case 'q': conf.emit_stats = 0;
|
|
|
|
conf.suppress_comments = 1;
|
|
|
|
conf.suppress_offset_comment = 1; break;
|
[PAHOLE]: Use cus__loadfl, i.e. libdwfl
Now we have:
[acme@filo pahole]$ pahole --help
Usage: pahole [OPTION...] [FILE] {[CLASS]}
-a, --anon_include include anonymous classes
-A, --nested_anon_include include nested (inside other structs) anonymous
classes
-B, --bit_holes=NR_HOLES Show only structs at least NR_HOLES bit holes
-c, --cacheline_size=SIZE set cacheline size to SIZE
-D, --decl_exclude=PREFIX exclude classes declared in files with PREFIX
-E, --expand_types expand class members
-H, --holes=NR_HOLES show only structs at least NR_HOLES holes
-m, --nr_methods show number of methods
-n, --nr_members show number of members
-N, --class_name_len show size of classes
-P, --packable show only structs that has holes that can be
packed
-R, --reorganize reorg struct trying to kill holes
-s, --sizes show size of classes
-S, --show_reorg_steps show the struct layout at each reorganization step
-t, --nr_definitions show how many times struct was defined
-V, --verbose be verbose
-x, --exclude=PREFIX exclude PREFIXed classes
-X, --cu_exclude=PREFIX exclude PREFIXed compilation units
Input Selection:
--debuginfo-path=PATH Search path for separate debuginfo files
-e, --executable=FILE Find addresses in FILE
-k, --kernel Find addresses in the running kernel
-K, --offline-kernel[=RELEASE] Kernel with all modules
-M, --linux-process-map=FILE Find addresses in files mapped as read from
FILE in Linux /proc/PID/maps format
-p, --pid=PID Find addresses in files mapped into process PID
-?, --help Give this help list
--usage Give a short usage message
Mandatory or optional arguments to long options are also mandatory or optional
for any corresponding short options.
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-03-30 18:25:51 +02:00
|
|
|
case 'R': reorganize = 1; break;
|
2007-11-16 19:01:26 +01:00
|
|
|
case 'r': conf.rel_offset = 1; break;
|
2007-03-30 15:07:01 +02:00
|
|
|
case 'S': show_reorg_steps = 1; break;
|
|
|
|
case 's': formatter = size_formatter; break;
|
2009-03-13 19:05:19 +01:00
|
|
|
case 'T': stats_formatter = nr_definitions_formatter;
|
|
|
|
formatter = NULL; break;
|
2007-11-16 19:01:26 +01:00
|
|
|
case 't': separator = arg[0]; break;
|
2008-02-07 12:16:22 +01:00
|
|
|
case 'u': defined_in = 1; break;
|
2007-11-16 19:01:26 +01:00
|
|
|
case 'V': global_verbose = 1; break;
|
2008-01-12 16:14:40 +01:00
|
|
|
case 'w': word_size = atoi(arg); break;
|
2007-11-16 19:01:26 +01:00
|
|
|
case 'X': cu__exclude_prefix = arg;
|
|
|
|
cu__exclude_prefix_len = strlen(cu__exclude_prefix);
|
2007-03-30 15:07:01 +02:00
|
|
|
break;
|
|
|
|
case 'x': class__exclude_prefix = arg;
|
|
|
|
class__exclude_prefix_len = strlen(class__exclude_prefix);
|
|
|
|
break;
|
2009-03-13 19:05:19 +01:00
|
|
|
case 'y': class__include_prefix = arg;
|
|
|
|
class__include_prefix_len = strlen(class__include_prefix);
|
|
|
|
break;
|
2007-11-16 19:01:26 +01:00
|
|
|
case 'z':
|
|
|
|
hole_size_ge = atoi(arg);
|
|
|
|
if (!global_verbose)
|
|
|
|
formatter = class_name_formatter;
|
|
|
|
break;
|
2009-03-20 14:29:50 +01:00
|
|
|
case 'Z': ctf_encode = 1; break;
|
|
|
|
case ARGP_flat_arrays: conf.flat_arrays = 1; break;
|
2019-04-03 18:08:02 +02:00
|
|
|
case ARGP_suppress_aligned_attribute:
|
|
|
|
conf.suppress_aligned_attribute = 1; break;
|
2019-04-15 19:34:25 +02:00
|
|
|
case ARGP_suppress_force_paddings:
|
|
|
|
conf.suppress_force_paddings = 1; break;
|
2019-04-15 20:01:53 +02:00
|
|
|
case ARGP_suppress_packed:
|
|
|
|
conf.suppress_packed = 1; break;
|
2009-03-20 15:37:22 +01:00
|
|
|
case ARGP_show_private_classes:
|
2009-03-20 18:13:40 +01:00
|
|
|
show_private_classes = true;
|
|
|
|
conf.show_only_data_members = 1; break;
|
2009-03-20 17:54:04 +01:00
|
|
|
case ARGP_fixup_silly_bitfields:
|
|
|
|
conf_load.fixup_silly_bitfields = 1; break;
|
2009-08-24 20:13:58 +02:00
|
|
|
case ARGP_first_obj_only:
|
|
|
|
first_obj_only = true; break;
|
2009-08-24 22:22:43 +02:00
|
|
|
case ARGP_classes_as_structs:
|
|
|
|
conf.classes_as_structs = 1; break;
|
2009-10-20 17:59:12 +02:00
|
|
|
case ARGP_hex_fmt:
|
|
|
|
conf.hex_fmt = 1; break;
|
pahole: Introduce --unions to consider just unions
Most filters can be used together with it, for instance to see the
biggest unions in the kernel:
$ pahole --unions --sizes | sort -k2 -nr | head
thread_union 16384 0
swap_header 4096 0
fpregs_state 4096 0
autofs_v5_packet_union 304 0
autofs_packet_union 272 0
pptp_ctrl_union 208 0
acpi_parse_object 200 0
acpi_descriptor 200 0
bpf_attr 120 0
phy_configure_opts 112 0
$
Or just some unions that have some specific prefix:
$ pahole --unions --prefix tcp
union tcp_md5_addr {
struct in_addr a4; /* 0 4 */
struct in6_addr a6; /* 0 16 */
};
union tcp_word_hdr {
struct tcphdr hdr; /* 0 20 */
__be32 words[5]; /* 0 20 */
};
union tcp_cc_info {
struct tcpvegas_info vegas; /* 0 16 */
struct tcp_dctcp_info dctcp; /* 0 16 */
struct tcp_bbr_info bbr; /* 0 20 */
};
$
What are the biggest unions in terms of number of members?
$ pahole --unions --nr_members | sort -k2 -nr | head
security_list_options 218
aml_resource 36
acpi_resource_data 29
acpi_operand_object 26
iwreq_data 18
sctp_params 15
ib_flow_spec 14
ethtool_flow_union 14
pptp_ctrl_union 13
bpf_attr 12
$
If you want to script most of the queries can change the separator:
$ pahole --unions --nr_members -t, | sort -t, -k2 -nr | head
security_list_options,218
aml_resource,36
acpi_resource_data,29
acpi_operand_object,26
iwreq_data,18
sctp_params,15
ib_flow_spec,14
ethtool_flow_union,14
pptp_ctrl_union,13
bpf_attr,12
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-01-15 15:35:25 +01:00
|
|
|
case ARGP_just_unions:
|
|
|
|
just_unions = true; break;
|
2020-01-15 16:41:28 +01:00
|
|
|
case ARGP_just_structs:
|
|
|
|
just_structs = true; break;
|
2007-03-30 15:07:01 +02:00
|
|
|
default:
|
|
|
|
return ARGP_ERR_UNKNOWN;
|
|
|
|
}
|
|
|
|
return 0;
|
2006-11-02 17:47:37 +01:00
|
|
|
}
|
|
|
|
|
2008-01-31 12:30:55 +01:00
|
|
|
static const char pahole__args_doc[] = "FILE";
|
2007-03-30 15:07:01 +02:00
|
|
|
|
|
|
|
static struct argp pahole__argp = {
|
|
|
|
.options = pahole__options,
|
|
|
|
.parser = pahole__options_parser,
|
|
|
|
.args_doc = pahole__args_doc,
|
|
|
|
};
|
|
|
|
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
static void do_reorg(struct tag *class, struct cu *cu)
|
2009-03-13 19:05:19 +01:00
|
|
|
{
|
2009-08-13 16:59:18 +02:00
|
|
|
int savings;
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
const uint8_t reorg_verbose =
|
|
|
|
show_reorg_steps ? 2 : global_verbose;
|
2009-08-18 23:21:20 +02:00
|
|
|
struct class *clone = class__clone(tag__class(class), NULL, cu);
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
if (clone == NULL) {
|
|
|
|
fprintf(stderr, "pahole: out of memory!\n");
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
class__reorganize(clone, cu, reorg_verbose, stdout);
|
|
|
|
savings = class__size(tag__class(class)) - class__size(clone);
|
|
|
|
if (savings != 0 && reorg_verbose) {
|
|
|
|
putchar('\n');
|
|
|
|
if (show_reorg_steps)
|
|
|
|
puts("/* Final reorganized struct: */");
|
|
|
|
}
|
|
|
|
tag__fprintf(class__tag(clone), cu, &conf, stdout);
|
|
|
|
if (savings != 0) {
|
|
|
|
const size_t cacheline_savings =
|
|
|
|
(tag__nr_cachelines(class, cu) -
|
|
|
|
tag__nr_cachelines(class__tag(clone), cu));
|
|
|
|
|
2009-08-13 16:59:18 +02:00
|
|
|
printf(" /* saved %d byte%s", savings,
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
savings != 1 ? "s" : "");
|
|
|
|
if (cacheline_savings != 0)
|
|
|
|
printf(" and %zu cacheline%s",
|
|
|
|
cacheline_savings,
|
|
|
|
cacheline_savings != 1 ?
|
|
|
|
"s" : "");
|
|
|
|
puts("! */");
|
|
|
|
} else
|
|
|
|
putchar('\n');
|
|
|
|
|
2009-09-20 21:46:32 +02:00
|
|
|
/* FIXME: we need to free in the right order,
|
|
|
|
* cu->obstack is being corrupted...
|
|
|
|
class__delete(clone, cu);
|
|
|
|
*/
|
2009-03-13 19:05:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static enum load_steal_kind pahole_stealer(struct cu *cu,
|
|
|
|
struct conf_load *conf_load __unused)
|
|
|
|
{
|
2012-03-22 19:30:28 +01:00
|
|
|
int ret = LSK__DELETE;
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
|
2009-03-13 19:05:19 +01:00
|
|
|
if (!cu__filter(cu))
|
2009-08-24 20:13:58 +02:00
|
|
|
goto filter_it;
|
2009-03-13 19:05:19 +01:00
|
|
|
|
2018-03-06 01:53:50 +01:00
|
|
|
if (btf_encode) {
|
|
|
|
cu__encode_btf(cu, global_verbose);
|
2018-12-18 23:09:39 +01:00
|
|
|
return LSK__KEEPIT;
|
2018-03-06 01:53:50 +01:00
|
|
|
}
|
|
|
|
|
2009-03-19 16:16:07 +01:00
|
|
|
if (ctf_encode) {
|
2009-12-06 17:17:29 +01:00
|
|
|
cu__encode_ctf(cu, global_verbose);
|
2009-03-19 16:16:07 +01:00
|
|
|
/*
|
|
|
|
* We still have to get the type signature code merged to eliminate
|
|
|
|
* dups, reference another CTF file, etc, so for now just encode the
|
|
|
|
* first cu that is let thru by cu__filter.
|
|
|
|
*/
|
|
|
|
goto dump_and_stop;
|
|
|
|
}
|
|
|
|
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
if (class_name == NULL) {
|
|
|
|
if (stats_formatter == nr_methods_formatter) {
|
|
|
|
cu__account_nr_methods(cu);
|
|
|
|
goto dump_it;
|
|
|
|
}
|
2009-03-13 19:05:19 +01:00
|
|
|
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
if (word_size != 0)
|
|
|
|
cu_fixup_word_size_iterator(cu);
|
2009-02-10 00:43:56 +01:00
|
|
|
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
memset(tab, ' ', sizeof(tab) - 1);
|
2009-03-13 19:05:19 +01:00
|
|
|
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
print_classes(cu);
|
2009-03-13 19:05:19 +01:00
|
|
|
goto dump_it;
|
2009-02-10 22:11:32 +01:00
|
|
|
}
|
[PAHOLE]: Use cus__loadfl, i.e. libdwfl
Now we have:
[acme@filo pahole]$ pahole --help
Usage: pahole [OPTION...] [FILE] {[CLASS]}
-a, --anon_include include anonymous classes
-A, --nested_anon_include include nested (inside other structs) anonymous
classes
-B, --bit_holes=NR_HOLES Show only structs at least NR_HOLES bit holes
-c, --cacheline_size=SIZE set cacheline size to SIZE
-D, --decl_exclude=PREFIX exclude classes declared in files with PREFIX
-E, --expand_types expand class members
-H, --holes=NR_HOLES show only structs at least NR_HOLES holes
-m, --nr_methods show number of methods
-n, --nr_members show number of members
-N, --class_name_len show size of classes
-P, --packable show only structs that has holes that can be
packed
-R, --reorganize reorg struct trying to kill holes
-s, --sizes show size of classes
-S, --show_reorg_steps show the struct layout at each reorganization step
-t, --nr_definitions show how many times struct was defined
-V, --verbose be verbose
-x, --exclude=PREFIX exclude PREFIXed classes
-X, --cu_exclude=PREFIX exclude PREFIXed compilation units
Input Selection:
--debuginfo-path=PATH Search path for separate debuginfo files
-e, --executable=FILE Find addresses in FILE
-k, --kernel Find addresses in the running kernel
-K, --offline-kernel[=RELEASE] Kernel with all modules
-M, --linux-process-map=FILE Find addresses in files mapped as read from
FILE in Linux /proc/PID/maps format
-p, --pid=PID Find addresses in files mapped into process PID
-?, --help Give this help list
--usage Give a short usage message
Mandatory or optional arguments to long options are also mandatory or optional
for any corresponding short options.
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-03-30 18:25:51 +02:00
|
|
|
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
struct str_node *pos;
|
|
|
|
struct rb_node *next = rb_first(&class_names->entries);
|
2008-01-12 16:14:40 +01:00
|
|
|
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
while (next) {
|
|
|
|
pos = rb_entry(next, struct str_node, rb_node);
|
|
|
|
next = rb_next(&pos->rb_node);
|
2007-05-11 00:11:51 +02:00
|
|
|
|
2019-03-07 22:04:20 +01:00
|
|
|
static type_id_t class_id;
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
bool include_decls = find_pointers_in_structs != 0 ||
|
|
|
|
stats_formatter == nr_methods_formatter;
|
2018-12-03 17:15:14 +01:00
|
|
|
struct tag *class = cu__find_struct_or_union_by_name(cu, pos->s, include_decls, &class_id);
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
if (class == NULL)
|
|
|
|
continue;
|
2008-10-28 21:56:47 +01:00
|
|
|
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
if (defined_in) {
|
|
|
|
puts(cu->name);
|
|
|
|
goto dump_it;
|
2009-03-13 19:05:19 +01:00
|
|
|
}
|
|
|
|
/*
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
* Ok, found it, so remove from the list to avoid printing it
|
|
|
|
* twice, in another CU.
|
2009-03-13 19:05:19 +01:00
|
|
|
*/
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
strlist__remove(class_names, pos);
|
|
|
|
|
|
|
|
class__find_holes(tag__class(class));
|
2018-12-03 17:15:14 +01:00
|
|
|
if (reorganize) {
|
|
|
|
if (tag__is_struct(class))
|
|
|
|
do_reorg(class, cu);
|
|
|
|
} else if (find_containers)
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
print_containers(cu, class_id, 0);
|
|
|
|
else if (find_pointers_in_structs)
|
|
|
|
print_structs_with_pointer_to(cu, class_id);
|
|
|
|
else {
|
|
|
|
/*
|
|
|
|
* We don't need to print it for every compile unit
|
|
|
|
* but the previous options need
|
|
|
|
*/
|
|
|
|
tag__fprintf(class, cu, &conf, stdout);
|
|
|
|
putchar('\n');
|
|
|
|
}
|
2009-03-13 19:05:19 +01:00
|
|
|
}
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If we found all the entries in --class_name, stop
|
|
|
|
*/
|
|
|
|
if (strlist__empty(class_names)) {
|
2009-03-19 16:16:07 +01:00
|
|
|
dump_and_stop:
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
ret = LSK__STOP_LOADING;
|
|
|
|
}
|
2009-03-13 19:05:19 +01:00
|
|
|
dump_it:
|
2009-08-24 20:13:58 +02:00
|
|
|
if (first_obj_only)
|
|
|
|
ret = LSK__STOP_LOADING;
|
|
|
|
filter_it:
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int add_class_name_entry(const char *s)
|
|
|
|
{
|
|
|
|
if (strncmp(s, "file://", 7) == 0) {
|
|
|
|
if (strlist__load(class_names, s + 7))
|
|
|
|
return -1;
|
|
|
|
} else switch (strlist__add(class_names, s)) {
|
|
|
|
case -EEXIST:
|
|
|
|
if (global_verbose)
|
|
|
|
fprintf(stderr,
|
|
|
|
"pahole: %s dup in -C, ignoring\n", s);
|
|
|
|
break;
|
|
|
|
case -ENOMEM:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int populate_class_names(void)
|
|
|
|
{
|
|
|
|
char *s = class_name, *sep;
|
|
|
|
|
|
|
|
while ((sep = strchr(s, ',')) != NULL) {
|
|
|
|
*sep = '\0';
|
|
|
|
if (add_class_name_entry(s))
|
|
|
|
return -1;
|
|
|
|
*sep = ',';
|
|
|
|
s = sep + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return *s ? add_class_name_entry(s) : 0;
|
2009-03-13 19:05:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
int err, remaining, rc = EXIT_FAILURE;
|
|
|
|
|
pahole: Do not require a class name to operate without a file name
Since we default to operating on the running kernel data structures, we
should make the default to, with no options passed, to pretty print all
the running kernel data structures, or do what was asked in terms of
number of members, size of structs, etc, i.e.:
[root@quaco ~]# pahole --help |& head
Usage: pahole [OPTION...] FILE
-a, --anon_include include anonymous classes
-A, --nested_anon_include include nested (inside other structs) anonymous
classes
-B, --bit_holes=NR_HOLES Show only structs at least NR_HOLES bit holes
-c, --cacheline_size=SIZE set cacheline size to SIZE
--classes_as_structs Use 'struct' when printing classes
-C, --class_name=CLASS_NAME Show just this class
-d, --recursive recursive mode, affects several other flags
[root@quaco ~]#
Continues working as before, but if you do:
pahole
It will work just as if you did:
pahole vmlinux
and that vmlinux file is the running kernel vmlinux.
And since the default now is to read BTF info, then it will do all its
operations on /sys/kernel/btf/vmlinux, when present, i.e. want to know
what are the fattest data structures in the running kernel:
[root@quaco ~]# pahole -s | sort -k2 -nr | head
cmp_data 290904 1
dec_data 274520 1
cpu_entry_area 217088 0
pglist_data 172928 4
saved_cmdlines_buffer 131104 1
debug_store_buffers 131072 0
hid_parser 110848 1
hid_local 110608 0
zonelist 81936 0
e820_table 64004 0
[root@quaco ~]#
How many data structures in the running kernel vmlinux area embbed
'struct list_head'?
[root@quaco ~]# pahole -i list_head | wc -l
260
[root@quaco ~]#
Lets see some of those?
[root@quaco ~]# pahole -C fsnotify_event
struct fsnotify_event {
struct list_head list; /* 0 16 */
struct inode * inode; /* 16 8 */
/* size: 24, cachelines: 1, members: 2 */
/* last cacheline: 24 bytes */
};
[root@quaco ~]# pahole -C audit_chunk
struct audit_chunk {
struct list_head hash; /* 0 16 */
long unsigned int key; /* 16 8 */
struct fsnotify_mark * mark; /* 24 8 */
struct list_head trees; /* 32 16 */
int count; /* 48 4 */
/* XXX 4 bytes hole, try to pack */
atomic_long_t refs; /* 56 8 */
/* --- cacheline 1 boundary (64 bytes) --- */
struct callback_head head; /* 64 16 */
struct node owners[]; /* 80 0 */
/* size: 80, cachelines: 2, members: 8 */
/* sum members: 76, holes: 1, sum holes: 4 */
/* last cacheline: 16 bytes */
};
[root@quaco ~]#
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-01-06 17:53:37 +01:00
|
|
|
if (argp_parse(&pahole__argp, argc, argv, 0, &remaining, NULL)) {
|
2009-03-13 19:05:19 +01:00
|
|
|
argp_help(&pahole__argp, stderr, ARGP_HELP_SEE, argv[0]);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
class_names = strlist__new(true);
|
|
|
|
|
|
|
|
if (class_names == NULL || dwarves__init(cacheline_size)) {
|
2009-03-13 19:05:19 +01:00
|
|
|
fputs("pahole: insufficient memory\n", stderr);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
all: Fix possible uninitialized variable uses
I wasn't especifying the optimization level and the default, despite
using -Wall, was for this so simple case not to be warned about, so
now I'm using -O2.
Alexandre provided a patch initializing the variables to NULL, so that
when we called cus__delete it would bail out and not possibly act on
a random value, I preferred to add extra goto labels and do the exit
path only on the resources that were successfully allocated/initialized,
avoiding, for instance, to call dwarves_exit() if dwarves_init() wasn't
called, which wasn't a problem so far, but could be in the future.
Reported-by: Alexandre Vassalotti <alexandre@peadrop.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-05-04 20:50:06 +02:00
|
|
|
struct cus *cus = cus__new();
|
|
|
|
if (cus == NULL) {
|
|
|
|
fputs("pahole: insufficient memory\n", stderr);
|
|
|
|
goto out_dwarves_exit;
|
|
|
|
}
|
|
|
|
|
2009-03-13 19:05:19 +01:00
|
|
|
conf_load.steal = pahole_stealer;
|
|
|
|
|
pahole: When the sole argument passed isn't a file, take it as a class name
With that it becomes as compact as it gets for kernel data structures,
just state the name of the struct and it'll try to find that as a file,
not being a file it'll use /sys/kernel/btf/vmlinux and the argument as a
list of structs, i.e.:
$ pahole skb_ext,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 */
};
struct skb_ext {
refcount_t refcnt; /* 0 4 */
u8 offset[3]; /* 4 3 */
u8 chunks; /* 7 1 */
char data[]; /* 8 0 */
/* size: 8, cachelines: 1, members: 4 */
/* last cacheline: 8 bytes */
};
$ pahole hlist_node
struct hlist_node {
struct hlist_node * next; /* 0 8 */
struct hlist_node * * pprev; /* 8 8 */
/* size: 16, cachelines: 1, members: 2 */
/* last cacheline: 16 bytes */
};
$
Of course -C continues to work:
$ pahole -C inode | tail
__u32 i_fsnotify_mask; /* 556 4 */
struct fsnotify_mark_connector * i_fsnotify_marks; /* 560 8 */
struct fscrypt_info * i_crypt_info; /* 568 8 */
/* --- cacheline 9 boundary (576 bytes) --- */
struct fsverity_info * i_verity_info; /* 576 8 */
void * i_private; /* 584 8 */
/* size: 592, cachelines: 10, members: 53 */
/* last cacheline: 16 bytes */
};
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-01-14 18:04:09 +01:00
|
|
|
try_sole_arg_as_class_names:
|
|
|
|
if (class_name && populate_class_names())
|
|
|
|
goto out_dwarves_exit;
|
|
|
|
|
2009-03-13 19:05:19 +01:00
|
|
|
err = cus__load_files(cus, &conf_load, argv + remaining);
|
|
|
|
if (err != 0) {
|
pahole: When the sole argument passed isn't a file, take it as a class name
With that it becomes as compact as it gets for kernel data structures,
just state the name of the struct and it'll try to find that as a file,
not being a file it'll use /sys/kernel/btf/vmlinux and the argument as a
list of structs, i.e.:
$ pahole skb_ext,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 */
};
struct skb_ext {
refcount_t refcnt; /* 0 4 */
u8 offset[3]; /* 4 3 */
u8 chunks; /* 7 1 */
char data[]; /* 8 0 */
/* size: 8, cachelines: 1, members: 4 */
/* last cacheline: 8 bytes */
};
$ pahole hlist_node
struct hlist_node {
struct hlist_node * next; /* 0 8 */
struct hlist_node * * pprev; /* 8 8 */
/* size: 16, cachelines: 1, members: 2 */
/* last cacheline: 16 bytes */
};
$
Of course -C continues to work:
$ pahole -C inode | tail
__u32 i_fsnotify_mask; /* 556 4 */
struct fsnotify_mark_connector * i_fsnotify_marks; /* 560 8 */
struct fscrypt_info * i_crypt_info; /* 568 8 */
/* --- cacheline 9 boundary (576 bytes) --- */
struct fsverity_info * i_verity_info; /* 576 8 */
void * i_private; /* 584 8 */
/* size: 592, cachelines: 10, members: 53 */
/* last cacheline: 16 bytes */
};
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-01-14 18:04:09 +01:00
|
|
|
if (class_name == NULL) {
|
|
|
|
class_name = argv[remaining];
|
|
|
|
remaining = argc;
|
|
|
|
goto try_sole_arg_as_class_names;
|
|
|
|
}
|
2016-03-15 18:25:58 +01:00
|
|
|
cus__fprintf_load_files_err(cus, "pahole", argv + remaining, err, stderr);
|
all: Fix possible uninitialized variable uses
I wasn't especifying the optimization level and the default, despite
using -Wall, was for this so simple case not to be warned about, so
now I'm using -O2.
Alexandre provided a patch initializing the variables to NULL, so that
when we called cus__delete it would bail out and not possibly act on
a random value, I preferred to add extra goto labels and do the exit
path only on the resources that were successfully allocated/initialized,
avoiding, for instance, to call dwarves_exit() if dwarves_init() wasn't
called, which wasn't a problem so far, but could be in the future.
Reported-by: Alexandre Vassalotti <alexandre@peadrop.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-05-04 20:50:06 +02:00
|
|
|
goto out_cus_delete;
|
2009-03-13 19:05:19 +01:00
|
|
|
}
|
|
|
|
|
2018-12-18 23:09:39 +01:00
|
|
|
if (btf_encode) {
|
|
|
|
err = btf_encoder__encode();
|
|
|
|
if (err) {
|
|
|
|
fputs("Failed to encode BTF\n", stderr);
|
|
|
|
goto out_cus_delete;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-13 19:05:19 +01:00
|
|
|
if (stats_formatter != NULL)
|
|
|
|
print_stats();
|
2009-03-11 16:31:17 +01:00
|
|
|
rc = EXIT_SUCCESS;
|
all: Fix possible uninitialized variable uses
I wasn't especifying the optimization level and the default, despite
using -Wall, was for this so simple case not to be warned about, so
now I'm using -O2.
Alexandre provided a patch initializing the variables to NULL, so that
when we called cus__delete it would bail out and not possibly act on
a random value, I preferred to add extra goto labels and do the exit
path only on the resources that were successfully allocated/initialized,
avoiding, for instance, to call dwarves_exit() if dwarves_init() wasn't
called, which wasn't a problem so far, but could be in the future.
Reported-by: Alexandre Vassalotti <alexandre@peadrop.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-05-04 20:50:06 +02:00
|
|
|
out_cus_delete:
|
2009-07-06 05:42:59 +02:00
|
|
|
#ifdef DEBUG_CHECK_LEAKS
|
2009-03-11 16:31:17 +01:00
|
|
|
cus__delete(cus);
|
|
|
|
structures__delete();
|
2009-07-06 05:42:59 +02:00
|
|
|
#endif
|
all: Fix possible uninitialized variable uses
I wasn't especifying the optimization level and the default, despite
using -Wall, was for this so simple case not to be warned about, so
now I'm using -O2.
Alexandre provided a patch initializing the variables to NULL, so that
when we called cus__delete it would bail out and not possibly act on
a random value, I preferred to add extra goto labels and do the exit
path only on the resources that were successfully allocated/initialized,
avoiding, for instance, to call dwarves_exit() if dwarves_init() wasn't
called, which wasn't a problem so far, but could be in the future.
Reported-by: Alexandre Vassalotti <alexandre@peadrop.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-05-04 20:50:06 +02:00
|
|
|
out_dwarves_exit:
|
2009-07-06 05:42:59 +02:00
|
|
|
#ifdef DEBUG_CHECK_LEAKS
|
2009-03-11 16:31:17 +01:00
|
|
|
dwarves__exit();
|
2009-07-06 05:42:59 +02:00
|
|
|
#endif
|
all: Fix possible uninitialized variable uses
I wasn't especifying the optimization level and the default, despite
using -Wall, was for this so simple case not to be warned about, so
now I'm using -O2.
Alexandre provided a patch initializing the variables to NULL, so that
when we called cus__delete it would bail out and not possibly act on
a random value, I preferred to add extra goto labels and do the exit
path only on the resources that were successfully allocated/initialized,
avoiding, for instance, to call dwarves_exit() if dwarves_init() wasn't
called, which wasn't a problem so far, but could be in the future.
Reported-by: Alexandre Vassalotti <alexandre@peadrop.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-05-04 20:50:06 +02:00
|
|
|
out:
|
2009-07-06 05:42:59 +02:00
|
|
|
#ifdef DEBUG_CHECK_LEAKS
|
pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:
[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
And also:
[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
void * tree; /* 0 8 */
struct gobuffer gb; /* 8 24 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
struct tag {
struct list_head node; /* 0 16 */
uint16_t type; /* 16 2 */
uint16_t tag; /* 18 2 */
uint16_t visited:1; /* 20:15 2 */
uint16_t top_level:1; /* 20:14 2 */
/* XXX 14 bits hole, try to pack */
uint16_t recursivity_level; /* 22 2 */
void * priv; /* 24 8 */
/* size: 32, cachelines: 1, members: 7 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
struct str_node {
struct rb_node rb_node; /* 0 24 */
const char * s; /* 24 8 */
/* size: 32, cachelines: 1, members: 2 */
/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$
Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 19:58:51 +02:00
|
|
|
strlist__delete(class_names);
|
2009-07-06 05:42:59 +02:00
|
|
|
#endif
|
2009-03-11 16:31:17 +01:00
|
|
|
return rc;
|
2006-10-25 01:42:39 +02:00
|
|
|
}
|