dwarves/dwarves.h

1308 lines
38 KiB
C
Raw Normal View History

#ifndef _DWARVES_H_
#define _DWARVES_H_ 1
/*
SPDX-License-Identifier: GPL-2.0-only
Copyright (C) 2006 Mandriva Conectiva S.A.
Copyright (C) 2006..2019 Arnaldo Carvalho de Melo <acme@redhat.com>
*/
#include <stdint.h>
#include <stdio.h>
#include <dwarf.h>
#include <elfutils/libdwfl.h>
pahole: Introduce --seek_bytes Works with stdio, will work with files where we'll use plain lseek and allow for pretty printing trailer structs. E.g.: $ objcopy -O binary --only-section=__versions drivers/scsi/sg.ko versions $ pahole -C modversion_info drivers/scsi/sg.ko struct modversion_info { long unsigned int crc; /* 0 8 */ char name[56]; /* 8 56 */ /* size: 64, cachelines: 1, members: 2 */ }; $ pahole --count 2 -C modversion_info drivers/scsi/sg.ko < versions { .crc = 0x8dabd84, .name = "module_layout", }, { .crc = 0x45e4617b, .name = "no_llseek", }, $ pahole --skip 1 --count 1 -C modversion_info drivers/scsi/sg.ko < versions { .crc = 0x45e4617b, .name = "no_llseek", }, Then the equivalent, skipping sizeof(modversion_info) explicitely: $ pahole --seek_bytes 64 --count 1 -C modversion_info drivers/scsi/sg.ko < versions { .crc = 0x45e4617b, .name = "no_llseek", }, $ Using a perf.data file generated by 'perf record': $ perf report -D | head -18 # To display the perf.data header info, please use --header/--header-only options. # 0x130 [0x20]: event: 79 . . ... raw event: size 32 bytes . 0000: 4f 00 00 00 00 00 20 00 1f 00 00 00 00 00 00 00 O..... ......... . 0010: 31 30 9b 3c 00 00 00 00 2e 53 f8 0c 52 8c 01 00 10.<.....S�.R... 0 0x130 [0x20]: PERF_RECORD_TIME_CONV: unhandled! 0x150 [0x28]: event: 73 . . ... raw event: size 40 bytes . 0000: 49 00 00 00 00 00 28 00 01 00 00 00 00 00 00 00 I.....(......... . 0010: 50 7e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 P~.............. . 0020: 00 00 00 00 00 00 00 00 ........ $ pahole --seek_bytes 0x130 --count 1 -C perf_event_header < perf.data { .type = 0x4f, .misc = 0, .size = 0x20, }, $ printf "0x%x\n" 79 0x4f $ pahole --seek_bytes 0x150 --count 1 -C perf_event_header < perf.data { .type = 0x49, .misc = 0, .size = 0x28, }, $ printf "0x%x\n" 73 0x49 $ Now to use more complex types, again using perf.data files. # perf record -a sleep 1 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 3.834 MB perf.data (31853 samples) ] # perf report -D | grep -m1 -B20 PERF_RECORD_BPF 0x6aa0 [0x58]: event: 17 . . ... raw event: size 88 bytes . 0020: 5f 37 62 65 34 39 65 33 39 33 34 61 31 32 35 62 _7be49e3934a125b . 0030: 61 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 a............... . 0040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ . 0050: 00 00 00 00 00 00 00 00 ........ 0 0 0x6aa0 [0x58]: PERF_RECORD_KSYMBOL addr ffffffffc03e0e90 len 203 type 1 flags 0x0 name bpf_prog_7be49e3934a125ba 0x6af8 [0x38]: event: 18 . . ... raw event: size 56 bytes . 0000: 12 00 00 00 00 00 38 00 01 00 00 00 11 00 00 00 ......8......... . 0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ . 0030: 00 00 00 00 00 00 00 00 ........ 0 0 0x6af8 [0x38]: PERF_RECORD_BPF_EVENT type 1, flags 0, id 17 Binary file (standard input) matches # pahole -C perf_record_bpf_event ~/bin/perf struct perf_record_bpf_event { struct perf_event_header header; /* 0 8 */ __u16 type; /* 8 2 */ __u16 flags; /* 10 2 */ __u32 id; /* 12 4 */ __u8 tag[8]; /* 16 8 */ /* size: 24, cachelines: 1, members: 5 */ /* last cacheline: 24 bytes */ }; # pahole -C perf_record_bpf_event --seek_bytes 0x6af8 --count 1 ~/bin/perf < perf.data { .header = 0x12 0x00 0x00 0x00 0x00 0x00 0x38 0x00, .type = 0x1, .flags = 0, .id = 0x11, .tag = { 0, 0, 0, 0, 0, 0, 0, 0}, }, # printf "0x%x\n" 18 0x12 # pahole -C perf_record_ksymbol ~/bin/perf struct perf_record_ksymbol { struct perf_event_header header; /* 0 8 */ __u64 addr; /* 8 8 */ __u32 len; /* 16 4 */ __u16 ksym_type; /* 20 2 */ __u16 flags; /* 22 2 */ char name[256]; /* 24 256 */ /* size: 280, cachelines: 5, members: 6 */ /* last cacheline: 24 bytes */ }; # pahole -C perf_record_ksymbol --seek_bytes 0x6aa0 --count 1 ~/bin/perf < perf.data { .header = 0x11 0x00 0x00 0x00 0x00 0x00 0x58 0x00, .addr = 0xffffffffc03e0e90, .len = 0xcb, .ksym_type = 0x1, .flags = 0, .name = "bpf_prog_7be49e3934a125ba", }, # printf "0x%x\n" 17 0x11 # Need to recursively pretty print substructs, but all seems to work with the simple hexdump. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-07-01 14:17:38 +02:00
#include <sys/types.h>
#include "dutil.h"
#include "list.h"
#include "rbtree.h"
struct cu;
enum load_steal_kind {
LSK__KEEPIT,
LSK__DELETE,
LSK__STOP_LOADING,
};
/*
* BTF combines all the types into one big CU using btf_dedup(), so for something
* like a allyesconfig vmlinux kernel we can get over 65535 types.
*/
typedef uint32_t type_id_t;
struct btf;
struct conf_fprintf;
/** struct conf_load - load configuration
* @extra_dbg_info - keep original debugging format extra info
* (e.g. DWARF's decl_{line,file}, id, etc)
* @fixup_silly_bitfields - Fixup silly things such as "int foo:32;"
dwarves: Allow avoiding loading addr information As, for instance, pahole doesn't need it at all. Down from: [acme@doppio pahole]$ perf stat -r 5 pahole object_samples/zweinberg\@mozilla.com/libgklayout.so > /dev/null Performance counter stats for 'pahole object_samples/zweinberg@mozilla.com/libgklayout.so' (5 runs): 17233.989563 task-clock-msecs # 0.994 CPUs ( +- 0.076% ) 1880 context-switches # 0.000 M/sec ( +- 0.159% ) 0 CPU-migrations # 0.000 M/sec ( +- 0.000% ) 26248 page-faults # 0.002 M/sec ( +- 0.000% ) 34244461105 cycles # 1987.030 M/sec ( +- 0.078% ) 34510583834 instructions # 1.008 IPC ( +- 0.001% ) 445937867 cache-references # 25.875 M/sec ( +- 0.160% ) 56898165 cache-misses # 3.302 M/sec ( +- 0.074% ) 17.335292038 seconds time elapsed ( +- 0.076% ) [acme@doppio pahole]$ To: [acme@doppio pahole]$ perf stat -r 5 pahole object_samples/zweinberg\@mozilla.com/libgklayout.so > /dev/null Performance counter stats for 'pahole object_samples/zweinberg@mozilla.com/libgklayout.so' (5 runs): 16511.627334 task-clock-msecs # 0.992 CPUs ( +- 0.208% ) 1922 context-switches # 0.000 M/sec ( +- 3.068% ) 0 CPU-migrations # 0.000 M/sec ( +- 0.000% ) 25570 page-faults # 0.002 M/sec ( +- 0.000% ) 32807624343 cycles # 1986.941 M/sec ( +- 0.208% ) 32711598374 instructions # 0.997 IPC ( +- 0.001% ) 436345377 cache-references # 26.427 M/sec ( +- 0.178% ) 54044997 cache-misses # 3.273 M/sec ( +- 0.685% ) 16.652951166 seconds time elapsed ( +- 0.304% ) [acme@doppio pahole]$ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-07-06 18:44:57 +02:00
* @get_addr_info - wheter to load DW_AT_location and other addr info
* @nr_jobs - -j argument, number of threads to use
*/
struct conf_load {
enum load_steal_kind (*steal)(struct cu *cu,
struct conf_load *conf);
void *cookie;
char *format_path;
int nr_jobs;
bool extra_dbg_info;
bool fixup_silly_bitfields;
dwarves: Allow avoiding loading addr information As, for instance, pahole doesn't need it at all. Down from: [acme@doppio pahole]$ perf stat -r 5 pahole object_samples/zweinberg\@mozilla.com/libgklayout.so > /dev/null Performance counter stats for 'pahole object_samples/zweinberg@mozilla.com/libgklayout.so' (5 runs): 17233.989563 task-clock-msecs # 0.994 CPUs ( +- 0.076% ) 1880 context-switches # 0.000 M/sec ( +- 0.159% ) 0 CPU-migrations # 0.000 M/sec ( +- 0.000% ) 26248 page-faults # 0.002 M/sec ( +- 0.000% ) 34244461105 cycles # 1987.030 M/sec ( +- 0.078% ) 34510583834 instructions # 1.008 IPC ( +- 0.001% ) 445937867 cache-references # 25.875 M/sec ( +- 0.160% ) 56898165 cache-misses # 3.302 M/sec ( +- 0.074% ) 17.335292038 seconds time elapsed ( +- 0.076% ) [acme@doppio pahole]$ To: [acme@doppio pahole]$ perf stat -r 5 pahole object_samples/zweinberg\@mozilla.com/libgklayout.so > /dev/null Performance counter stats for 'pahole object_samples/zweinberg@mozilla.com/libgklayout.so' (5 runs): 16511.627334 task-clock-msecs # 0.992 CPUs ( +- 0.208% ) 1922 context-switches # 0.000 M/sec ( +- 3.068% ) 0 CPU-migrations # 0.000 M/sec ( +- 0.000% ) 25570 page-faults # 0.002 M/sec ( +- 0.000% ) 32807624343 cycles # 1986.941 M/sec ( +- 0.208% ) 32711598374 instructions # 0.997 IPC ( +- 0.001% ) 436345377 cache-references # 26.427 M/sec ( +- 0.178% ) 54044997 cache-misses # 3.273 M/sec ( +- 0.685% ) 16.652951166 seconds time elapsed ( +- 0.304% ) [acme@doppio pahole]$ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-07-06 18:44:57 +02:00
bool get_addr_info;
uint16_t kabi_prefix_len;
const char *kabi_prefix;
struct btf *base_btf;
struct conf_fprintf *conf_fprintf;
};
/** struct conf_fprintf - hints to the __fprintf routines
*
* @count - Just like 'dd', stop pretty printing input after 'count' records
* @skip - Just like 'dd', skip 'count' records when pretty printing input
pahole: Add support for referencing header variables when pretty printing To know from where to start reading some variable sized type we need some information from a domain specific tool such as 'perf report -D' for perf.data files, i.e.: $ perf report -D -i perf.data # To display the perf.data header info, please use --header/--header-only options. # 0x130 [0x20]: event: 79 . . ... raw event: size 32 bytes . 0000: 4f 00 00 00 00 00 20 00 1f 00 00 00 00 00 00 00 O..... ......... . 0010: 31 30 9b 3c 00 00 00 00 2e 53 f8 0c 52 8c 01 00 10.<.....S<F8>.R... 0 0x130 [0x20]: PERF_RECORD_TIME_CONV: unhandled! So we see that 0x130 is where the first PERF_RECORD_* event is located, and we can use that with --seek_bytes and with some extra info we can decode variable sized records: $ pahole --seek_bytes=0x130 -C 'perf_event_header(sizeof=size,type=type,type_enum=perf_event_type)' --skip 2 --count 3 ~/bin/perf < perf.data { .type = 0x4a, .misc = 0, .size = 0x20, }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x28, }, .id = 0x1, .path = "/", }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x30, }, .id = 0x611, .path = "/system.slice", }, $ But if we decode the perf.data file header: $ pahole ~/bin/perf -C perf_file_header --count 1 < perf.data { .magic = 0x32454c4946524550, .size = 0x68, .attr_size = 0x88, .attrs = { .offset = 0xa8, .size = 0x88, }, .data = { .offset = 0x130, .size = 0x588, }, .event_types = { .offset = 0, .size = 0, }, .adds_features = { 0x16717ffc, 0, 0, 0 }, }, $ We see that that 0x130 offset is at field perf_file_header->data.offset, so lets automate this so that we can try to extract that value and then use it with --seek_bytes: $ pahole --header=perf_file_header --seek_bytes='$header.data.offset' -C 'perf_event_header(sizeof=size,type=type,type_enum=perf_event_type)' --skip 2 --count 3 ~/bin/perf < perf.data pahole: the type enum 'perf_event_type' wasn't found in 'util/header.c' $ The problem here is that pahole tries to avoid processing all the CUs (compile units) in a binary, as, so far, it only needed to process one main type at a time, i.e. the ones in -C/--class. Now we need multiple types, in the above example we need: struct perf_event_header struct pref_file_header enum perf_event_type And in this case, the perf binary doesn't have any object/CU that has all these three types. To see if the code works we can resort to using BTF, that combines all types into just one "CU", deduplicating them in the process, so: $ pahole --btf_encode ~/bin/perf And now it works: $ pahole -V -F btf --header=perf_file_header --seek_bytes='$header.data.offset' -C 'perf_event_header(sizeof=size,type=type,type_enum=perf_event_type)' --skip 2 --count 3 ~/bin/perf < perf.data pahole: sizeof_operator for 'perf_event_header' is 'size' pahole: type member for 'perf_event_header' is 'type' pahole: type enum for 'perf_event_header' is 'perf_event_type' pahole: seek bytes evaluated from --seek_bytes=$header.data.offset is 0x130 { .type = 0x4a, .misc = 0, .size = 0x20, }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x28, }, .id = 0x1, .path = "/", }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x30, }, .id = 0x611, .path = "/system.slice", }, $ In the next csets a fallback approach will allow for this to work even with DWARF, when we'll notice that stdin wasn't consumed and thus we need to search for the types needed with cus__find_struct_by_name() & friends. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-07-20 13:25:45 +02:00
* @seek_bytes - Number of bytes to seek, if stdin only from start, when we have --pretty FILE, then from the end as well with negative numbers,
* may be of the form $header.MEMBER_NAME when using with --header.
pahole: Add support for --size_bytes, accepts header variables Last magic number elliminated for the printing of 'struct perf_event_header' variable sized records as found in perf.data files. Now its possible to state when to stop processing, and do that based on fields in the header, i.e., for perf.data files we have: $ pahole ~/bin/perf -C perf_file_header --count 1 < perf.data { .magic = 0x32454c4946524550, .size = 0x68, .attr_size = 0x88, .attrs = { .offset = 0xa8, .size = 0x88, }, .data = { .offset = 0x130, .size = 0x588, }, .event_types = { .offset = 0, .size = 0, }, .adds_features = { 0x16717ffc, 0, 0, 0 }, }, $ So we want to start at header->data.offset and stop processing after event->data.size bytes, we can do it as naturally as: $ pahole -V -F btf \ --header=perf_file_header \ --seek_bytes='$header.data.offset' \ -C 'perf_event_header(sizeof=size,type=type,type_enum=perf_event_type)' \ --size_bytes='$header.data.size' ~/bin/perf < perf.data pahole: sizeof_operator for 'perf_event_header' is 'size' pahole: type member for 'perf_event_header' is 'type' pahole: type enum for 'perf_event_header' is 'perf_event_type' pahole: seek bytes evaluated from --seek_bytes=$header.data.offset is 0x130 pahole: size bytes evaluated from --size_bytes=$header.data.size is 0x588 { .type = 0x4f, .misc = 0, .size = 0x20, }, { .type = 0x49, .misc = 0, .size = 0x28, }, { .type = 0x4a, .misc = 0, .size = 0x20, }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x28, }, .id = 0x1, .path = "/", }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x30, }, .id = 0x611, .path = "/system.slice", }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x30, }, .id = 0x8, .path = "/machine.slice", }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x80, }, .id = 0x1e94, .path = "/machine.slice/libpod-42be8e8d4eb9d22405845005f0d04ea398548dccc934a150fbaa3c1f1f9492c2.scope", }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x58, }, .id = 0xd, .path = "/machine.slice/machine-qemu\x2d1\x2drhel6.sandy.scope", }, { .header = { .type = PERF_RECORD_COMM, .misc = 0, .size = 0x28, }, .pid = 0x7e50, .tid = 0x7e50, .comm = "perf", }, { .header = { .type = PERF_RECORD_COMM, .misc = 0x2000, .size = 0x28, }, .pid = 0x7e50, .tid = 0x7e50, .comm = "sleep", }, { .header = { .type = PERF_RECORD_MMAP2, .misc = 0x2, .size = 0x68, }, .pid = 0x7e50, .tid = 0x7e50, .start = 0x55ea2a865000, .len = 0x4000, .pgoff = 0x2000, .maj = 0xfd, .min = 0, .ino = 0x1e0526, .ino_generation = 0xc97273c3, .prot = 0x5, .flags = 0x1802, .filename = "/usr/bin/sleep", }, { .header = { .type = PERF_RECORD_MMAP2, .misc = 0x2, .size = 0x70, }, .pid = 0x7e50, .tid = 0x7e50, .start = 0x7f53040c7000, .len = 0x20000, .pgoff = 0x1000, .maj = 0xfd, .min = 0, .ino = 0x1e1faf, .ino_generation = 0x83ee2ed3, .prot = 0x5, .flags = 0x1802, .filename = "/usr/lib64/ld-2.29.so", }, { .header = { .type = PERF_RECORD_MMAP2, .misc = 0x2, .size = 0x60, }, .pid = 0x7e50, .tid = 0x7e50, .start = 0x7fffd8b69000, .len = 0x2000, .pgoff = 0, .maj = 0, .min = 0, .ino = 0, .ino_generation = 0, .prot = 0x5, .flags = 0x1002, .filename = "[vdso]", }, { .header = { .type = PERF_RECORD_SAMPLE, .misc = 0x4001, .size = 0x28, }, .array = { 0xffffffff88c00b27, 0x7e5000007e50, 0x190aac32b3544, 0x1 }, }, { .header = { .type = PERF_RECORD_SAMPLE, .misc = 0x4001, .size = 0x28, }, .array = { 0xffffffff88c00b27, 0x7e5000007e50, 0x190aac32b4a90, 0x1 }, }, { .header = { .type = PERF_RECORD_SAMPLE, .misc = 0x4001, .size = 0x28, }, .array = { 0xffffffff88c00b27, 0x7e5000007e50, 0x190aac32b57c8, 0x6 }, }, { .header = { .type = PERF_RECORD_SAMPLE, .misc = 0x4001, .size = 0x28, }, .array = { 0xffffffff88c00b27, 0x7e5000007e50, 0x190aac32b644b, 0x3a }, }, { .header = { .type = PERF_RECORD_SAMPLE, .misc = 0x4001, .size = 0x28, }, .array = { 0xffffffff88c00b27, 0x7e5000007e50, 0x190aac32b7279, 0x266 }, }, { .header = { .type = PERF_RECORD_SAMPLE, .misc = 0x4001, .size = 0x28, }, .array = { 0xffffffff88c00b27, 0x7e5000007e50, 0x190aac32b97c7, 0x16cd }, }, { .header = { .type = PERF_RECORD_SAMPLE, .misc = 0x4002, .size = 0x28, }, .array = { 0x7f53040c814b, 0x7e5000007e50, 0x190aac32bc2b8, 0x5f03 }, }, { .header = { .type = PERF_RECORD_SAMPLE, .misc = 0x4002, .size = 0x28, }, .array = { 0x7f53040dd5af, 0x7e5000007e50, 0x190aac32c1af2, 0x16141 }, }, { .header = { .type = PERF_RECORD_MMAP2, .misc = 0x2, .size = 0x70, }, .pid = 0x7e50, .tid = 0x7e50, .start = 0x7f5303efe000, .len = 0x14d000, .pgoff = 0x22000, .maj = 0xfd, .min = 0, .ino = 0x1e028a, .ino_generation = 0xd5947787, .prot = 0x5, .flags = 0x1002, .filename = "/usr/lib64/libc-2.29.so", }, { .header = { .type = PERF_RECORD_SAMPLE, .misc = 0x4002, .size = 0x28, }, .array = { 0x7f53040d7281, 0x7e5000007e50, 0x190aac32ee484, 0x31f6d }, }, { .header = { .type = PERF_RECORD_SAMPLE, .misc = 0x4002, .size = 0x28, }, .array = { 0x7f5304011e55, 0x7e5000007e50, 0x190aac331dd50, 0x34455 }, }, { .type = PERF_RECORD_EXIT, .misc = 0, .size = 0x30, }, { .type = 0x44, .misc = 0, .size = 0x8, }, $ Should work with --count, --skip and filtering by type, lets see, lets show just two PERF_RECORD_CGROUP records, but skip the first: $ pahole -F btf \ --header=perf_file_header \ --seek_bytes='$header.data.offset' \ -C 'perf_event_header(sizeof=size,type=type,type_enum=perf_event_type,filter=type==PERF_RECORD_CGROUP)' \ --size_bytes='$header.data.size' --skip 1 --count 2 ~/bin/perf < perf.data { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x30, }, .id = 0x611, .path = "/system.slice", }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x30, }, .id = 0x8, .path = "/machine.slice", }, $ Well, this works even without -size_bytes, but if we ask for the first 500 records, skipping the first, then --size_bytes will avoid processing things outside the 'struct perf_event_header' range: $ pahole -F btf \ --header=perf_file_header \ --seek_bytes='$header.data.offset' \ -C 'perf_event_header(sizeof=size,type=type,type_enum=perf_event_type,filter=type==PERF_RECORD_CGROUP)' \ --size_bytes='$header.data.size' --skip 1 --count 500 ~/bin/perf < perf.data { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x30, }, .id = 0x611, .path = "/system.slice", }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x30, }, .id = 0x8, .path = "/machine.slice", }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x80, }, .id = 0x1e94, .path = "/machine.slice/libpod-42be8e8d4eb9d22405845005f0d04ea398548dccc934a150fbaa3c1f1f9492c2.scope", }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x58, }, .id = 0xd, .path = "/machine.slice/machine-qemu\x2d1\x2drhel6.sandy.scope", }, $ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-07-20 14:27:10 +02:00
* @size_bytes - Number of bytes to read, similar to seek_bytes, and when both are in place, first seek seek_bytes then read size_bytes
* @range - data structure field in --header to determine --seek_bytes and --size_bytes, must have 'offset' and 'size' fields
* @flat_arrays - a->foo[10][2] becomes a->foo[20]
* @classes_as_structs - class f becomes struct f, CTF doesn't have a "class"
dwarves_fprintf: Fixup cacheline boundary printing on expanded structs A diff for 'pahole -EC task_struct vmlinux' should clarify what this fixes: [acme@jouet linux]$ diff -u /tmp/before.c /tmp/after.c | head -30 --- /tmp/before.c 2016-06-29 17:00:38.082647281 -0300 +++ /tmp/a.c 2016-06-29 17:03:36.913124779 -0300 @@ -43,8 +43,8 @@ struct list_head * prev; /* 176 8 */ } group_node; /* 168 16 */ unsigned int on_rq; /* 184 4 */ + /* --- cacheline 3 boundary (192 bytes) --- */ /* typedef u64 */ long long unsigned int exec_start; /* 192 8 */ - /* --- cacheline 1 boundary (64 bytes) was 4 bytes ago --- */ /* typedef u64 */ long long unsigned int sum_exec_runtime; /* 200 8 */ /* typedef u64 */ long long unsigned int vruntime; /* 208 8 */ /* typedef u64 */ long long unsigned int prev_sum_exec_runtime; /* 216 8 */ @@ -53,40 +53,40 @@ /* typedef u64 */ long long unsigned int wait_start; /* 232 8 */ /* typedef u64 */ long long unsigned int wait_max; /* 240 8 */ /* typedef u64 */ long long unsigned int wait_count; /* 248 8 */ + /* --- cacheline 4 boundary (256 bytes) --- */ /* typedef u64 */ long long unsigned int wait_sum; /* 256 8 */ /* typedef u64 */ long long unsigned int iowait_count; /* 264 8 */ /* typedef u64 */ long long unsigned int iowait_sum; /* 272 8 */ /* typedef u64 */ long long unsigned int sleep_start; /* 280 8 */ /* typedef u64 */ long long unsigned int sleep_max; /* 288 8 */ - /* --- cacheline 1 boundary (64 bytes) --- */ /* typedef s64 */ long long int sum_sleep_runtime; /* 296 8 */ /* typedef u64 */ long long unsigned int block_start; /* 304 8 */ /* typedef u64 */ long long unsigned int block_max; /* 312 8 */ + /* --- cacheline 5 boundary (320 bytes) --- */ /* typedef u64 */ long long unsigned int exec_max; /* 320 8 */ /* typedef u64 */ long long unsigned int slice_max; /* 328 8 */ /* typedef u64 */ long long unsigned int nr_migrations_cold; /* 336 8 */ [acme@jouet linux]$ I.e. the boundary detection was being reset at each expanded struct, do the math globally, using the member offset, that was already done globally and correctly. Reported-and-Tested-by: Peter Zijlstra <peterz@infradead.org> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2016-06-29 22:27:51 +02:00
* @cachelinep - pointer to current cacheline, so that when expanding types we keep track of it,
* needs to be "global", i.e. not set at each recursion.
* @suppress_force_paddings: This makes sense only if the debugging format has struct alignment information,
* So allow for it to be disabled and disable it automatically for things like BTF,
* that don't have such info.
*/
struct conf_fprintf {
const char *prefix;
const char *suffix;
int32_t type_spacing;
int32_t name_spacing;
uint32_t base_offset;
uint32_t count;
dwarves_fprintf: Fixup cacheline boundary printing on expanded structs A diff for 'pahole -EC task_struct vmlinux' should clarify what this fixes: [acme@jouet linux]$ diff -u /tmp/before.c /tmp/after.c | head -30 --- /tmp/before.c 2016-06-29 17:00:38.082647281 -0300 +++ /tmp/a.c 2016-06-29 17:03:36.913124779 -0300 @@ -43,8 +43,8 @@ struct list_head * prev; /* 176 8 */ } group_node; /* 168 16 */ unsigned int on_rq; /* 184 4 */ + /* --- cacheline 3 boundary (192 bytes) --- */ /* typedef u64 */ long long unsigned int exec_start; /* 192 8 */ - /* --- cacheline 1 boundary (64 bytes) was 4 bytes ago --- */ /* typedef u64 */ long long unsigned int sum_exec_runtime; /* 200 8 */ /* typedef u64 */ long long unsigned int vruntime; /* 208 8 */ /* typedef u64 */ long long unsigned int prev_sum_exec_runtime; /* 216 8 */ @@ -53,40 +53,40 @@ /* typedef u64 */ long long unsigned int wait_start; /* 232 8 */ /* typedef u64 */ long long unsigned int wait_max; /* 240 8 */ /* typedef u64 */ long long unsigned int wait_count; /* 248 8 */ + /* --- cacheline 4 boundary (256 bytes) --- */ /* typedef u64 */ long long unsigned int wait_sum; /* 256 8 */ /* typedef u64 */ long long unsigned int iowait_count; /* 264 8 */ /* typedef u64 */ long long unsigned int iowait_sum; /* 272 8 */ /* typedef u64 */ long long unsigned int sleep_start; /* 280 8 */ /* typedef u64 */ long long unsigned int sleep_max; /* 288 8 */ - /* --- cacheline 1 boundary (64 bytes) --- */ /* typedef s64 */ long long int sum_sleep_runtime; /* 296 8 */ /* typedef u64 */ long long unsigned int block_start; /* 304 8 */ /* typedef u64 */ long long unsigned int block_max; /* 312 8 */ + /* --- cacheline 5 boundary (320 bytes) --- */ /* typedef u64 */ long long unsigned int exec_max; /* 320 8 */ /* typedef u64 */ long long unsigned int slice_max; /* 328 8 */ /* typedef u64 */ long long unsigned int nr_migrations_cold; /* 336 8 */ [acme@jouet linux]$ I.e. the boundary detection was being reset at each expanded struct, do the math globally, using the member offset, that was already done globally and correctly. Reported-and-Tested-by: Peter Zijlstra <peterz@infradead.org> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2016-06-29 22:27:51 +02:00
uint32_t *cachelinep;
pahole: Add support for referencing header variables when pretty printing To know from where to start reading some variable sized type we need some information from a domain specific tool such as 'perf report -D' for perf.data files, i.e.: $ perf report -D -i perf.data # To display the perf.data header info, please use --header/--header-only options. # 0x130 [0x20]: event: 79 . . ... raw event: size 32 bytes . 0000: 4f 00 00 00 00 00 20 00 1f 00 00 00 00 00 00 00 O..... ......... . 0010: 31 30 9b 3c 00 00 00 00 2e 53 f8 0c 52 8c 01 00 10.<.....S<F8>.R... 0 0x130 [0x20]: PERF_RECORD_TIME_CONV: unhandled! So we see that 0x130 is where the first PERF_RECORD_* event is located, and we can use that with --seek_bytes and with some extra info we can decode variable sized records: $ pahole --seek_bytes=0x130 -C 'perf_event_header(sizeof=size,type=type,type_enum=perf_event_type)' --skip 2 --count 3 ~/bin/perf < perf.data { .type = 0x4a, .misc = 0, .size = 0x20, }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x28, }, .id = 0x1, .path = "/", }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x30, }, .id = 0x611, .path = "/system.slice", }, $ But if we decode the perf.data file header: $ pahole ~/bin/perf -C perf_file_header --count 1 < perf.data { .magic = 0x32454c4946524550, .size = 0x68, .attr_size = 0x88, .attrs = { .offset = 0xa8, .size = 0x88, }, .data = { .offset = 0x130, .size = 0x588, }, .event_types = { .offset = 0, .size = 0, }, .adds_features = { 0x16717ffc, 0, 0, 0 }, }, $ We see that that 0x130 offset is at field perf_file_header->data.offset, so lets automate this so that we can try to extract that value and then use it with --seek_bytes: $ pahole --header=perf_file_header --seek_bytes='$header.data.offset' -C 'perf_event_header(sizeof=size,type=type,type_enum=perf_event_type)' --skip 2 --count 3 ~/bin/perf < perf.data pahole: the type enum 'perf_event_type' wasn't found in 'util/header.c' $ The problem here is that pahole tries to avoid processing all the CUs (compile units) in a binary, as, so far, it only needed to process one main type at a time, i.e. the ones in -C/--class. Now we need multiple types, in the above example we need: struct perf_event_header struct pref_file_header enum perf_event_type And in this case, the perf binary doesn't have any object/CU that has all these three types. To see if the code works we can resort to using BTF, that combines all types into just one "CU", deduplicating them in the process, so: $ pahole --btf_encode ~/bin/perf And now it works: $ pahole -V -F btf --header=perf_file_header --seek_bytes='$header.data.offset' -C 'perf_event_header(sizeof=size,type=type,type_enum=perf_event_type)' --skip 2 --count 3 ~/bin/perf < perf.data pahole: sizeof_operator for 'perf_event_header' is 'size' pahole: type member for 'perf_event_header' is 'type' pahole: type enum for 'perf_event_header' is 'perf_event_type' pahole: seek bytes evaluated from --seek_bytes=$header.data.offset is 0x130 { .type = 0x4a, .misc = 0, .size = 0x20, }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x28, }, .id = 0x1, .path = "/", }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x30, }, .id = 0x611, .path = "/system.slice", }, $ In the next csets a fallback approach will allow for this to work even with DWARF, when we'll notice that stdin wasn't consumed and thus we need to search for the types needed with cus__find_struct_by_name() & friends. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-07-20 13:25:45 +02:00
const char *seek_bytes;
pahole: Add support for --size_bytes, accepts header variables Last magic number elliminated for the printing of 'struct perf_event_header' variable sized records as found in perf.data files. Now its possible to state when to stop processing, and do that based on fields in the header, i.e., for perf.data files we have: $ pahole ~/bin/perf -C perf_file_header --count 1 < perf.data { .magic = 0x32454c4946524550, .size = 0x68, .attr_size = 0x88, .attrs = { .offset = 0xa8, .size = 0x88, }, .data = { .offset = 0x130, .size = 0x588, }, .event_types = { .offset = 0, .size = 0, }, .adds_features = { 0x16717ffc, 0, 0, 0 }, }, $ So we want to start at header->data.offset and stop processing after event->data.size bytes, we can do it as naturally as: $ pahole -V -F btf \ --header=perf_file_header \ --seek_bytes='$header.data.offset' \ -C 'perf_event_header(sizeof=size,type=type,type_enum=perf_event_type)' \ --size_bytes='$header.data.size' ~/bin/perf < perf.data pahole: sizeof_operator for 'perf_event_header' is 'size' pahole: type member for 'perf_event_header' is 'type' pahole: type enum for 'perf_event_header' is 'perf_event_type' pahole: seek bytes evaluated from --seek_bytes=$header.data.offset is 0x130 pahole: size bytes evaluated from --size_bytes=$header.data.size is 0x588 { .type = 0x4f, .misc = 0, .size = 0x20, }, { .type = 0x49, .misc = 0, .size = 0x28, }, { .type = 0x4a, .misc = 0, .size = 0x20, }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x28, }, .id = 0x1, .path = "/", }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x30, }, .id = 0x611, .path = "/system.slice", }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x30, }, .id = 0x8, .path = "/machine.slice", }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x80, }, .id = 0x1e94, .path = "/machine.slice/libpod-42be8e8d4eb9d22405845005f0d04ea398548dccc934a150fbaa3c1f1f9492c2.scope", }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x58, }, .id = 0xd, .path = "/machine.slice/machine-qemu\x2d1\x2drhel6.sandy.scope", }, { .header = { .type = PERF_RECORD_COMM, .misc = 0, .size = 0x28, }, .pid = 0x7e50, .tid = 0x7e50, .comm = "perf", }, { .header = { .type = PERF_RECORD_COMM, .misc = 0x2000, .size = 0x28, }, .pid = 0x7e50, .tid = 0x7e50, .comm = "sleep", }, { .header = { .type = PERF_RECORD_MMAP2, .misc = 0x2, .size = 0x68, }, .pid = 0x7e50, .tid = 0x7e50, .start = 0x55ea2a865000, .len = 0x4000, .pgoff = 0x2000, .maj = 0xfd, .min = 0, .ino = 0x1e0526, .ino_generation = 0xc97273c3, .prot = 0x5, .flags = 0x1802, .filename = "/usr/bin/sleep", }, { .header = { .type = PERF_RECORD_MMAP2, .misc = 0x2, .size = 0x70, }, .pid = 0x7e50, .tid = 0x7e50, .start = 0x7f53040c7000, .len = 0x20000, .pgoff = 0x1000, .maj = 0xfd, .min = 0, .ino = 0x1e1faf, .ino_generation = 0x83ee2ed3, .prot = 0x5, .flags = 0x1802, .filename = "/usr/lib64/ld-2.29.so", }, { .header = { .type = PERF_RECORD_MMAP2, .misc = 0x2, .size = 0x60, }, .pid = 0x7e50, .tid = 0x7e50, .start = 0x7fffd8b69000, .len = 0x2000, .pgoff = 0, .maj = 0, .min = 0, .ino = 0, .ino_generation = 0, .prot = 0x5, .flags = 0x1002, .filename = "[vdso]", }, { .header = { .type = PERF_RECORD_SAMPLE, .misc = 0x4001, .size = 0x28, }, .array = { 0xffffffff88c00b27, 0x7e5000007e50, 0x190aac32b3544, 0x1 }, }, { .header = { .type = PERF_RECORD_SAMPLE, .misc = 0x4001, .size = 0x28, }, .array = { 0xffffffff88c00b27, 0x7e5000007e50, 0x190aac32b4a90, 0x1 }, }, { .header = { .type = PERF_RECORD_SAMPLE, .misc = 0x4001, .size = 0x28, }, .array = { 0xffffffff88c00b27, 0x7e5000007e50, 0x190aac32b57c8, 0x6 }, }, { .header = { .type = PERF_RECORD_SAMPLE, .misc = 0x4001, .size = 0x28, }, .array = { 0xffffffff88c00b27, 0x7e5000007e50, 0x190aac32b644b, 0x3a }, }, { .header = { .type = PERF_RECORD_SAMPLE, .misc = 0x4001, .size = 0x28, }, .array = { 0xffffffff88c00b27, 0x7e5000007e50, 0x190aac32b7279, 0x266 }, }, { .header = { .type = PERF_RECORD_SAMPLE, .misc = 0x4001, .size = 0x28, }, .array = { 0xffffffff88c00b27, 0x7e5000007e50, 0x190aac32b97c7, 0x16cd }, }, { .header = { .type = PERF_RECORD_SAMPLE, .misc = 0x4002, .size = 0x28, }, .array = { 0x7f53040c814b, 0x7e5000007e50, 0x190aac32bc2b8, 0x5f03 }, }, { .header = { .type = PERF_RECORD_SAMPLE, .misc = 0x4002, .size = 0x28, }, .array = { 0x7f53040dd5af, 0x7e5000007e50, 0x190aac32c1af2, 0x16141 }, }, { .header = { .type = PERF_RECORD_MMAP2, .misc = 0x2, .size = 0x70, }, .pid = 0x7e50, .tid = 0x7e50, .start = 0x7f5303efe000, .len = 0x14d000, .pgoff = 0x22000, .maj = 0xfd, .min = 0, .ino = 0x1e028a, .ino_generation = 0xd5947787, .prot = 0x5, .flags = 0x1002, .filename = "/usr/lib64/libc-2.29.so", }, { .header = { .type = PERF_RECORD_SAMPLE, .misc = 0x4002, .size = 0x28, }, .array = { 0x7f53040d7281, 0x7e5000007e50, 0x190aac32ee484, 0x31f6d }, }, { .header = { .type = PERF_RECORD_SAMPLE, .misc = 0x4002, .size = 0x28, }, .array = { 0x7f5304011e55, 0x7e5000007e50, 0x190aac331dd50, 0x34455 }, }, { .type = PERF_RECORD_EXIT, .misc = 0, .size = 0x30, }, { .type = 0x44, .misc = 0, .size = 0x8, }, $ Should work with --count, --skip and filtering by type, lets see, lets show just two PERF_RECORD_CGROUP records, but skip the first: $ pahole -F btf \ --header=perf_file_header \ --seek_bytes='$header.data.offset' \ -C 'perf_event_header(sizeof=size,type=type,type_enum=perf_event_type,filter=type==PERF_RECORD_CGROUP)' \ --size_bytes='$header.data.size' --skip 1 --count 2 ~/bin/perf < perf.data { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x30, }, .id = 0x611, .path = "/system.slice", }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x30, }, .id = 0x8, .path = "/machine.slice", }, $ Well, this works even without -size_bytes, but if we ask for the first 500 records, skipping the first, then --size_bytes will avoid processing things outside the 'struct perf_event_header' range: $ pahole -F btf \ --header=perf_file_header \ --seek_bytes='$header.data.offset' \ -C 'perf_event_header(sizeof=size,type=type,type_enum=perf_event_type,filter=type==PERF_RECORD_CGROUP)' \ --size_bytes='$header.data.size' --skip 1 --count 500 ~/bin/perf < perf.data { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x30, }, .id = 0x611, .path = "/system.slice", }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x30, }, .id = 0x8, .path = "/machine.slice", }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x80, }, .id = 0x1e94, .path = "/machine.slice/libpod-42be8e8d4eb9d22405845005f0d04ea398548dccc934a150fbaa3c1f1f9492c2.scope", }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x58, }, .id = 0xd, .path = "/machine.slice/machine-qemu\x2d1\x2drhel6.sandy.scope", }, $ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-07-20 14:27:10 +02:00
const char *size_bytes;
pahole: Add support for referencing header variables when pretty printing To know from where to start reading some variable sized type we need some information from a domain specific tool such as 'perf report -D' for perf.data files, i.e.: $ perf report -D -i perf.data # To display the perf.data header info, please use --header/--header-only options. # 0x130 [0x20]: event: 79 . . ... raw event: size 32 bytes . 0000: 4f 00 00 00 00 00 20 00 1f 00 00 00 00 00 00 00 O..... ......... . 0010: 31 30 9b 3c 00 00 00 00 2e 53 f8 0c 52 8c 01 00 10.<.....S<F8>.R... 0 0x130 [0x20]: PERF_RECORD_TIME_CONV: unhandled! So we see that 0x130 is where the first PERF_RECORD_* event is located, and we can use that with --seek_bytes and with some extra info we can decode variable sized records: $ pahole --seek_bytes=0x130 -C 'perf_event_header(sizeof=size,type=type,type_enum=perf_event_type)' --skip 2 --count 3 ~/bin/perf < perf.data { .type = 0x4a, .misc = 0, .size = 0x20, }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x28, }, .id = 0x1, .path = "/", }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x30, }, .id = 0x611, .path = "/system.slice", }, $ But if we decode the perf.data file header: $ pahole ~/bin/perf -C perf_file_header --count 1 < perf.data { .magic = 0x32454c4946524550, .size = 0x68, .attr_size = 0x88, .attrs = { .offset = 0xa8, .size = 0x88, }, .data = { .offset = 0x130, .size = 0x588, }, .event_types = { .offset = 0, .size = 0, }, .adds_features = { 0x16717ffc, 0, 0, 0 }, }, $ We see that that 0x130 offset is at field perf_file_header->data.offset, so lets automate this so that we can try to extract that value and then use it with --seek_bytes: $ pahole --header=perf_file_header --seek_bytes='$header.data.offset' -C 'perf_event_header(sizeof=size,type=type,type_enum=perf_event_type)' --skip 2 --count 3 ~/bin/perf < perf.data pahole: the type enum 'perf_event_type' wasn't found in 'util/header.c' $ The problem here is that pahole tries to avoid processing all the CUs (compile units) in a binary, as, so far, it only needed to process one main type at a time, i.e. the ones in -C/--class. Now we need multiple types, in the above example we need: struct perf_event_header struct pref_file_header enum perf_event_type And in this case, the perf binary doesn't have any object/CU that has all these three types. To see if the code works we can resort to using BTF, that combines all types into just one "CU", deduplicating them in the process, so: $ pahole --btf_encode ~/bin/perf And now it works: $ pahole -V -F btf --header=perf_file_header --seek_bytes='$header.data.offset' -C 'perf_event_header(sizeof=size,type=type,type_enum=perf_event_type)' --skip 2 --count 3 ~/bin/perf < perf.data pahole: sizeof_operator for 'perf_event_header' is 'size' pahole: type member for 'perf_event_header' is 'type' pahole: type enum for 'perf_event_header' is 'perf_event_type' pahole: seek bytes evaluated from --seek_bytes=$header.data.offset is 0x130 { .type = 0x4a, .misc = 0, .size = 0x20, }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x28, }, .id = 0x1, .path = "/", }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x30, }, .id = 0x611, .path = "/system.slice", }, $ In the next csets a fallback approach will allow for this to work even with DWARF, when we'll notice that stdin wasn't consumed and thus we need to search for the types needed with cus__find_struct_by_name() & friends. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-07-20 13:25:45 +02:00
const char *header_type;
const char *range;
uint32_t skip;
uint8_t indent;
uint8_t expand_types:1;
uint8_t expand_pointers:1;
uint8_t rel_offset:1;
uint8_t emit_stats:1;
uint8_t suppress_comments:1;
uint8_t has_alignment_info:1;
uint8_t suppress_aligned_attribute:1;
uint8_t suppress_offset_comment:1;
uint8_t suppress_force_paddings:1;
uint8_t suppress_packed:1;
uint8_t show_decl_info:1;
uint8_t show_only_data_members:1;
uint8_t no_semicolon:1;
uint8_t show_first_biggest_size_base_type_member:1;
uint8_t flat_arrays:1;
uint8_t first_member:1;
fprintf: Deal with zero sized arrays in the middle of a struct Consider: struct ipc64_perm { __kernel_key_t key; __kernel_uid32_t uid; __kernel_gid32_t gid; __kernel_uid32_t cuid; __kernel_gid32_t cgid; __kernel_mode_t mode; /* pad if mode_t is u16: */ unsigned char __pad1[4 - sizeof(__kernel_mode_t)]; unsigned short seq; unsigned short __pad2; __kernel_ulong_t __unused1; __kernel_ulong_t __unused2; }; That is a roundabout way of using __attribute__(__aligned__(4)), but should work nonetheless. We were not putting the [0] in that zero sized array which ended up making gcc complain with: $ gcc -g -c shm.c shm.c:199:29: error: flexible array member not at end of struct unsigned char __pad1[]; /* 24 0 */ ^~~~~~ $ Now this works, i.e. generates compilable source code out of the type tags, be it from BTF or from DWARF, i.e. this is all from the internal representation of such types, agnostic wrt the original type format. So, the full circle: $ pahole -C ipc64_perm /home/acme/git/build/v5.1-rc4+/ipc/shm.o struct ipc64_perm { __kernel_key_t key; /* 0 4 */ __kernel_uid32_t uid; /* 4 4 */ __kernel_gid32_t gid; /* 8 4 */ __kernel_uid32_t cuid; /* 12 4 */ __kernel_gid32_t cgid; /* 16 4 */ __kernel_mode_t mode; /* 20 4 */ unsigned char __pad1[0]; /* 24 0 */ short unsigned int seq; /* 24 2 */ short unsigned int __pad2; /* 26 2 */ /* XXX 4 bytes hole, try to pack */ __kernel_ulong_t __unused1; /* 32 8 */ __kernel_ulong_t __unused2; /* 40 8 */ /* size: 48, cachelines: 1, members: 11 */ /* sum members: 44, holes: 1, sum holes: 4 */ /* last cacheline: 48 bytes */ }; $ pfunct --compile /home/acme/git/build/v5.1-rc4+/ipc/shm.o > shm.c $ gcc -g -c shm.c $ pahole -C ipc64_perm shm.o struct ipc64_perm { __kernel_key_t key; /* 0 4 */ __kernel_uid32_t uid; /* 4 4 */ __kernel_gid32_t gid; /* 8 4 */ __kernel_uid32_t cuid; /* 12 4 */ __kernel_gid32_t cgid; /* 16 4 */ __kernel_mode_t mode; /* 20 4 */ unsigned char __pad1[0]; /* 24 0 */ short unsigned int seq; /* 24 2 */ short unsigned int __pad2; /* 26 2 */ /* XXX 4 bytes hole, try to pack */ __kernel_ulong_t __unused1; /* 32 8 */ __kernel_ulong_t __unused2; /* 40 8 */ /* size: 48, cachelines: 1, members: 11 */ /* sum members: 44, holes: 1, sum holes: 4 */ /* last cacheline: 48 bytes */ }; $ And for a chuckle, the original source code with a bit of history about struct layout worries: include/uapi/asm-generic/ipcbuf.h: /* * The generic ipc64_perm structure: * Note extra padding because this structure is passed back and forth * between kernel and user space. * * ipc64_perm was originally meant to be architecture specific, but * everyone just ended up making identical copies without specific * optimizations, so we may just as well all use the same one. * * Pad space is left for: * - 32-bit mode_t on architectures that only had 16 bit * - 32-bit seq * - 2 miscellaneous 32-bit values */ struct ipc64_perm { __kernel_key_t key; __kernel_uid32_t uid; __kernel_gid32_t gid; __kernel_uid32_t cuid; __kernel_gid32_t cgid; __kernel_mode_t mode; /* pad if mode_t is u16: */ unsigned char __pad1[4 - sizeof(__kernel_mode_t)]; unsigned short seq; unsigned short __pad2; __kernel_ulong_t __unused1; __kernel_ulong_t __unused2; }; Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-15 21:33:51 +02:00
uint8_t last_member:1;
uint8_t union_member:1;
uint8_t no_parm_names:1;
uint8_t classes_as_structs:1;
uint8_t hex_fmt:1;
uint8_t strip_inline:1;
};
struct cus;
struct cus *cus__new(void);
void cus__delete(struct cus *cus);
int cus__load_file(struct cus *cus, struct conf_load *conf,
const char *filename);
int cus__load_files(struct cus *cus, struct conf_load *conf,
char *filenames[]);
int cus__fprintf_load_files_err(struct cus *cus, const char *tool,
char *argv[], int err, FILE *output);
int cus__load_dir(struct cus *cus, struct conf_load *conf,
const char *dirname, const char *filename_mask,
const int recursive);
void cus__add(struct cus *cus, struct cu *cu);
void cus__print_error_msg(const char *progname, const struct cus *cus,
const char *filename, const int err);
struct cu *cus__find_pair(struct cus *cus, const char *name);
struct cu *cus__find_cu_by_name(struct cus *cus, const char *name);
struct tag *cus__find_struct_by_name(struct cus *cus, struct cu **cu,
const char *name, const int include_decls,
type_id_t *id);
struct tag *cus__find_struct_or_union_by_name(struct cus *cus, struct cu **cu,
const char *name, const int include_decls, type_id_t *id);
struct tag *cu__find_type_by_name(const struct cu *cu, const char *name, const int include_decls, type_id_t *idp);
struct tag *cus__find_type_by_name(struct cus *cus, struct cu **cu, const char *name,
const int include_decls, type_id_t *id);
struct function *cus__find_function_at_addr(struct cus *cus, uint64_t addr, struct cu **cu);
void cus__for_each_cu(struct cus *cus, int (*iterator)(struct cu *cu, void *cookie),
void *cookie,
struct cu *(*filter)(struct cu *cu));
bool cus__empty(const struct cus *cus);
uint32_t cus__nr_entries(const struct cus *cus);
void cus__lock(struct cus *cus);
void cus__unlock(struct cus *cus);
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
struct ptr_table {
void **entries;
uint32_t nr_entries;
uint32_t allocated_entries;
};
struct function;
struct tag;
struct cu;
struct variable;
/* Same as DW_LANG, so that we don't have to include dwarf.h in CTF */
enum dwarf_languages {
LANG_C89 = 0x01, /* ISO C:1989 */
LANG_C = 0x02, /* C */
LANG_Ada83 = 0x03, /* ISO Ada:1983 */
LANG_C_plus_plus = 0x04, /* ISO C++:1998 */
LANG_Cobol74 = 0x05, /* ISO Cobol:1974 */
LANG_Cobol85 = 0x06, /* ISO Cobol:1985 */
LANG_Fortran77 = 0x07, /* ISO FORTRAN 77 */
LANG_Fortran90 = 0x08, /* ISO Fortran 90 */
LANG_Pascal83 = 0x09, /* ISO Pascal:1983 */
LANG_Modula2 = 0x0a, /* ISO Modula-2:1996 */
LANG_Java = 0x0b, /* Java */
LANG_C99 = 0x0c, /* ISO C:1999 */
LANG_Ada95 = 0x0d, /* ISO Ada:1995 */
LANG_Fortran95 = 0x0e, /* ISO Fortran 95 */
LANG_PL1 = 0x0f, /* ISO PL/1:1976 */
LANG_Objc = 0x10, /* Objective-C */
LANG_ObjC_plus_plus = 0x11, /* Objective-C++ */
LANG_UPC = 0x12, /* Unified Parallel C */
LANG_D = 0x13, /* D */
};
/** struct debug_fmt_ops - specific to the underlying debug file format
*
* cu__delete - called at cu__delete(), to give a chance to formats such as
* CTF to keep the .strstab ELF section available till the cu is
* deleted.
*/
struct debug_fmt_ops {
const char *name;
int (*init)(void);
void (*exit)(void);
int (*load_file)(struct cus *cus,
struct conf_load *conf,
const char *filename);
const char *(*tag__decl_file)(const struct tag *tag,
const struct cu *cu);
uint32_t (*tag__decl_line)(const struct tag *tag,
const struct cu *cu);
unsigned long long (*tag__orig_id)(const struct tag *tag,
const struct cu *cu);
void (*tag__free_orig_info)(struct tag *tag,
struct cu *cu);
void (*cu__delete)(struct cu *cu);
bool has_alignment_info;
};
extern struct debug_fmt_ops *dwarves__active_loader;
struct cu {
struct list_head node;
struct list_head tags;
struct list_head tool_list; /* To be used by tools such as ctracer */
struct ptr_table types_table;
struct ptr_table functions_table;
struct ptr_table tags_table;
struct rb_root functions;
char *name;
char *filename;
void *priv;
struct debug_fmt_ops *dfops;
Elf *elf;
Dwfl_Module *dwfl;
uint32_t cached_symtab_nr_entries;
uint8_t addr_size;
uint8_t extra_dbg_info:1;
dwarves: Allow avoiding loading addr information As, for instance, pahole doesn't need it at all. Down from: [acme@doppio pahole]$ perf stat -r 5 pahole object_samples/zweinberg\@mozilla.com/libgklayout.so > /dev/null Performance counter stats for 'pahole object_samples/zweinberg@mozilla.com/libgklayout.so' (5 runs): 17233.989563 task-clock-msecs # 0.994 CPUs ( +- 0.076% ) 1880 context-switches # 0.000 M/sec ( +- 0.159% ) 0 CPU-migrations # 0.000 M/sec ( +- 0.000% ) 26248 page-faults # 0.002 M/sec ( +- 0.000% ) 34244461105 cycles # 1987.030 M/sec ( +- 0.078% ) 34510583834 instructions # 1.008 IPC ( +- 0.001% ) 445937867 cache-references # 25.875 M/sec ( +- 0.160% ) 56898165 cache-misses # 3.302 M/sec ( +- 0.074% ) 17.335292038 seconds time elapsed ( +- 0.076% ) [acme@doppio pahole]$ To: [acme@doppio pahole]$ perf stat -r 5 pahole object_samples/zweinberg\@mozilla.com/libgklayout.so > /dev/null Performance counter stats for 'pahole object_samples/zweinberg@mozilla.com/libgklayout.so' (5 runs): 16511.627334 task-clock-msecs # 0.992 CPUs ( +- 0.208% ) 1922 context-switches # 0.000 M/sec ( +- 3.068% ) 0 CPU-migrations # 0.000 M/sec ( +- 0.000% ) 25570 page-faults # 0.002 M/sec ( +- 0.000% ) 32807624343 cycles # 1986.941 M/sec ( +- 0.208% ) 32711598374 instructions # 0.997 IPC ( +- 0.001% ) 436345377 cache-references # 26.427 M/sec ( +- 0.178% ) 54044997 cache-misses # 3.273 M/sec ( +- 0.685% ) 16.652951166 seconds time elapsed ( +- 0.304% ) [acme@doppio pahole]$ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-07-06 18:44:57 +02:00
uint8_t has_addr_info:1;
uint8_t uses_global_strings:1;
uint8_t little_endian:1;
uint16_t language;
unsigned long nr_inline_expansions;
size_t size_inline_expansions;
uint32_t nr_functions_changed;
uint32_t nr_structures_changed;
size_t max_len_changed_item;
size_t function_bytes_added;
size_t function_bytes_removed;
int build_id_len;
unsigned char build_id[0];
};
struct cu *cu__new(const char *name, uint8_t addr_size,
const unsigned char *build_id, int build_id_len,
const char *filename);
void cu__delete(struct cu *cu);
static inline int cu__cache_symtab(struct cu *cu)
{
int err = dwfl_module_getsymtab(cu->dwfl);
if (err > 0)
cu->cached_symtab_nr_entries = dwfl_module_getsymtab(cu->dwfl);
return err;
}
static inline __pure bool cu__is_c_plus_plus(const struct cu *cu)
{
return cu->language == LANG_C_plus_plus;
}
/**
* cu__for_each_cached_symtab_entry - iterate thru the cached symtab entries
* @cu: struct cu instance
* @id: uint32_t tag id
* @pos: struct GElf_Sym iterator
* @name: char pointer where the symbol_name will be stored
*/
#define cu__for_each_cached_symtab_entry(cu, id, pos, name) \
for (id = 1, \
name = dwfl_module_getsym(cu->dwfl, id, &sym, NULL); \
id < cu->cached_symtab_nr_entries; \
++id, name = dwfl_module_getsym(cu->dwfl, id, &sym, 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
/**
* cu__for_each_type - iterate thru all the type tags
* @cu: struct cu instance to iterate
* @id: type_id_t id
* @pos: struct tag iterator
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
*
* See cu__table_nullify_type_entry and users for the reason for
* the NULL test (hint: CTF Unknown types)
*/
#define cu__for_each_type(cu, id, pos) \
for (id = 1; id < cu->types_table.nr_entries; ++id) \
if (!(pos = cu->types_table.entries[id])) \
dwarves: Remove some more DWARF details from the core Had to be a big sweeping change, but the regression tests shows just improvements :-) Now we stop using an id in struct tag, only storing the type, that now uses 16 bits only, as CTF does. Each format loader has to go on adding the types to the core, that figures out if it is a tag that can be on the tag->type field (tag__is_tag_type). Formats that already have the types separated and in sequence, such as CTF, just ask the core to insert in the types_table directly with its original ID. For DWARF, we ask the core to put it on the table, in sequence, and return the index, that is then stashed with the DWARF specific info (original id, type, decl_line, etc) and hashed by the original id. Later we recode everything, looking up via the original type, getting the small_id to put on the tag->type. The underlying debugging info not needed by the core is stashed in tag->priv, and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of the core tag and points it there, and makes that info available thru cu->orig_info. In the future we can ask, when loading a cu, that this info be trown away, so that we reduce the memory footprint for big multi-cu files such as the Linux kernel. There is also a routine to ask for inserting a NULL, as we still have bugs in the CTF decoding and thus some entries are being lost, to avoid using an undefined pointer when traversing the types_table the ctf loader puts a NULL there via cu__table_nullify_type_entry() and then cu__for_each_type skips those. There is some more cleanups for leftovers that I avoided cleaning to reduce this changeset. And also while doing this I saw that enums can appear without any enumerators and that an array with DW_TAG_GNU_vector is actually a different tag, encoded this way till we get to DWARF4 ;-) So now we don't have to lookup on a hash table looking for DWARF offsets, we can do the more sensible thing of just indexing the types_tags array. Now to do some cleanups and try to get the per cu encoder done. Then order all the cus per number of type entries, pick the one with more, then go on merging/recoding the types of the others and putting the parent linkage in place. Just to show the extent of the changes: $ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0 /home/acme/git/pahole/dwarves.c: struct cu | -4048 struct tag | -32 struct ptr_to_member_type | -32 struct namespace | -32 struct type | -32 struct class | -32 struct base_type | -32 struct array_type | -32 struct class_member | -32 struct lexblock | -32 struct ftype | -32 struct function | -64 struct parameter | -32 struct variable | -32 struct inline_expansion | -32 struct label | -32 struct enumerator | -32 17 structs changed tag__follow_typedef | +3 tag__fprintf_decl_info | +25 array_type__fprintf | +6 type__name | -126 type__find_first_biggest_size_base_type_member | -3 typedef__fprintf | +16 imported_declaration__fprintf | +6 imported_module__fprintf | +3 cu__new | +26 cu__delete | +26 hashtags__hash | -65 hash_64 | -124 hlist_add_head | -78 hashtags__find | -157 cu__hash | -80 cu__add_tag | +20 tag__prefix | -3 cu__find_tag_by_id | -2 cu__find_type_by_id | -3 cu__find_first_typedef_of_type | +38 cu__find_base_type_by_name | +68 cu__find_base_type_by_name_and_size | +72 cu__find_struct_by_name | +59 cus__find_struct_by_name | +8 cus__find_tag_by_id | +5 cus__find_cu_by_name | -6 lexblock__find_tag_by_id | -173 cu__find_variable_by_id | -197 list__find_tag_by_id | -308 cu__find_parameter_by_id | -60 tag__ptr_name | +6 tag__name | +15 variable__type | +13 variable__name | +7 class_member__size | +6 parameter__name | -119 tag__parameter | -14 parameter__type | -143 type__fprintf | -29 union__fprintf | +6 class__add_vtable_entry | -9 type__add_member | -6 type__clone_members | -3 enumeration__add | -6 function__name | -156 ftype__has_parm_of_type | -39 class__find_holes | -27 class__has_hole_ge | -3 type__nr_members_of_type | +3 lexblock__account_inline_expansions | +3 cu__account_inline_expansions | -18 ftype__fprintf_parms | +46 function__tag_fprintf | +24 lexblock__fprintf | -6 ftype__fprintf | +3 function__fprintf_stats | -18 function__size | -6 class__vtable_fprintf | -11 class__fprintf | -21 tag__fprintf | -35 60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541 /home/acme/git/pahole/ctf_loader.c: struct ctf_short_type | +0 14 structs changed type__init | -14 type__new | -9 class__new | -12 create_new_base_type | -7 create_new_base_type_float | -7 create_new_array | -8 create_new_subroutine_type | -9 create_full_members | -18 create_short_members | -18 create_new_class | +1 create_new_union | +1 create_new_enumeration | -19 create_new_forward_decl | -2 create_new_typedef | +3 create_new_tag | -5 load_types | +16 class__fixup_ctf_bitfields | -3 17 functions changed, 21 bytes added, 131 bytes removed, diff: -110 /home/acme/git/pahole/dwarf_loader.c: 17 structs changed zalloc | -56 tag__init | +3 array_type__new | +20 type__init | -24 class_member__new | +46 inline_expansion__new | +12 class__new | +81 lexblock__init | +19 function__new | +43 die__create_new_array | +20 die__create_new_parameter | +4 die__create_new_label | +4 die__create_new_subroutine_type | +113 die__create_new_enumeration | -21 die__process_class | +79 die__process_namespace | +76 die__create_new_inline_expansion | +4 die__process_function | +147 __die__process_tag | +34 die__process_unit | +56 die__process | +90 21 functions changed, 851 bytes added, 101 bytes removed, diff: +750 /home/acme/git/pahole/dwarves.c: struct ptr_table | +16 struct cu_orig_info | +32 2 structs changed tag__decl_line | +68 tag__decl_file | +70 tag__orig_id | +71 ptr_table__init | +46 ptr_table__exit | +37 ptr_table__add | +183 ptr_table__add_with_id | +165 ptr_table__entry | +64 cu__table_add_tag | +171 cu__table_nullify_type_entry | +38 10 functions changed, 913 bytes added, diff: +913 /home/acme/git/pahole/ctf_loader.c: 2 structs changed tag__alloc | +52 1 function changed, 52 bytes added, diff: +52 /home/acme/git/pahole/dwarf_loader.c: struct dwarf_tag | +48 struct dwarf_cu | +4104 4 structs changed dwarf_cu__init | +83 hashtags__hash | +61 hash_64 | +124 hlist_add_head | +78 hashtags__find | +161 cu__hash | +95 tag__is_tag_type | +171 tag__is_type | +85 tag__is_union | +28 tag__is_struct | +57 tag__is_typedef | +28 tag__is_enumeration | +28 dwarf_cu__find_tag_by_id | +56 dwarf_cu__find_type_by_id | +63 tag__alloc | +114 __tag__print_type_not_found | +108 namespace__recode_dwarf_types | +346 tag__namespace | +14 tag__has_namespace | +86 tag__is_namespace | +28 type__recode_dwarf_specification | +182 tag__type | +14 __tag__print_abstract_origin_not_found | +105 ftype__recode_dwarf_types | +322 tag__ftype | +14 tag__parameter | +14 lexblock__recode_dwarf_types | +736 tag__lexblock | +14 tag__label | +14 tag__recode_dwarf_type | +766 tag__ptr_to_member_type | +14 cu__recode_dwarf_types_table | +88 cu__recode_dwarf_types | +48 dwarf_tag__decl_file | +77 strings__ptr | +33 dwarf_tag__decl_line | +59 dwarf_tag__orig_id | +59 dwarf_tag__orig_type | +59 38 functions changed, 4432 bytes added, diff: +4432 build/libdwarves.so.1.0.0: 147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496 Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
continue; \
else
/**
* cu__for_each_struct - iterate thru all the struct tags
* @cu: struct cu instance to iterate
* @pos: struct class iterator
* @id: type_id_t id
*/
#define cu__for_each_struct(cu, id, pos) \
for (id = 1; id < cu->types_table.nr_entries; ++id) \
if (!(pos = tag__class(cu->types_table.entries[id])) || \
!tag__is_struct(class__tag(pos))) \
continue; \
else
/**
* cu__for_each_struct_or_union - iterate thru all the struct and union tags
* @cu: struct cu instance to iterate
* @pos: struct class iterator
* @id: type_id_t tag id
*/
#define cu__for_each_struct_or_union(cu, id, pos) \
for (id = 1; id < cu->types_table.nr_entries; ++id) \
if (!(pos = tag__class(cu->types_table.entries[id])) || \
!(tag__is_struct(class__tag(pos)) || \
tag__is_union(class__tag(pos)))) \
continue; \
else
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__for_each_function - iterate thru all the function tags
* @cu: struct cu instance to iterate
* @pos: struct function iterator
* @id: uint32_t tag id
*/
#define cu__for_each_function(cu, id, pos) \
for (id = 0; id < cu->functions_table.nr_entries; ++id) \
if (!(pos = tag__function(cu->functions_table.entries[id]))) \
continue; \
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
else
/**
* cu__for_each_variable - iterate thru all the global variable tags
* @cu: struct cu instance to iterate
* @pos: struct tag iterator
* @id: uint32_t tag id
*/
#define cu__for_each_variable(cu, id, pos) \
for (id = 0; id < cu->tags_table.nr_entries; ++id) \
if (!(pos = cu->tags_table.entries[id]) || \
!tag__is_variable(pos)) \
continue; \
else
int cu__add_tag(struct cu *cu, struct tag *tag, uint32_t *id);
int cu__add_tag_with_id(struct cu *cu, struct tag *tag, uint32_t id);
int cu__table_add_tag(struct cu *cu, struct tag *tag, uint32_t *id);
int cu__table_add_tag_with_id(struct cu *cu, struct tag *tag, uint32_t id);
int cu__table_nullify_type_entry(struct cu *cu, uint32_t id);
struct tag *cu__find_base_type_by_name(const struct cu *cu, const char *name,
type_id_t *id);
struct tag *cu__find_base_type_by_name_and_size(const struct cu *cu, const char* name,
uint16_t bit_size, type_id_t *idp);
struct tag *cu__find_enumeration_by_name(const struct cu *cu, const char *name, type_id_t *idp);
struct tag *cu__find_enumeration_by_name_and_size(const struct cu *cu, const char* name,
uint16_t bit_size, type_id_t *idp);
struct tag *cu__find_first_typedef_of_type(const struct cu *cu,
const type_id_t type);
struct tag *cu__find_function_by_name(const struct cu *cu, const char *name);
struct function *cu__find_function_at_addr(const struct cu *cu,
uint64_t addr);
struct tag *cu__function(const struct cu *cu, const uint32_t id);
struct tag *cu__tag(const struct cu *cu, const uint32_t id);
struct tag *cu__type(const struct cu *cu, const type_id_t id);
struct tag *cu__find_struct_by_name(const struct cu *cu, const char *name,
const int include_decls, type_id_t *id);
struct tag *cu__find_struct_or_union_by_name(const struct cu *cu, const char *name,
const int include_decls, type_id_t *id);
bool cu__same_build_id(const struct cu *cu, const struct cu *other);
void cu__account_inline_expansions(struct cu *cu);
int cu__for_all_tags(struct cu *cu,
int (*iterator)(struct tag *tag,
struct cu *cu, void *cookie),
void *cookie);
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
/** struct tag - basic representation of a debug info element
* @priv - extra data, for instance, DWARF offset, id, decl_{file,line}
* @top_level -
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
*/
struct tag {
struct list_head node;
type_id_t type;
[LIB]: Reorganize struct tag Erm, eating my dog food now that I have access to a 64bit machine here at home: [acme@mica pahole]$ pahole build/libdwarves.so.1.0.0 tag /* <b7e> /home/acme/git/pahole/dwarves.h:48 */ struct tag { struct list_head node; /* 0 16 */ Dwarf_Off type; /* 16 8 */ Dwarf_Off id; /* 24 8 */ uint16_t tag; /* 32 2 */ uint16_t decl_line; /* 34 2 */ /* XXX 4 bytes hole, try to pack */ const char * decl_file; /* 40 8 */ uint32_t refcnt; /* 48 4 */ }; /* size: 56, cachelines: 1 */ /* sum members: 48, holes: 1, sum holes: 4 */ /* padding: 4 */ /* last cacheline: 56 bytes */ [acme@mica pahole]$ [acme@mica pahole]$ pahole --reorganize build/libdwarves.so.1.0.0 tag /* <b7e> /home/acme/git/pahole/dwarves.h:48 */ struct tag { struct list_head node; /* 0 16 */ Dwarf_Off type; /* 16 8 */ Dwarf_Off id; /* 24 8 */ uint16_t tag; /* 32 2 */ uint16_t decl_line; /* 34 2 */ uint32_t refcnt; /* 36 4 */ const char * decl_file; /* 40 8 */ }; /* size: 48, cachelines: 1 */ /* last cacheline: 48 bytes */ /* saved 8 bytes! */ [acme@mica pahole]$ [acme@mica pahole]$ codiff build/libdwarves.so.1.0.0.before build/libdwarves.so.1.0.0 /home/acme/git/pahole/dwarves.c: struct tag | -8 struct type | -8 struct class | -8 struct base_type | -8 struct array_type | -8 struct class_member | -8 struct lexblock | -8 struct ftype | -8 struct function | -16 struct parameter | -8 struct variable | -8 struct inline_expansion | -8 struct label | -8 struct enumerator | -8 14 structs changed class_member__clone | -8 class__clone | -8 2 functions changed, 16 bytes removed [acme@mica pahole]$ Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-03-07 16:10:56 +01:00
uint16_t tag;
bool visited;
bool top_level;
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
uint16_t recursivity_level;
void *priv;
};
// To use with things like type->type_enum == perf_event_type+perf_user_event_type
struct tag_cu {
struct tag *tag;
struct cu *cu;
};
void tag__delete(struct tag *tag);
static inline int tag__is_enumeration(const struct tag *tag)
{
return tag->tag == DW_TAG_enumeration_type;
}
static inline int tag__is_namespace(const struct tag *tag)
{
return tag->tag == DW_TAG_namespace;
}
static inline int tag__is_struct(const struct tag *tag)
{
return tag->tag == DW_TAG_structure_type ||
tag->tag == DW_TAG_interface_type ||
tag->tag == DW_TAG_class_type;
}
static inline int tag__is_typedef(const struct tag *tag)
{
return tag->tag == DW_TAG_typedef;
}
static inline int tag__is_rvalue_reference_type(const struct tag *tag)
{
return tag->tag == DW_TAG_rvalue_reference_type;
}
static inline int tag__is_union(const struct tag *tag)
{
return tag->tag == DW_TAG_union_type;
}
static inline int tag__is_const(const struct tag *tag)
{
return tag->tag == DW_TAG_const_type;
}
static inline int tag__is_pointer(const struct tag *tag)
{
return tag->tag == DW_TAG_pointer_type;
}
static inline int tag__is_pointer_to(const struct tag *tag, type_id_t type)
{
return tag__is_pointer(tag) && tag->type == type;
}
static inline bool tag__is_variable(const struct tag *tag)
{
return tag->tag == DW_TAG_variable;
}
static inline bool tag__is_volatile(const struct tag *tag)
{
return tag->tag == DW_TAG_volatile_type;
}
loaders: Strip away volatile/const/restrict when fixing bitfields btf_loader and ctf_loader didn't remove const/volatile/restrict, so bitfields using modifiers were not adjusted properly. This patch abstracts logic of stripping aways typedefs and access modifiers into tag__strip_typedefs_and_modifiers, which handles any interleaving of typedefs and modifiers. dwarf_loader was adapter to reuse this function as well, instead of custom goto loop. REPRO: $ cat vc_map.c typedef unsigned int u32; typedef volatile u32 vu32; typedef vu32 vu32_t; typedef struct vc_map { volatile unsigned int tx: 1; vu32_t rx: 1; void *x1, *x2; } vc_map; int main() { struct vc_map s; return 0; } BEFORE: $ ~/pahole/build/pahole -F btf vc_map struct vc_map { volatile unsigned int tx:1; /* 0: 0 4 */ vu32_t rx:1; /* 0: 0 4 */ /* XXX 30 bits hole, try to pack */ /* XXX 4 bytes hole, try to pack */ void * x1; /* 8 8 */ void * x2; /* 16 8 */ /* size: 24, cachelines: 1, members: 4 */ /* sum members: 20, holes: 1, sum holes: 4 */ /* bit holes: 1, sum bit holes: 30 bits */ /* last cacheline: 24 bytes */ }; AFTER: $ ~/pahole/build/pahole -F btf vc_map struct vc_map { volatile unsigned int tx:1; /* 0:31 4 */ vu32_t rx:1; /* 0:30 4 */ /* XXX 30 bits hole, try to pack */ /* XXX 4 bytes hole, try to pack */ void * x1; /* 8 8 */ void * x2; /* 16 8 */ /* size: 24, cachelines: 1, members: 4 */ /* sum members: 20, holes: 1, sum holes: 4 */ /* bit holes: 1, sum bit holes: 30 bits */ /* last cacheline: 24 bytes */ }; Signed-off-by: Andrii Nakryiko <andriin@fb.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Alexei Starovoitov <ast@fb.com> Cc: Yonghong Song <yhs@fb.com> Cc: bpf@vger.kernel.org Cc: dwarves@vger.kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-03-13 17:53:01 +01:00
static inline bool tag__is_restrict(const struct tag *tag)
{
return tag->tag == DW_TAG_restrict_type;
}
static inline int tag__is_modifier(const struct tag *tag)
{
return tag__is_const(tag) ||
tag__is_volatile(tag) ||
tag__is_restrict(tag);
}
static inline bool tag__has_namespace(const struct tag *tag)
{
return tag__is_struct(tag) ||
tag__is_union(tag) ||
tag__is_namespace(tag) ||
tag__is_enumeration(tag);
}
/**
* tag__is_tag_type - is this tag derived from the 'type' class?
* @tag - tag queried
*/
static inline int tag__is_type(const struct tag *tag)
{
return tag__is_union(tag) ||
tag__is_struct(tag) ||
tag__is_typedef(tag) ||
tag__is_rvalue_reference_type(tag) ||
tag__is_enumeration(tag);
}
/**
* tag__is_tag_type - is this one of the possible types for a tag?
* @tag - tag queried
*/
static inline int tag__is_tag_type(const struct tag *tag)
{
return tag__is_type(tag) ||
tag->tag == DW_TAG_array_type ||
tag->tag == DW_TAG_string_type ||
tag->tag == DW_TAG_base_type ||
tag->tag == DW_TAG_const_type ||
tag->tag == DW_TAG_pointer_type ||
tag->tag == DW_TAG_rvalue_reference_type ||
tag->tag == DW_TAG_ptr_to_member_type ||
tag->tag == DW_TAG_reference_type ||
dwarf_loader: Add support for DW_TAG_restrict_type I.e. supporting the 'restrict' keyword, emitted by recent compilers: [acme@jouet pahole]$ pfunct -P ~/bin/perf |& grep -w restrict inline int vprintf(const char * restrict __fmt, struct __va_list_tag * __ap); inline size_t fread(void * restrict __ptr, size_t __size, size_t __n, FILE * restrict __stream); inline int vfprintf(FILE * restrict __stream, const char * restrict __fmt, struct __va_list_tag * __ap); inline int vasprintf(char * * restrict __ptr, const char * restrict __fmt, struct __va_list_tag * __ap); inline char * realpath(const char * restrict __name, char * restrict __resolved); inline ssize_t readlink(const char * restrict __path, char * restrict __buf, size_t __len); inline char * strcat(char * restrict __dest, const char * restrict __src); inline char * fgets(char * restrict __s, int __n, FILE * restrict __stream); inline int snprintf(char * restrict __s, size_t __n, const char * restrict __fmt, ...); inline int sprintf(char * restrict __s, const char * restrict __fmt, ...); inline char * strcpy(char * restrict __dest, const char * restrict __src); inline int asprintf(char * * restrict __ptr, const char * restrict __fmt, ...); inline char * strncpy(char * restrict __dest, const char * restrict __src, size_t __len); inline int fprintf(FILE * restrict __stream, const char * restrict __fmt, ...); inline int vsnprintf(char * restrict __s, size_t __n, const char * restrict __fmt, struct __va_list_tag * __ap); inline int printf(const char * restrict __fmt, ...); [acme@jouet pahole]$ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2016-05-06 20:02:17 +02:00
tag->tag == DW_TAG_restrict_type ||
tag->tag == DW_TAG_subroutine_type ||
tag->tag == DW_TAG_unspecified_type ||
tag->tag == DW_TAG_volatile_type;
}
static inline const char *tag__decl_file(const struct tag *tag,
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
const struct cu *cu)
{
if (cu->dfops && cu->dfops->tag__decl_file)
return cu->dfops->tag__decl_file(tag, cu);
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
}
static inline uint32_t tag__decl_line(const struct tag *tag,
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
const struct cu *cu)
{
if (cu->dfops && cu->dfops->tag__decl_line)
return cu->dfops->tag__decl_line(tag, cu);
return 0;
dwarves: Remove some more DWARF details from the core Had to be a big sweeping change, but the regression tests shows just improvements :-) Now we stop using an id in struct tag, only storing the type, that now uses 16 bits only, as CTF does. Each format loader has to go on adding the types to the core, that figures out if it is a tag that can be on the tag->type field (tag__is_tag_type). Formats that already have the types separated and in sequence, such as CTF, just ask the core to insert in the types_table directly with its original ID. For DWARF, we ask the core to put it on the table, in sequence, and return the index, that is then stashed with the DWARF specific info (original id, type, decl_line, etc) and hashed by the original id. Later we recode everything, looking up via the original type, getting the small_id to put on the tag->type. The underlying debugging info not needed by the core is stashed in tag->priv, and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of the core tag and points it there, and makes that info available thru cu->orig_info. In the future we can ask, when loading a cu, that this info be trown away, so that we reduce the memory footprint for big multi-cu files such as the Linux kernel. There is also a routine to ask for inserting a NULL, as we still have bugs in the CTF decoding and thus some entries are being lost, to avoid using an undefined pointer when traversing the types_table the ctf loader puts a NULL there via cu__table_nullify_type_entry() and then cu__for_each_type skips those. There is some more cleanups for leftovers that I avoided cleaning to reduce this changeset. And also while doing this I saw that enums can appear without any enumerators and that an array with DW_TAG_GNU_vector is actually a different tag, encoded this way till we get to DWARF4 ;-) So now we don't have to lookup on a hash table looking for DWARF offsets, we can do the more sensible thing of just indexing the types_tags array. Now to do some cleanups and try to get the per cu encoder done. Then order all the cus per number of type entries, pick the one with more, then go on merging/recoding the types of the others and putting the parent linkage in place. Just to show the extent of the changes: $ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0 /home/acme/git/pahole/dwarves.c: struct cu | -4048 struct tag | -32 struct ptr_to_member_type | -32 struct namespace | -32 struct type | -32 struct class | -32 struct base_type | -32 struct array_type | -32 struct class_member | -32 struct lexblock | -32 struct ftype | -32 struct function | -64 struct parameter | -32 struct variable | -32 struct inline_expansion | -32 struct label | -32 struct enumerator | -32 17 structs changed tag__follow_typedef | +3 tag__fprintf_decl_info | +25 array_type__fprintf | +6 type__name | -126 type__find_first_biggest_size_base_type_member | -3 typedef__fprintf | +16 imported_declaration__fprintf | +6 imported_module__fprintf | +3 cu__new | +26 cu__delete | +26 hashtags__hash | -65 hash_64 | -124 hlist_add_head | -78 hashtags__find | -157 cu__hash | -80 cu__add_tag | +20 tag__prefix | -3 cu__find_tag_by_id | -2 cu__find_type_by_id | -3 cu__find_first_typedef_of_type | +38 cu__find_base_type_by_name | +68 cu__find_base_type_by_name_and_size | +72 cu__find_struct_by_name | +59 cus__find_struct_by_name | +8 cus__find_tag_by_id | +5 cus__find_cu_by_name | -6 lexblock__find_tag_by_id | -173 cu__find_variable_by_id | -197 list__find_tag_by_id | -308 cu__find_parameter_by_id | -60 tag__ptr_name | +6 tag__name | +15 variable__type | +13 variable__name | +7 class_member__size | +6 parameter__name | -119 tag__parameter | -14 parameter__type | -143 type__fprintf | -29 union__fprintf | +6 class__add_vtable_entry | -9 type__add_member | -6 type__clone_members | -3 enumeration__add | -6 function__name | -156 ftype__has_parm_of_type | -39 class__find_holes | -27 class__has_hole_ge | -3 type__nr_members_of_type | +3 lexblock__account_inline_expansions | +3 cu__account_inline_expansions | -18 ftype__fprintf_parms | +46 function__tag_fprintf | +24 lexblock__fprintf | -6 ftype__fprintf | +3 function__fprintf_stats | -18 function__size | -6 class__vtable_fprintf | -11 class__fprintf | -21 tag__fprintf | -35 60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541 /home/acme/git/pahole/ctf_loader.c: struct ctf_short_type | +0 14 structs changed type__init | -14 type__new | -9 class__new | -12 create_new_base_type | -7 create_new_base_type_float | -7 create_new_array | -8 create_new_subroutine_type | -9 create_full_members | -18 create_short_members | -18 create_new_class | +1 create_new_union | +1 create_new_enumeration | -19 create_new_forward_decl | -2 create_new_typedef | +3 create_new_tag | -5 load_types | +16 class__fixup_ctf_bitfields | -3 17 functions changed, 21 bytes added, 131 bytes removed, diff: -110 /home/acme/git/pahole/dwarf_loader.c: 17 structs changed zalloc | -56 tag__init | +3 array_type__new | +20 type__init | -24 class_member__new | +46 inline_expansion__new | +12 class__new | +81 lexblock__init | +19 function__new | +43 die__create_new_array | +20 die__create_new_parameter | +4 die__create_new_label | +4 die__create_new_subroutine_type | +113 die__create_new_enumeration | -21 die__process_class | +79 die__process_namespace | +76 die__create_new_inline_expansion | +4 die__process_function | +147 __die__process_tag | +34 die__process_unit | +56 die__process | +90 21 functions changed, 851 bytes added, 101 bytes removed, diff: +750 /home/acme/git/pahole/dwarves.c: struct ptr_table | +16 struct cu_orig_info | +32 2 structs changed tag__decl_line | +68 tag__decl_file | +70 tag__orig_id | +71 ptr_table__init | +46 ptr_table__exit | +37 ptr_table__add | +183 ptr_table__add_with_id | +165 ptr_table__entry | +64 cu__table_add_tag | +171 cu__table_nullify_type_entry | +38 10 functions changed, 913 bytes added, diff: +913 /home/acme/git/pahole/ctf_loader.c: 2 structs changed tag__alloc | +52 1 function changed, 52 bytes added, diff: +52 /home/acme/git/pahole/dwarf_loader.c: struct dwarf_tag | +48 struct dwarf_cu | +4104 4 structs changed dwarf_cu__init | +83 hashtags__hash | +61 hash_64 | +124 hlist_add_head | +78 hashtags__find | +161 cu__hash | +95 tag__is_tag_type | +171 tag__is_type | +85 tag__is_union | +28 tag__is_struct | +57 tag__is_typedef | +28 tag__is_enumeration | +28 dwarf_cu__find_tag_by_id | +56 dwarf_cu__find_type_by_id | +63 tag__alloc | +114 __tag__print_type_not_found | +108 namespace__recode_dwarf_types | +346 tag__namespace | +14 tag__has_namespace | +86 tag__is_namespace | +28 type__recode_dwarf_specification | +182 tag__type | +14 __tag__print_abstract_origin_not_found | +105 ftype__recode_dwarf_types | +322 tag__ftype | +14 tag__parameter | +14 lexblock__recode_dwarf_types | +736 tag__lexblock | +14 tag__label | +14 tag__recode_dwarf_type | +766 tag__ptr_to_member_type | +14 cu__recode_dwarf_types_table | +88 cu__recode_dwarf_types | +48 dwarf_tag__decl_file | +77 strings__ptr | +33 dwarf_tag__decl_line | +59 dwarf_tag__orig_id | +59 dwarf_tag__orig_type | +59 38 functions changed, 4432 bytes added, diff: +4432 build/libdwarves.so.1.0.0: 147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496 Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
}
static inline unsigned long long tag__orig_id(const struct tag *tag,
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
const struct cu *cu)
{
if (cu->dfops && cu->dfops->tag__orig_id)
return cu->dfops->tag__orig_id(tag, cu);
return 0;
dwarves: Remove some more DWARF details from the core Had to be a big sweeping change, but the regression tests shows just improvements :-) Now we stop using an id in struct tag, only storing the type, that now uses 16 bits only, as CTF does. Each format loader has to go on adding the types to the core, that figures out if it is a tag that can be on the tag->type field (tag__is_tag_type). Formats that already have the types separated and in sequence, such as CTF, just ask the core to insert in the types_table directly with its original ID. For DWARF, we ask the core to put it on the table, in sequence, and return the index, that is then stashed with the DWARF specific info (original id, type, decl_line, etc) and hashed by the original id. Later we recode everything, looking up via the original type, getting the small_id to put on the tag->type. The underlying debugging info not needed by the core is stashed in tag->priv, and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of the core tag and points it there, and makes that info available thru cu->orig_info. In the future we can ask, when loading a cu, that this info be trown away, so that we reduce the memory footprint for big multi-cu files such as the Linux kernel. There is also a routine to ask for inserting a NULL, as we still have bugs in the CTF decoding and thus some entries are being lost, to avoid using an undefined pointer when traversing the types_table the ctf loader puts a NULL there via cu__table_nullify_type_entry() and then cu__for_each_type skips those. There is some more cleanups for leftovers that I avoided cleaning to reduce this changeset. And also while doing this I saw that enums can appear without any enumerators and that an array with DW_TAG_GNU_vector is actually a different tag, encoded this way till we get to DWARF4 ;-) So now we don't have to lookup on a hash table looking for DWARF offsets, we can do the more sensible thing of just indexing the types_tags array. Now to do some cleanups and try to get the per cu encoder done. Then order all the cus per number of type entries, pick the one with more, then go on merging/recoding the types of the others and putting the parent linkage in place. Just to show the extent of the changes: $ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0 /home/acme/git/pahole/dwarves.c: struct cu | -4048 struct tag | -32 struct ptr_to_member_type | -32 struct namespace | -32 struct type | -32 struct class | -32 struct base_type | -32 struct array_type | -32 struct class_member | -32 struct lexblock | -32 struct ftype | -32 struct function | -64 struct parameter | -32 struct variable | -32 struct inline_expansion | -32 struct label | -32 struct enumerator | -32 17 structs changed tag__follow_typedef | +3 tag__fprintf_decl_info | +25 array_type__fprintf | +6 type__name | -126 type__find_first_biggest_size_base_type_member | -3 typedef__fprintf | +16 imported_declaration__fprintf | +6 imported_module__fprintf | +3 cu__new | +26 cu__delete | +26 hashtags__hash | -65 hash_64 | -124 hlist_add_head | -78 hashtags__find | -157 cu__hash | -80 cu__add_tag | +20 tag__prefix | -3 cu__find_tag_by_id | -2 cu__find_type_by_id | -3 cu__find_first_typedef_of_type | +38 cu__find_base_type_by_name | +68 cu__find_base_type_by_name_and_size | +72 cu__find_struct_by_name | +59 cus__find_struct_by_name | +8 cus__find_tag_by_id | +5 cus__find_cu_by_name | -6 lexblock__find_tag_by_id | -173 cu__find_variable_by_id | -197 list__find_tag_by_id | -308 cu__find_parameter_by_id | -60 tag__ptr_name | +6 tag__name | +15 variable__type | +13 variable__name | +7 class_member__size | +6 parameter__name | -119 tag__parameter | -14 parameter__type | -143 type__fprintf | -29 union__fprintf | +6 class__add_vtable_entry | -9 type__add_member | -6 type__clone_members | -3 enumeration__add | -6 function__name | -156 ftype__has_parm_of_type | -39 class__find_holes | -27 class__has_hole_ge | -3 type__nr_members_of_type | +3 lexblock__account_inline_expansions | +3 cu__account_inline_expansions | -18 ftype__fprintf_parms | +46 function__tag_fprintf | +24 lexblock__fprintf | -6 ftype__fprintf | +3 function__fprintf_stats | -18 function__size | -6 class__vtable_fprintf | -11 class__fprintf | -21 tag__fprintf | -35 60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541 /home/acme/git/pahole/ctf_loader.c: struct ctf_short_type | +0 14 structs changed type__init | -14 type__new | -9 class__new | -12 create_new_base_type | -7 create_new_base_type_float | -7 create_new_array | -8 create_new_subroutine_type | -9 create_full_members | -18 create_short_members | -18 create_new_class | +1 create_new_union | +1 create_new_enumeration | -19 create_new_forward_decl | -2 create_new_typedef | +3 create_new_tag | -5 load_types | +16 class__fixup_ctf_bitfields | -3 17 functions changed, 21 bytes added, 131 bytes removed, diff: -110 /home/acme/git/pahole/dwarf_loader.c: 17 structs changed zalloc | -56 tag__init | +3 array_type__new | +20 type__init | -24 class_member__new | +46 inline_expansion__new | +12 class__new | +81 lexblock__init | +19 function__new | +43 die__create_new_array | +20 die__create_new_parameter | +4 die__create_new_label | +4 die__create_new_subroutine_type | +113 die__create_new_enumeration | -21 die__process_class | +79 die__process_namespace | +76 die__create_new_inline_expansion | +4 die__process_function | +147 __die__process_tag | +34 die__process_unit | +56 die__process | +90 21 functions changed, 851 bytes added, 101 bytes removed, diff: +750 /home/acme/git/pahole/dwarves.c: struct ptr_table | +16 struct cu_orig_info | +32 2 structs changed tag__decl_line | +68 tag__decl_file | +70 tag__orig_id | +71 ptr_table__init | +46 ptr_table__exit | +37 ptr_table__add | +183 ptr_table__add_with_id | +165 ptr_table__entry | +64 cu__table_add_tag | +171 cu__table_nullify_type_entry | +38 10 functions changed, 913 bytes added, diff: +913 /home/acme/git/pahole/ctf_loader.c: 2 structs changed tag__alloc | +52 1 function changed, 52 bytes added, diff: +52 /home/acme/git/pahole/dwarf_loader.c: struct dwarf_tag | +48 struct dwarf_cu | +4104 4 structs changed dwarf_cu__init | +83 hashtags__hash | +61 hash_64 | +124 hlist_add_head | +78 hashtags__find | +161 cu__hash | +95 tag__is_tag_type | +171 tag__is_type | +85 tag__is_union | +28 tag__is_struct | +57 tag__is_typedef | +28 tag__is_enumeration | +28 dwarf_cu__find_tag_by_id | +56 dwarf_cu__find_type_by_id | +63 tag__alloc | +114 __tag__print_type_not_found | +108 namespace__recode_dwarf_types | +346 tag__namespace | +14 tag__has_namespace | +86 tag__is_namespace | +28 type__recode_dwarf_specification | +182 tag__type | +14 __tag__print_abstract_origin_not_found | +105 ftype__recode_dwarf_types | +322 tag__ftype | +14 tag__parameter | +14 lexblock__recode_dwarf_types | +736 tag__lexblock | +14 tag__label | +14 tag__recode_dwarf_type | +766 tag__ptr_to_member_type | +14 cu__recode_dwarf_types_table | +88 cu__recode_dwarf_types | +48 dwarf_tag__decl_file | +77 strings__ptr | +33 dwarf_tag__decl_line | +59 dwarf_tag__orig_id | +59 dwarf_tag__orig_type | +59 38 functions changed, 4432 bytes added, diff: +4432 build/libdwarves.so.1.0.0: 147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496 Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
}
static inline void tag__free_orig_info(struct tag *tag, struct cu *cu)
{
if (cu->dfops && cu->dfops->tag__free_orig_info)
cu->dfops->tag__free_orig_info(tag, cu);
}
size_t tag__fprintf_decl_info(const struct tag *tag,
const struct cu *cu, FILE *fp);
size_t tag__fprintf(struct tag *tag, const struct cu *cu,
const struct conf_fprintf *conf, FILE *fp);
const char *tag__name(const struct tag *tag, const struct cu *cu,
char *bf, size_t len, const struct conf_fprintf *conf);
void tag__not_found_die(const char *file, int line, const char *func);
#define tag__assert_search_result(tag) \
do { if (!tag) tag__not_found_die(__FILE__,\
__LINE__, __func__); } while (0)
size_t tag__size(const struct tag *tag, const struct cu *cu);
size_t tag__nr_cachelines(const struct tag *tag, const struct cu *cu);
struct tag *tag__follow_typedef(const struct tag *tag, const struct cu *cu);
loaders: Strip away volatile/const/restrict when fixing bitfields btf_loader and ctf_loader didn't remove const/volatile/restrict, so bitfields using modifiers were not adjusted properly. This patch abstracts logic of stripping aways typedefs and access modifiers into tag__strip_typedefs_and_modifiers, which handles any interleaving of typedefs and modifiers. dwarf_loader was adapter to reuse this function as well, instead of custom goto loop. REPRO: $ cat vc_map.c typedef unsigned int u32; typedef volatile u32 vu32; typedef vu32 vu32_t; typedef struct vc_map { volatile unsigned int tx: 1; vu32_t rx: 1; void *x1, *x2; } vc_map; int main() { struct vc_map s; return 0; } BEFORE: $ ~/pahole/build/pahole -F btf vc_map struct vc_map { volatile unsigned int tx:1; /* 0: 0 4 */ vu32_t rx:1; /* 0: 0 4 */ /* XXX 30 bits hole, try to pack */ /* XXX 4 bytes hole, try to pack */ void * x1; /* 8 8 */ void * x2; /* 16 8 */ /* size: 24, cachelines: 1, members: 4 */ /* sum members: 20, holes: 1, sum holes: 4 */ /* bit holes: 1, sum bit holes: 30 bits */ /* last cacheline: 24 bytes */ }; AFTER: $ ~/pahole/build/pahole -F btf vc_map struct vc_map { volatile unsigned int tx:1; /* 0:31 4 */ vu32_t rx:1; /* 0:30 4 */ /* XXX 30 bits hole, try to pack */ /* XXX 4 bytes hole, try to pack */ void * x1; /* 8 8 */ void * x2; /* 16 8 */ /* size: 24, cachelines: 1, members: 4 */ /* sum members: 20, holes: 1, sum holes: 4 */ /* bit holes: 1, sum bit holes: 30 bits */ /* last cacheline: 24 bytes */ }; Signed-off-by: Andrii Nakryiko <andriin@fb.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Alexei Starovoitov <ast@fb.com> Cc: Yonghong Song <yhs@fb.com> Cc: bpf@vger.kernel.org Cc: dwarves@vger.kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-03-13 17:53:01 +01:00
struct tag *tag__strip_typedefs_and_modifiers(const struct tag *tag, const struct cu *cu);
size_t __tag__id_not_found_fprintf(FILE *fp, type_id_t id,
const char *fn, int line);
#define tag__id_not_found_fprintf(fp, id) \
__tag__id_not_found_fprintf(fp, id, __func__, __LINE__)
int __tag__has_type_loop(const struct tag *tag, const struct tag *type,
char *bf, size_t len, FILE *fp,
const char *fn, int line);
#define tag__has_type_loop(tag, type, bf, len, fp) \
__tag__has_type_loop(tag, type, bf, len, fp, __func__, __LINE__)
struct ptr_to_member_type {
struct tag tag;
type_id_t containing_type;
};
static inline struct ptr_to_member_type *
tag__ptr_to_member_type(const struct tag *tag)
{
return (struct ptr_to_member_type *)tag;
}
/** struct namespace - base class for enums, structs, unions, typedefs, etc
*
* @tags - class_member, enumerators, etc
* @shared_tags: if this bit is set, don't free the entries in @tags
*/
struct namespace {
struct tag tag;
const char *name;
uint16_t nr_tags;
uint8_t shared_tags;
struct list_head tags;
};
static inline struct namespace *tag__namespace(const struct tag *tag)
{
return (struct namespace *)tag;
}
void namespace__delete(struct namespace *nspace);
/**
* namespace__for_each_tag - iterate thru all the tags
* @nspace: struct namespace instance to iterate
* @pos: struct tag iterator
*/
#define namespace__for_each_tag(nspace, pos) \
list_for_each_entry(pos, &(nspace)->tags, node)
/**
* namespace__for_each_tag_safe_reverse - safely iterate thru all the tags, in reverse order
* @nspace: struct namespace instance to iterate
* @pos: struct tag iterator
* @n: struct class_member temp iterator
*/
#define namespace__for_each_tag_safe_reverse(nspace, pos, n) \
list_for_each_entry_safe_reverse(pos, n, &(nspace)->tags, node)
void namespace__add_tag(struct namespace *nspace, struct tag *tag);
struct ip_tag {
struct tag tag;
uint64_t addr;
};
struct inline_expansion {
struct ip_tag ip;
size_t size;
uint64_t high_pc;
};
static inline struct inline_expansion *
tag__inline_expansion(const struct tag *tag)
{
return (struct inline_expansion *)tag;
}
struct label {
struct ip_tag ip;
const char *name;
};
static inline struct label *tag__label(const struct tag *tag)
{
return (struct label *)tag;
}
static inline const char *label__name(const struct label *label)
{
return label->name;
}
enum vscope {
VSCOPE_UNKNOWN,
VSCOPE_LOCAL,
VSCOPE_GLOBAL,
VSCOPE_REGISTER,
VSCOPE_OPTIMIZED
} __attribute__((packed));
struct location {
Dwarf_Op *expr;
size_t exprlen;
};
struct variable {
struct ip_tag ip;
const char *name;
uint8_t external:1;
uint8_t declaration:1;
enum vscope scope;
struct location location;
struct hlist_node tool_hnode;
btf_encoder: Handle DW_TAG_variable that has DW_AT_specification It is found on gcc 8.2 that global percpu variables generate the following dwarf entry in the cu where the variable is defined[1]. Take the global variable "bpf_prog_active" defined in kernel/bpf/syscall.c as an example. The debug info for syscall.c has two dwarf entries for "bpf_prog_active". > readelf -wi kernel/bpf/syscall.o 0x00013534: DW_TAG_variable DW_AT_name ("bpf_prog_active") DW_AT_decl_file ("/data/users/yhs/work/net-next/include/linux/bpf.h") DW_AT_decl_line (1074) DW_AT_decl_column (0x01) DW_AT_type (0x000000d6 "int") DW_AT_external (true) DW_AT_declaration (true) 0x00021a25: DW_TAG_variable DW_AT_specification (0x00013534 "bpf_prog_active") DW_AT_decl_file ("/data/users/yhs/work/net-next/kernel/bpf/syscall.c") DW_AT_decl_line (43) DW_AT_location (DW_OP_addr 0x0) Note that second DW_TAG_variable entry contains specification that points to the first entry. This causes problem for btf_encoder when encoding global variables. The tag generated for the second entry doesn't have the type and scope info. Therefore the BTF VARs encoded using this tag has incorrect type_id and scope. As fix, when creating variable, examine the dwarf entry. If it has a DW_AT_specification, store the referred struct variable in a 'spec' field. When encoding VARs, check this 'spec', if it's non-empty, follow the pointer to use the referred var. [1] https://www.mail-archive.com/netdev@vger.kernel.org/msg348144.html Tested: Tested using gcc 4.9 and gcc 8.2. The types and scopes of global vars are now generated correctly. [21] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED [21102] VAR 'bpf_prog_active' type_id=21, linkage=global-alloc Signed-off-by: Hao Luo <haoluo@google.com> Cc: Alexei Starovoitov <alexei.starovoitov@gmail.com> Cc: Andrii Nakryiko <andrii.nakryiko@gmail.com> Cc: Daniel Borkmann <daniel@iogearbox.net> Cc: Martin KaFai Lau <kafai@fb.com> Cc: Yonghong Song <yhs@fb.com> Cc: dwarves@vger.kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-08-25 02:45:23 +02:00
struct variable *spec;
};
static inline struct variable *tag__variable(const struct tag *tag)
{
return (struct variable *)tag;
}
enum vscope variable__scope(const struct variable *var);
const char *variable__scope_str(const struct variable *var);
const char *variable__name(const struct variable *var, const struct cu *cu);
const char *variable__type_name(const struct variable *var,
const struct cu *cu, char *bf, size_t len);
struct lexblock {
struct ip_tag ip;
struct list_head tags;
uint32_t size;
uint16_t nr_inline_expansions;
uint16_t nr_labels;
uint16_t nr_variables;
uint16_t nr_lexblocks;
uint32_t size_inline_expansions;
};
static inline struct lexblock *tag__lexblock(const struct tag *tag)
{
return (struct lexblock *)tag;
}
void lexblock__delete(struct lexblock *lexblock);
struct function;
void lexblock__add_inline_expansion(struct lexblock *lexblock,
struct inline_expansion *exp);
void lexblock__add_label(struct lexblock *lexblock, struct label *label);
void lexblock__add_lexblock(struct lexblock *lexblock, struct lexblock *child);
void lexblock__add_tag(struct lexblock *lexblock, struct tag *tag);
void lexblock__add_variable(struct lexblock *lexblock, struct variable *var);
size_t lexblock__fprintf(const struct lexblock *lexblock, const struct cu *cu,
struct function *function, uint16_t indent,
const struct conf_fprintf *conf, FILE *fp);
struct parameter {
struct tag tag;
const char *name;
};
static inline struct parameter *tag__parameter(const struct tag *tag)
{
return (struct parameter *)tag;
}
static inline const char *parameter__name(const struct parameter *parm)
{
return parm->name;
}
/*
* tag.tag can be DW_TAG_subprogram_type or DW_TAG_subroutine_type.
*/
struct ftype {
struct tag tag;
struct list_head parms;
uint16_t nr_parms;
uint8_t unspec_parms; /* just one bit is needed */
};
static inline struct ftype *tag__ftype(const struct tag *tag)
{
return (struct ftype *)tag;
}
void ftype__delete(struct ftype *ftype);
/**
* ftype__for_each_parameter - iterate thru all the parameters
* @ftype: struct ftype instance to iterate
* @pos: struct parameter iterator
*/
#define ftype__for_each_parameter(ftype, pos) \
list_for_each_entry(pos, &(ftype)->parms, tag.node)
/**
* ftype__for_each_parameter_safe - safely iterate thru all the parameters
* @ftype: struct ftype instance to iterate
* @pos: struct parameter iterator
* @n: struct parameter temp iterator
*/
#define ftype__for_each_parameter_safe(ftype, pos, n) \
list_for_each_entry_safe(pos, n, &(ftype)->parms, tag.node)
/**
* ftype__for_each_parameter_safe_reverse - safely iterate thru all the parameters, in reverse order
* @ftype: struct ftype instance to iterate
* @pos: struct parameter iterator
* @n: struct parameter temp iterator
*/
#define ftype__for_each_parameter_safe_reverse(ftype, pos, n) \
list_for_each_entry_safe_reverse(pos, n, &(ftype)->parms, tag.node)
void ftype__add_parameter(struct ftype *ftype, struct parameter *parm);
size_t ftype__fprintf(const struct ftype *ftype, const struct cu *cu,
const char *name, const int inlined,
btf_loader: Add support for BTF_KIND_FUNC Some changes to the fprintf routines were needed, as BTF has as the function type just a BTF_KIND_FUNC_PROTO, while DWARF has as the type for a function its return value type. With a function->btf flag this was overcome and all the other goodies in pfunct are present, for instance: $ pahole -JV examples/tcp.o | grep -w FUNC | head [4068] FUNC tcp_init type_id=4067 [4070] FUNC tcp_abort type_id=4069 [4072] FUNC tcp_done type_id=4071 [4074] FUNC tcp_md5_hash_key type_id=4073 [4076] FUNC tcp_md5_hash_skb_data type_id=4075 [4078] FUNC tcp_get_md5sig_pool type_id=4077 [4080] FUNC tcp_alloc_md5sig_pool type_id=4079 [4082] FUNC compat_tcp_getsockopt type_id=4081 [4084] FUNC tcp_getsockopt type_id=4083 [4086] FUNC tcp_get_timestamping_opt_stats type_id=4085 $ $ pfunct -F btf examples/tcp.o | head memset memcpy tcp_enter_memory_pressure tcp_leave_memory_pressure tcp_init_sock tcp_init_transfer tcp_poll tcp_ioctl tcp_splice_read sk_stream_alloc_skb $ $ pfunct --prototype -F btf examples/tcp.o | head void * memset(void * p, int c, __kernel_size_t size); void * memcpy(void * p, const void * q, __kernel_size_t size); void tcp_enter_memory_pressure(struct sock * sk); void tcp_leave_memory_pressure(struct sock * sk); void tcp_init_sock(struct sock * sk); void tcp_init_transfer(struct sock * sk, int bpf_op); __poll_t tcp_poll(struct file * file, struct socket * sock, poll_table * wait); int tcp_ioctl(struct sock * sk, int cmd, long unsigned int arg); ssize_t tcp_splice_read(struct socket * sock, loff_t * ppos, struct pipe_inode_info * pipe, size_t len, unsigned int flags); struct sk_buff * sk_stream_alloc_skb(struct sock * sk, int size, gfp_t gfp, bool force_schedule); $ Now to ask just for the 'struct sock' 'methods', i.e. functions that have as one of its arguments a pointer to the given 'class' name: $ pfunct --class sock -F btf examples/tcp.o | head tcp_abort tcp_done compat_tcp_getsockopt tcp_getsockopt tcp_get_info compat_tcp_setsockopt tcp_setsockopt tcp_disconnect tcp_write_queue_purge tcp_close $ Then ask for the prototypes, which requires -V, should have that fixed: $ pfunct -V --prototypes --class sock -F btf examples/tcp.o | head int tcp_abort(struct sock * sk, int err); void tcp_done(struct sock * sk); int compat_tcp_getsockopt(struct sock * sk, int level, int optname, char * optval, int * optlen); int tcp_getsockopt(struct sock * sk, int level, int optname, char * optval, int * optlen); void tcp_get_info(struct sock * sk, struct tcp_info * info); int compat_tcp_setsockopt(struct sock * sk, int level, int optname, char * optval, unsigned int optlen); int tcp_setsockopt(struct sock * sk, int level, int optname, char * optval, unsigned int optlen); int tcp_disconnect(struct sock * sk, int flags); void tcp_write_queue_purge(struct sock * sk); void tcp_close(struct sock * sk, long int timeout); $ Don't like prototypes with parm names, got you covered: $ pfunct --no_parm_names -V --prototypes --class sock -F btf examples/tcp.o | head int tcp_abort(struct sock *, int); void tcp_done(struct sock *); int compat_tcp_getsockopt(struct sock *, int, int, char *, int *); int tcp_getsockopt(struct sock *, int, int, char *, int *); void tcp_get_info(struct sock *, struct tcp_info *); int compat_tcp_setsockopt(struct sock *, int, int, char *, unsigned int); int tcp_setsockopt(struct sock *, int, int, char *, unsigned int); int tcp_disconnect(struct sock *, int); void tcp_write_queue_purge(struct sock *); void tcp_close(struct sock *, long int); $ Don't like long options and want just one function? $ pfunct -f tcp_setsockopt -F btf examples/tcp.o int tcp_setsockopt(struct sock * sk, int level, int optname, char * optval, unsigned int optlen); $ Want to generate compileable code for all of those functions, full with the necessary types, etc? $ pfunct -F btf --compile examples/tcp.o > a.c $ gcc -c -o a.o a.c $ pfunct -F dwarf --prototypes --class sock a.o | head pfunct: a.o: No debugging information found $ gcc -g -c -o a.o a.c $ pfunct -V -F dwarf --prototypes --class sock a.o | head void tcp_enter_memory_pressure(struct sock * sk); void tcp_leave_memory_pressure(struct sock * sk); void tcp_init_sock(struct sock * sk); void tcp_init_transfer(struct sock * sk, int bpf_op); int tcp_ioctl(struct sock * sk, int cmd, long unsigned int arg); struct sk_buff * sk_stream_alloc_skb(struct sock * sk, int size, gfp_t gfp, bool force_schedule); ssize_t do_tcp_sendpages(struct sock * sk, struct page * page, int offset, size_t size, int flags); int tcp_sendpage_locked(struct sock * sk, struct page * page, int offset, size_t size, int flags); int tcp_sendpage(struct sock * sk, struct page * page, int offset, size_t size, int flags); int tcp_sendmsg_locked(struct sock * sk, struct msghdr * msg, size_t size); $ Now lets go full circle and encode BTF for this a.o generated from source code generated from the original BTF info in that examples/tcp.o file: $ pahole -JV a.o | tail [465] FUNC_PROTO (anon) return=35 args=(392 hp, 393 skb, 5 header_len) [466] FUNC tcp_md5_hash_skb_data type_id=465 [467] FUNC_PROTO (anon) return=35 args=(392 hp, 394 key) [468] FUNC tcp_md5_hash_key type_id=467 [469] FUNC_PROTO (anon) return=0 args=(49 sk) [470] FUNC tcp_done type_id=469 [471] FUNC_PROTO (anon) return=35 args=(49 sk, 35 err) [472] FUNC tcp_abort type_id=471 [473] FUNC_PROTO (anon) return=0 args=(void) [474] FUNC tcp_init type_id=473 $ $ pfunct -F btf -V --prototypes --class=sock a.o | head void tcp_enter_memory_pressure(struct sock * sk); void tcp_leave_memory_pressure(struct sock * sk); void tcp_init_sock(struct sock * sk); void tcp_init_transfer(struct sock * sk, int bpf_op); int tcp_ioctl(struct sock * sk, int cmd, long unsigned int arg); struct sk_buff * sk_stream_alloc_skb(struct sock * sk, int size, gfp_t gfp, bool force_schedule); ssize_t do_tcp_sendpages(struct sock * sk, struct page * page, int offset, size_t size, int flags); int tcp_sendpage_locked(struct sock * sk, struct page * page, int offset, size_t size, int flags); int tcp_sendpage(struct sock * sk, struct page * page, int offset, size_t size, int flags); int tcp_sendmsg_locked(struct sock * sk, struct msghdr * msg, size_t size); $ Curious about the code generated by 'pfunct -F btf --compile examples/tcp.o? http://vger.kernel.org/~acme/pahole/pfunct-F-BTF--compile-examples-tcp.o.txt Cc: Alexei Starovoitov <ast@fb.com> Cc: Alexei Starovoitov <ast@kernel.org> Cc: Andrii Nakryiko <andrii.nakryiko@gmail.com> Cc: Andrii Nakryiko <andriin@fb.com> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Yonghong Song <yhs@fb.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-11-05 15:30:51 +01:00
const int is_pointer, const int type_spacing, bool is_prototype,
const struct conf_fprintf *conf, FILE *fp);
size_t ftype__fprintf_parms(const struct ftype *ftype,
const struct cu *cu, int indent,
const struct conf_fprintf *conf, FILE *fp);
int ftype__has_parm_of_type(const struct ftype *ftype, const type_id_t target,
const struct cu *cu);
struct function {
struct ftype proto;
struct lexblock lexblock;
struct rb_node rb_node;
const char *name;
const char *linkage_name;
uint32_t cu_total_size_inline_expansions;
uint16_t cu_total_nr_inline_expansions;
uint8_t inlined:2;
uint8_t abstract_origin:1;
uint8_t external:1;
uint8_t accessibility:2; /* DW_ACCESS_{public,protected,private} */
uint8_t virtuality:2; /* DW_VIRTUALITY_{none,virtual,pure_virtual} */
btf_encoder: Preserve and encode exported functions as BTF_KIND_FUNC Add encoding of DWARF's DW_TAG_subprogram_type into BTF's BTF_KIND_FUNC (plus corresponding BTF_KIND_FUNC_PROTO). Only exported functions are converted for now. This allows to capture all the exported kernel functions, same subset that's exposed through /proc/kallsyms. Committer testing: Before: $ readelf -SW vmlinux | grep BTF [78] .BTF PROGBITS 0000000000000000 26a27da9 1e5543 00 0 0 1 $ After: $ pahole -J vmlinux $ readelf -SW vmlinux | grep BTF [78] .BTF PROGBITS 0000000000000000 26a27da9 2d5f47 00 0 0 1 $ >>> 0x2d5f47 - 0x1e5543 985604 The kernel has a lot of functions! :-) $ pahole -VJ vmlinux > /tmp/pahole-btf-encoding-verbose-output.txt $ grep -w FUNC /tmp/pahole-btf-encoding-verbose-output.txt | wc -l 22871 [acme@quaco pahole]$ grep -w FUNC /tmp/pahole-btf-encoding-verbose-output.txt | tail [4511543] FUNC copy_from_user_nmi type_id=4511542 [4512934] FUNC memcpy_page_flushcache type_id=4512933 [4512936] FUNC __memcpy_flushcache type_id=4512935 [4512938] FUNC __copy_user_flushcache type_id=4512937 [4512940] FUNC arch_wb_cache_pmem type_id=4512939 [4512942] FUNC mcsafe_handle_tail type_id=4512941 [4512944] FUNC copy_user_handle_tail type_id=4512943 [4512946] FUNC clear_user type_id=4512945 [4512948] FUNC __clear_user type_id=4512947 [4512950] FUNC memcpy type_id=4512949 $ grep -w FUNC_PROTO /tmp/pahole-btf-encoding-verbose-output.txt | tail [4512902] FUNC_PROTO (anon) return=4511725 args=(4512097 (anon), 4511544 (anon)) [4512933] FUNC_PROTO (anon) return=0 args=(4511598 to, 4511725 page, 4511610 offset, 4511610 len) [4512935] FUNC_PROTO (anon) return=0 args=(4511638 _dst, 4511759 _src, 4511610 size) [4512937] FUNC_PROTO (anon) return=4511585 args=(4511638 dst, 4511759 src, 4511552 size) [4512939] FUNC_PROTO (anon) return=0 args=(4511638 addr, 4511610 size) [4512941] FUNC_PROTO (anon) return=4511544 args=(4511598 to, 4511598 from, 4511552 len) [4512943] FUNC_PROTO (anon) return=4511544 args=(4511598 to, 4511598 from, 4511552 len) [4512945] FUNC_PROTO (anon) return=4511544 args=(4511638 to, 4511544 n) [4512947] FUNC_PROTO (anon) return=4511544 args=(4511638 addr, 4511544 size) [4512949] FUNC_PROTO (anon) return=4511638 args=(4511638 p, 4511759 q, 4511591 size) $ grep -w FUNC_PROTO /tmp/pahole-btf-encoding-verbose-output.txt |grep 4511542 [4511542] FUNC_PROTO (anon) return=4510159 args=(4510254 to, 4510374 from, 4510159 n) $ With a little change to pdwtags to see DW_TAG_subroutine_type, which is what BTF's KIND_FUNC_PROTO maps to, we see some of those last prototypes: [acme@quaco pahole]$ pdwtags -F btf vmlinux | grep '()(' | tail void ()(struct insn * insn); /* size: 45404744 */ int ()(struct insn * insn); /* size: 4 */ void ()(struct insn * insn, const void * kaddr, int buf_len, int x86_64); /* size: 45405032 */ long unsigned int ()(const char * purpose); /* size: 8 */ void ()(char * to, struct page * page, size_t offset, size_t len); /* size: 45405864 */ void ()(void * _dst, const void * _src, size_t size); /* size: 45406200 */ long int ()(void * dst, const void * src, unsigned int size); /* size: 8 */ long unsigned int ()(char * to, char * from, unsigned int len); /* size: 8 */ long unsigned int ()(void * to, long unsigned int n); /* size: 8 */ long unsigned int ()(void * addr, long unsigned int size); /* size: 8 */ [acme@quaco pahole]$ I.e.: [4512941] FUNC_PROTO (anon) return=4511544 args=(4511598 to, 4511598 from, 4511552 len) gets decoded by pdwtags as: long unsigned int ()(char * to, char * from, unsigned int len); /* size: 8 */ $ grep '\[\(4511544\|4511598\|4511550\|4511552\)\]' /tmp/pahole-btf-encoding-verbose-output.txt [4511544] INT long unsigned int size=8 bit_offset=0 nr_bits=64 encoding=(none) [4511550] INT char size=1 bit_offset=0 nr_bits=8 encoding=(none) [4511552] INT unsigned int size=4 bit_offset=0 nr_bits=32 encoding=(none) [4511598] PTR (anon) type_id=4511550 $ Signed-off-by: Andrii Nakryiko <andriin@fb.com> Tested-by: Alexei Starovoitov <ast@kernel.org> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Acked-by: Alexei Starovoitov <ast@kernel.org> Cc: Alexei Starovoitov <ast@fb.com> Cc: Andrii Nakryiko <andrii.nakryiko@gmail.com> Cc: Yonghong Song <yhs@fb.com> Cc: dwarves@vger.kernel.org Cc: kernel-team@fb.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-10-29 06:30:15 +01:00
uint8_t declaration:1;
btf_loader: Add support for BTF_KIND_FUNC Some changes to the fprintf routines were needed, as BTF has as the function type just a BTF_KIND_FUNC_PROTO, while DWARF has as the type for a function its return value type. With a function->btf flag this was overcome and all the other goodies in pfunct are present, for instance: $ pahole -JV examples/tcp.o | grep -w FUNC | head [4068] FUNC tcp_init type_id=4067 [4070] FUNC tcp_abort type_id=4069 [4072] FUNC tcp_done type_id=4071 [4074] FUNC tcp_md5_hash_key type_id=4073 [4076] FUNC tcp_md5_hash_skb_data type_id=4075 [4078] FUNC tcp_get_md5sig_pool type_id=4077 [4080] FUNC tcp_alloc_md5sig_pool type_id=4079 [4082] FUNC compat_tcp_getsockopt type_id=4081 [4084] FUNC tcp_getsockopt type_id=4083 [4086] FUNC tcp_get_timestamping_opt_stats type_id=4085 $ $ pfunct -F btf examples/tcp.o | head memset memcpy tcp_enter_memory_pressure tcp_leave_memory_pressure tcp_init_sock tcp_init_transfer tcp_poll tcp_ioctl tcp_splice_read sk_stream_alloc_skb $ $ pfunct --prototype -F btf examples/tcp.o | head void * memset(void * p, int c, __kernel_size_t size); void * memcpy(void * p, const void * q, __kernel_size_t size); void tcp_enter_memory_pressure(struct sock * sk); void tcp_leave_memory_pressure(struct sock * sk); void tcp_init_sock(struct sock * sk); void tcp_init_transfer(struct sock * sk, int bpf_op); __poll_t tcp_poll(struct file * file, struct socket * sock, poll_table * wait); int tcp_ioctl(struct sock * sk, int cmd, long unsigned int arg); ssize_t tcp_splice_read(struct socket * sock, loff_t * ppos, struct pipe_inode_info * pipe, size_t len, unsigned int flags); struct sk_buff * sk_stream_alloc_skb(struct sock * sk, int size, gfp_t gfp, bool force_schedule); $ Now to ask just for the 'struct sock' 'methods', i.e. functions that have as one of its arguments a pointer to the given 'class' name: $ pfunct --class sock -F btf examples/tcp.o | head tcp_abort tcp_done compat_tcp_getsockopt tcp_getsockopt tcp_get_info compat_tcp_setsockopt tcp_setsockopt tcp_disconnect tcp_write_queue_purge tcp_close $ Then ask for the prototypes, which requires -V, should have that fixed: $ pfunct -V --prototypes --class sock -F btf examples/tcp.o | head int tcp_abort(struct sock * sk, int err); void tcp_done(struct sock * sk); int compat_tcp_getsockopt(struct sock * sk, int level, int optname, char * optval, int * optlen); int tcp_getsockopt(struct sock * sk, int level, int optname, char * optval, int * optlen); void tcp_get_info(struct sock * sk, struct tcp_info * info); int compat_tcp_setsockopt(struct sock * sk, int level, int optname, char * optval, unsigned int optlen); int tcp_setsockopt(struct sock * sk, int level, int optname, char * optval, unsigned int optlen); int tcp_disconnect(struct sock * sk, int flags); void tcp_write_queue_purge(struct sock * sk); void tcp_close(struct sock * sk, long int timeout); $ Don't like prototypes with parm names, got you covered: $ pfunct --no_parm_names -V --prototypes --class sock -F btf examples/tcp.o | head int tcp_abort(struct sock *, int); void tcp_done(struct sock *); int compat_tcp_getsockopt(struct sock *, int, int, char *, int *); int tcp_getsockopt(struct sock *, int, int, char *, int *); void tcp_get_info(struct sock *, struct tcp_info *); int compat_tcp_setsockopt(struct sock *, int, int, char *, unsigned int); int tcp_setsockopt(struct sock *, int, int, char *, unsigned int); int tcp_disconnect(struct sock *, int); void tcp_write_queue_purge(struct sock *); void tcp_close(struct sock *, long int); $ Don't like long options and want just one function? $ pfunct -f tcp_setsockopt -F btf examples/tcp.o int tcp_setsockopt(struct sock * sk, int level, int optname, char * optval, unsigned int optlen); $ Want to generate compileable code for all of those functions, full with the necessary types, etc? $ pfunct -F btf --compile examples/tcp.o > a.c $ gcc -c -o a.o a.c $ pfunct -F dwarf --prototypes --class sock a.o | head pfunct: a.o: No debugging information found $ gcc -g -c -o a.o a.c $ pfunct -V -F dwarf --prototypes --class sock a.o | head void tcp_enter_memory_pressure(struct sock * sk); void tcp_leave_memory_pressure(struct sock * sk); void tcp_init_sock(struct sock * sk); void tcp_init_transfer(struct sock * sk, int bpf_op); int tcp_ioctl(struct sock * sk, int cmd, long unsigned int arg); struct sk_buff * sk_stream_alloc_skb(struct sock * sk, int size, gfp_t gfp, bool force_schedule); ssize_t do_tcp_sendpages(struct sock * sk, struct page * page, int offset, size_t size, int flags); int tcp_sendpage_locked(struct sock * sk, struct page * page, int offset, size_t size, int flags); int tcp_sendpage(struct sock * sk, struct page * page, int offset, size_t size, int flags); int tcp_sendmsg_locked(struct sock * sk, struct msghdr * msg, size_t size); $ Now lets go full circle and encode BTF for this a.o generated from source code generated from the original BTF info in that examples/tcp.o file: $ pahole -JV a.o | tail [465] FUNC_PROTO (anon) return=35 args=(392 hp, 393 skb, 5 header_len) [466] FUNC tcp_md5_hash_skb_data type_id=465 [467] FUNC_PROTO (anon) return=35 args=(392 hp, 394 key) [468] FUNC tcp_md5_hash_key type_id=467 [469] FUNC_PROTO (anon) return=0 args=(49 sk) [470] FUNC tcp_done type_id=469 [471] FUNC_PROTO (anon) return=35 args=(49 sk, 35 err) [472] FUNC tcp_abort type_id=471 [473] FUNC_PROTO (anon) return=0 args=(void) [474] FUNC tcp_init type_id=473 $ $ pfunct -F btf -V --prototypes --class=sock a.o | head void tcp_enter_memory_pressure(struct sock * sk); void tcp_leave_memory_pressure(struct sock * sk); void tcp_init_sock(struct sock * sk); void tcp_init_transfer(struct sock * sk, int bpf_op); int tcp_ioctl(struct sock * sk, int cmd, long unsigned int arg); struct sk_buff * sk_stream_alloc_skb(struct sock * sk, int size, gfp_t gfp, bool force_schedule); ssize_t do_tcp_sendpages(struct sock * sk, struct page * page, int offset, size_t size, int flags); int tcp_sendpage_locked(struct sock * sk, struct page * page, int offset, size_t size, int flags); int tcp_sendpage(struct sock * sk, struct page * page, int offset, size_t size, int flags); int tcp_sendmsg_locked(struct sock * sk, struct msghdr * msg, size_t size); $ Curious about the code generated by 'pfunct -F btf --compile examples/tcp.o? http://vger.kernel.org/~acme/pahole/pfunct-F-BTF--compile-examples-tcp.o.txt Cc: Alexei Starovoitov <ast@fb.com> Cc: Alexei Starovoitov <ast@kernel.org> Cc: Andrii Nakryiko <andrii.nakryiko@gmail.com> Cc: Andrii Nakryiko <andriin@fb.com> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Yonghong Song <yhs@fb.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-11-05 15:30:51 +01:00
uint8_t btf:1;
int32_t vtable_entry;
struct list_head vtable_node;
/* fields used by tools */
ctf_encoder: Convert DWARF functions to CTF Finally we can use the Elf file already opened in dwarf_load, call cu__for_each_cached_symtab_entry to iterate over the symtab entries, this iterator will first call dwfl_module_getsymtab, that will do the relocation that will allow us to go from the symtab address to the one in the DWARF DW_TAG_subprogram tag DW_AT_low_pc attribute. And voila, for a relatively complex single unit Linux kernel object file, kernel/sched.o, we go from: Just DWARF (gcc -g): $ ls -la kernel/sched.o 1979011 kernel/sched.o Then we run this to encode the CTF section: $ pahole -Z kernel/sched.o And get a file with both DWARF and CTF ELF sections: $ ls -la kernel/sched.o 2019848 kernel/sched.o We still need to encode the "OBJECTS", i.e. variables, but this gets us from 1979011 (just DWARF) to: $ strip--strip-debug kernel/sched.o $ ls -la kernel/sched.o -rw-rw-r-- 1 acme acme 507008 2009-03-30 23:01 kernel/sched.o 25% of the original size. Of course we don't have inline expansion information, parameter names, goto labels, etc, but should be good enough for most use cases. See, without DWARF data, if we ask for it to use DWARF, nothing will be printed, if we don't speficy the format, it will try first DWARF, it will not find anything, it will try CTF: $ pahole -F dwarf kernel/sched.o $ pahole -C seq_operations kernel/sched.o struct seq_operations { void * (*start)(struct seq_file *, loff_t *); /* 0 8 */ void (*stop)(struct seq_file *, void *); /* 8 8 */ void * (*next)(struct seq_file *, void *, loff_t *); /* 16 8 */ int (*show)(struct seq_file *, void *); /* 24 8 */ /* size: 32, cachelines: 1, members: 4 */ /* last cacheline: 32 bytes */ }; $ $ pfunct -Vi -f schedule kernel/sched.o void schedule(void); { /* low_pc=0xe01 */ }/* size: 83 */ $ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-31 03:54:29 +02:00
union {
struct list_head tool_node;
struct hlist_node tool_hnode;
};
void *priv;
};
static inline struct function *tag__function(const struct tag *tag)
{
return (struct function *)tag;
}
static inline struct tag *function__tag(const struct function *func)
{
return (struct tag *)func;
}
void function__delete(struct function *func);
static __pure inline int tag__is_function(const struct tag *tag)
{
return tag->tag == DW_TAG_subprogram;
}
/**
* function__for_each_parameter - iterate thru all the parameters
* @func: struct function instance to iterate
* @pos: struct parameter iterator
*/
#define function__for_each_parameter(func, cu, pos) \
ftype__for_each_parameter(func->btf ? tag__ftype(cu__type(cu, func->proto.tag.type)) : &func->proto, pos)
const char *function__name(struct function *func);
static inline const char *function__linkage_name(const struct function *func)
{
return func->linkage_name;
}
size_t function__fprintf_stats(const struct tag *tag_func,
const struct cu *cu,
const struct conf_fprintf *conf,
FILE *fp);
const char *function__prototype(const struct function *func,
const struct cu *cu, char *bf, size_t len);
static __pure inline uint64_t function__addr(const struct function *func)
{
return func->lexblock.ip.addr;
}
static __pure inline uint32_t function__size(const struct function *func)
{
return func->lexblock.size;
}
static inline int function__declared_inline(const struct function *func)
{
return (func->inlined == DW_INL_declared_inlined ||
func->inlined == DW_INL_declared_not_inlined);
}
static inline int function__inlined(const struct function *func)
{
return (func->inlined == DW_INL_inlined ||
func->inlined == DW_INL_declared_inlined);
}
/* struct class_member - struct, union, class member
*
* @bit_offset - offset in bits from the start of the struct
* @bit_size - cached bit size, can be smaller than the integral type if in a bitfield
* @byte_offset - offset in bytes from the start of the struct
* @byte_size - cached byte size, integral type byte size for bitfields
* @bitfield_offset - offset in the current bitfield
* @bitfield_size - size in the current bitfield
* @bit_hole - If there is a bit hole before the next one (or the end of the struct)
* @bitfield_end - Is this the last entry in a bitfield?
* @alignment - DW_AT_alignement, zero if not present, gcc emits since circa 7.3.1
* @accessibility - DW_ACCESS_{public,protected,private}
* @virtuality - DW_VIRTUALITY_{none,virtual,pure_virtual}
* @hole - If there is a hole before the next one (or the end of the struct)
dwarf_loader: Support DW_AT_data_bit_offset This appeared in DWARF4 but is supported only in gcc's -gdwarf-5, support it in a way that makes the output be the same for both cases: $ gcc -gdwarf-4 -c examples/dwarf5/bf.c $ pahole bf.o struct pea { long int a:1; /* 0: 0 8 */ long int b:1; /* 0: 1 8 */ long int c:1; /* 0: 2 8 */ /* XXX 29 bits hole, try to pack */ /* Bitfield combined with next fields */ int after_bitfield; /* 4 4 */ /* size: 8, cachelines: 1, members: 4 */ /* sum members: 4 */ /* sum bitfield members: 3 bits, bit holes: 1, sum bit holes: 29 bits */ /* last cacheline: 8 bytes */ }; $ gcc -gdwarf-5 -c examples/dwarf5/bf.c $ pahole bf.o struct pea { long int a:1; /* 0: 0 8 */ long int b:1; /* 0: 1 8 */ long int c:1; /* 0: 2 8 */ /* XXX 29 bits hole, try to pack */ /* Bitfield combined with next fields */ int after_bitfield; /* 4 4 */ /* size: 8, cachelines: 1, members: 4 */ /* sum members: 4 */ /* sum bitfield members: 3 bits, bit holes: 1, sum bit holes: 29 bits */ /* last cacheline: 8 bytes */ }; $ Now with an integer before the bitfield: $ cat examples/dwarf5/bf.c struct pea { int before_bitfield; long a:1, b:1, c:1; int after_bitfield; } p; $ gcc -gdwarf-4 -c examples/dwarf5/bf.c $ pahole bf.o struct pea { int before_bitfield; /* 0 4 */ /* Bitfield combined with previous fields */ long int a:1; /* 0:32 8 */ long int b:1; /* 0:33 8 */ long int c:1; /* 0:34 8 */ /* XXX 29 bits hole, try to pack */ int after_bitfield; /* 8 4 */ /* size: 16, cachelines: 1, members: 5 */ /* sum members: 8 */ /* sum bitfield members: 3 bits, bit holes: 1, sum bit holes: 29 bits */ /* padding: 4 */ /* last cacheline: 16 bytes */ }; $ gcc -gdwarf-5 -c examples/dwarf5/bf.c $ pahole bf.o struct pea { int before_bitfield; /* 0 4 */ /* Bitfield combined with previous fields */ long int a:1; /* 0:32 8 */ long int b:1; /* 0:33 8 */ long int c:1; /* 0:34 8 */ /* XXX 29 bits hole, try to pack */ int after_bitfield; /* 8 4 */ /* size: 16, cachelines: 1, members: 5 */ /* sum members: 8 */ /* sum bitfield members: 3 bits, bit holes: 1, sum bit holes: 29 bits */ /* padding: 4 */ /* last cacheline: 16 bytes */ }; $ And an array of long integers at the start, before the combination of an integer with a long integer bitfield: $ cat examples/dwarf5/bf.c struct pea { long array[3]; int before_bitfield; long a:1, b:1, c:1; int after_bitfield; } p; $ gcc -gdwarf-4 -c examples/dwarf5/bf.c $ pahole bf.o struct pea { long int array[3]; /* 0 24 */ int before_bitfield; /* 24 4 */ /* Bitfield combined with previous fields */ long int a:1; /* 24:32 8 */ long int b:1; /* 24:33 8 */ long int c:1; /* 24:34 8 */ /* XXX 29 bits hole, try to pack */ int after_bitfield; /* 32 4 */ /* size: 40, cachelines: 1, members: 6 */ /* sum members: 32 */ /* sum bitfield members: 3 bits, bit holes: 1, sum bit holes: 29 bits */ /* padding: 4 */ /* last cacheline: 40 bytes */ }; $ gcc -gdwarf-5 -c examples/dwarf5/bf.c $ pahole bf.o struct pea { long int array[3]; /* 0 24 */ int before_bitfield; /* 24 4 */ /* Bitfield combined with previous fields */ long int a:1; /* 24:32 8 */ long int b:1; /* 24:33 8 */ long int c:1; /* 24:34 8 */ /* XXX 29 bits hole, try to pack */ int after_bitfield; /* 32 4 */ /* size: 40, cachelines: 1, members: 6 */ /* sum members: 32 */ /* sum bitfield members: 3 bits, bit holes: 1, sum bit holes: 29 bits */ /* padding: 4 */ /* last cacheline: 40 bytes */ }; $ Reported-by: Mark Wielaard <mark@klomp.org> Tested-by: "Daniel P. Berrangé" <berrange@redhat.com> Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1919965 Link: https://lore.kernel.org/dwarves/20210128121122.GA775562@kernel.org/ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-01-28 12:51:31 +01:00
* @has_bit_offset: Don't recalcule this, it came from the debug info (DWARF5's DW_AT_data_bit_offset)
*/
struct class_member {
struct tag tag;
const char *name;
uint32_t bit_offset;
uint32_t bit_size;
uint32_t byte_offset;
size_t byte_size;
dwarves: Change type of bitfield_offset from uint8_t to int8_t The dwarves class_member field bitfield_offset represents the dwarf tag DW_AT_bit_offset. For dwarf2, this field can be negative for little endian for bitfields in packed data structures which cross type boundary. -bash-4.4$ cat bitfield.c struct packed { char x1: 1; char x2: 3; char x3: 3; int y1: 7; int y2: 20; } __attribute__((packed)); struct packed g; -bash-4.4$ gcc -O2 -c -g bitfield.c -bash-4.4$ pahole -JV bitfield.o File bitfield.o: [1] STRUCT packed kind_flag=1 size=5 vlen=5 x1 type_id=2 bitfield_size=1 bits_offset=0 x2 type_id=2 bitfield_size=3 bits_offset=1 x3 type_id=2 bitfield_size=3 bits_offset=4 y1 type_id=3 bitfield_size=7 bits_offset=7 y2 type_id=3 bitfield_size=255 bits_offset=16776974 [2] INT char size=1 bit_offset=0 nr_bits=8 encoding=(none) [3] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED -bash-4.4$ The above large negative bits_offset and bitfield_size=255 results from negative bitfield_offset which is interpreted as positive value in btf encoding. With this fix, the pahole works properly for BTF: -bash-4.4$ pahole -JV bitfield.o File bitfield.o: [1] STRUCT packed kind_flag=1 size=5 vlen=5 x1 type_id=2 bitfield_size=1 bits_offset=0 x2 type_id=2 bitfield_size=3 bits_offset=1 x3 type_id=2 bitfield_size=3 bits_offset=4 y1 type_id=3 bitfield_size=7 bits_offset=7 y2 type_id=3 bitfield_size=20 bits_offset=14 [2] INT char size=1 bit_offset=0 nr_bits=8 encoding=(none) [3] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED -bash-4.4$ Note that change bitfield_offset from uint8_t to int8_t is safe as the maximum int type we support is __int128 and maximum bitfield_offset is 127. Signed-off-by: Yonghong Song <yhs@fb.com> Reported-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Alexei Starovoitov <ast@fb.com> Cc: Andrii Nakryiko <andriin@fb.com> Cc: Martin KaFai Lau <kafai@fb.com> Cc: dwarves@vger.kernel.org Link: https://www.spinics.net/lists/dwarves/msg00199.html Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-01-12 01:19:53 +01:00
int8_t bitfield_offset;
uint8_t bitfield_size;
uint8_t bit_hole;
uint8_t bitfield_end:1;
uint64_t const_value;
uint32_t alignment;
uint8_t visited:1;
uint8_t is_static:1;
dwarf_loader: Support DW_AT_data_bit_offset This appeared in DWARF4 but is supported only in gcc's -gdwarf-5, support it in a way that makes the output be the same for both cases: $ gcc -gdwarf-4 -c examples/dwarf5/bf.c $ pahole bf.o struct pea { long int a:1; /* 0: 0 8 */ long int b:1; /* 0: 1 8 */ long int c:1; /* 0: 2 8 */ /* XXX 29 bits hole, try to pack */ /* Bitfield combined with next fields */ int after_bitfield; /* 4 4 */ /* size: 8, cachelines: 1, members: 4 */ /* sum members: 4 */ /* sum bitfield members: 3 bits, bit holes: 1, sum bit holes: 29 bits */ /* last cacheline: 8 bytes */ }; $ gcc -gdwarf-5 -c examples/dwarf5/bf.c $ pahole bf.o struct pea { long int a:1; /* 0: 0 8 */ long int b:1; /* 0: 1 8 */ long int c:1; /* 0: 2 8 */ /* XXX 29 bits hole, try to pack */ /* Bitfield combined with next fields */ int after_bitfield; /* 4 4 */ /* size: 8, cachelines: 1, members: 4 */ /* sum members: 4 */ /* sum bitfield members: 3 bits, bit holes: 1, sum bit holes: 29 bits */ /* last cacheline: 8 bytes */ }; $ Now with an integer before the bitfield: $ cat examples/dwarf5/bf.c struct pea { int before_bitfield; long a:1, b:1, c:1; int after_bitfield; } p; $ gcc -gdwarf-4 -c examples/dwarf5/bf.c $ pahole bf.o struct pea { int before_bitfield; /* 0 4 */ /* Bitfield combined with previous fields */ long int a:1; /* 0:32 8 */ long int b:1; /* 0:33 8 */ long int c:1; /* 0:34 8 */ /* XXX 29 bits hole, try to pack */ int after_bitfield; /* 8 4 */ /* size: 16, cachelines: 1, members: 5 */ /* sum members: 8 */ /* sum bitfield members: 3 bits, bit holes: 1, sum bit holes: 29 bits */ /* padding: 4 */ /* last cacheline: 16 bytes */ }; $ gcc -gdwarf-5 -c examples/dwarf5/bf.c $ pahole bf.o struct pea { int before_bitfield; /* 0 4 */ /* Bitfield combined with previous fields */ long int a:1; /* 0:32 8 */ long int b:1; /* 0:33 8 */ long int c:1; /* 0:34 8 */ /* XXX 29 bits hole, try to pack */ int after_bitfield; /* 8 4 */ /* size: 16, cachelines: 1, members: 5 */ /* sum members: 8 */ /* sum bitfield members: 3 bits, bit holes: 1, sum bit holes: 29 bits */ /* padding: 4 */ /* last cacheline: 16 bytes */ }; $ And an array of long integers at the start, before the combination of an integer with a long integer bitfield: $ cat examples/dwarf5/bf.c struct pea { long array[3]; int before_bitfield; long a:1, b:1, c:1; int after_bitfield; } p; $ gcc -gdwarf-4 -c examples/dwarf5/bf.c $ pahole bf.o struct pea { long int array[3]; /* 0 24 */ int before_bitfield; /* 24 4 */ /* Bitfield combined with previous fields */ long int a:1; /* 24:32 8 */ long int b:1; /* 24:33 8 */ long int c:1; /* 24:34 8 */ /* XXX 29 bits hole, try to pack */ int after_bitfield; /* 32 4 */ /* size: 40, cachelines: 1, members: 6 */ /* sum members: 32 */ /* sum bitfield members: 3 bits, bit holes: 1, sum bit holes: 29 bits */ /* padding: 4 */ /* last cacheline: 40 bytes */ }; $ gcc -gdwarf-5 -c examples/dwarf5/bf.c $ pahole bf.o struct pea { long int array[3]; /* 0 24 */ int before_bitfield; /* 24 4 */ /* Bitfield combined with previous fields */ long int a:1; /* 24:32 8 */ long int b:1; /* 24:33 8 */ long int c:1; /* 24:34 8 */ /* XXX 29 bits hole, try to pack */ int after_bitfield; /* 32 4 */ /* size: 40, cachelines: 1, members: 6 */ /* sum members: 32 */ /* sum bitfield members: 3 bits, bit holes: 1, sum bit holes: 29 bits */ /* padding: 4 */ /* last cacheline: 40 bytes */ }; $ Reported-by: Mark Wielaard <mark@klomp.org> Tested-by: "Daniel P. Berrangé" <berrange@redhat.com> Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1919965 Link: https://lore.kernel.org/dwarves/20210128121122.GA775562@kernel.org/ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-01-28 12:51:31 +01:00
uint8_t has_bit_offset:1;
uint8_t accessibility:2;
uint8_t virtuality:2;
uint16_t hole;
[CLASSES]: Add support for DW_TAG_inlined_subroutine Output of pfunct using this information (all for a make allyesconfig build): Top 5 functions by size of inlined functions in net/ipv4: [acme@newtoy guinea_pig-2.6]$ pfunct -I net/ipv4/built-in.o | sort -k3 -nr | head -5 ip_route_input: 19 7086 tcp_ack: 33 6415 do_ip_vs_set_ctl: 23 4193 q931_help: 8 3822 ip_defrag: 19 3318 [acme@newtoy guinea_pig-2.6]$ And by number of inline expansions: [acme@newtoy guinea_pig-2.6]$ pfunct -I net/ipv4/built-in.o | sort -k2 -nr | head -5 dump_packet: 35 905 tcp_v4_rcv: 34 1773 tcp_recvmsg: 34 928 tcp_ack: 33 6415 tcp_rcv_established: 31 1195 [acme@newtoy guinea_pig-2.6]$ And the list of expansions on a specific function: [acme@newtoy guinea_pig-2.6]$ pfunct -i net/ipv4/built-in.o tcp_v4_rcv /* net/ipv4/tcp_ipv4.c:1054 */ int tcp_v4_rcv(struct sk_buff * skb); /* size: 2189, variables: 8, goto labels: 6, inline expansions: 34 (1773 bytes) */ /* inline expansions in tcp_v4_rcv: current_thread_info: 8 pskb_may_pull: 36 pskb_may_pull: 29 tcp_v4_checksum_init: 139 __fswab32: 2 __fswab32: 2 inet_iif: 12 __inet_lookup: 292 __fswab16: 20 inet_ehashfn: 25 inet_ehash_bucket: 18 prefetch: 4 prefetch: 4 prefetch: 4 sock_hold: 4 xfrm4_policy_check: 59 nf_reset: 66 sk_filter: 135 __skb_trim: 20 get_softnet_dma: 68 tcp_prequeue: 257 sk_add_backlog: 40 sock_put: 27 xfrm4_policy_check: 46 tcp_checksum_complete: 29 current_thread_info: 8 sock_put: 20 xfrm4_policy_check: 50 tcp_checksum_complete: 29 current_thread_info: 8 inet_iif: 9 inet_lookup_listener: 36 inet_twsk_put: 114 tcp_v4_timewait_ack: 153 */ [acme@newtoy guinea_pig-2.6]$ Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-03 16:41:19 +01:00
};
void class_member__delete(struct class_member *member);
static inline struct class_member *tag__class_member(const struct tag *tag)
{
return (struct class_member *)tag;
}
static inline const char *class_member__name(const struct class_member *member)
dwarves: Remove some more DWARF details from the core Had to be a big sweeping change, but the regression tests shows just improvements :-) Now we stop using an id in struct tag, only storing the type, that now uses 16 bits only, as CTF does. Each format loader has to go on adding the types to the core, that figures out if it is a tag that can be on the tag->type field (tag__is_tag_type). Formats that already have the types separated and in sequence, such as CTF, just ask the core to insert in the types_table directly with its original ID. For DWARF, we ask the core to put it on the table, in sequence, and return the index, that is then stashed with the DWARF specific info (original id, type, decl_line, etc) and hashed by the original id. Later we recode everything, looking up via the original type, getting the small_id to put on the tag->type. The underlying debugging info not needed by the core is stashed in tag->priv, and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of the core tag and points it there, and makes that info available thru cu->orig_info. In the future we can ask, when loading a cu, that this info be trown away, so that we reduce the memory footprint for big multi-cu files such as the Linux kernel. There is also a routine to ask for inserting a NULL, as we still have bugs in the CTF decoding and thus some entries are being lost, to avoid using an undefined pointer when traversing the types_table the ctf loader puts a NULL there via cu__table_nullify_type_entry() and then cu__for_each_type skips those. There is some more cleanups for leftovers that I avoided cleaning to reduce this changeset. And also while doing this I saw that enums can appear without any enumerators and that an array with DW_TAG_GNU_vector is actually a different tag, encoded this way till we get to DWARF4 ;-) So now we don't have to lookup on a hash table looking for DWARF offsets, we can do the more sensible thing of just indexing the types_tags array. Now to do some cleanups and try to get the per cu encoder done. Then order all the cus per number of type entries, pick the one with more, then go on merging/recoding the types of the others and putting the parent linkage in place. Just to show the extent of the changes: $ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0 /home/acme/git/pahole/dwarves.c: struct cu | -4048 struct tag | -32 struct ptr_to_member_type | -32 struct namespace | -32 struct type | -32 struct class | -32 struct base_type | -32 struct array_type | -32 struct class_member | -32 struct lexblock | -32 struct ftype | -32 struct function | -64 struct parameter | -32 struct variable | -32 struct inline_expansion | -32 struct label | -32 struct enumerator | -32 17 structs changed tag__follow_typedef | +3 tag__fprintf_decl_info | +25 array_type__fprintf | +6 type__name | -126 type__find_first_biggest_size_base_type_member | -3 typedef__fprintf | +16 imported_declaration__fprintf | +6 imported_module__fprintf | +3 cu__new | +26 cu__delete | +26 hashtags__hash | -65 hash_64 | -124 hlist_add_head | -78 hashtags__find | -157 cu__hash | -80 cu__add_tag | +20 tag__prefix | -3 cu__find_tag_by_id | -2 cu__find_type_by_id | -3 cu__find_first_typedef_of_type | +38 cu__find_base_type_by_name | +68 cu__find_base_type_by_name_and_size | +72 cu__find_struct_by_name | +59 cus__find_struct_by_name | +8 cus__find_tag_by_id | +5 cus__find_cu_by_name | -6 lexblock__find_tag_by_id | -173 cu__find_variable_by_id | -197 list__find_tag_by_id | -308 cu__find_parameter_by_id | -60 tag__ptr_name | +6 tag__name | +15 variable__type | +13 variable__name | +7 class_member__size | +6 parameter__name | -119 tag__parameter | -14 parameter__type | -143 type__fprintf | -29 union__fprintf | +6 class__add_vtable_entry | -9 type__add_member | -6 type__clone_members | -3 enumeration__add | -6 function__name | -156 ftype__has_parm_of_type | -39 class__find_holes | -27 class__has_hole_ge | -3 type__nr_members_of_type | +3 lexblock__account_inline_expansions | +3 cu__account_inline_expansions | -18 ftype__fprintf_parms | +46 function__tag_fprintf | +24 lexblock__fprintf | -6 ftype__fprintf | +3 function__fprintf_stats | -18 function__size | -6 class__vtable_fprintf | -11 class__fprintf | -21 tag__fprintf | -35 60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541 /home/acme/git/pahole/ctf_loader.c: struct ctf_short_type | +0 14 structs changed type__init | -14 type__new | -9 class__new | -12 create_new_base_type | -7 create_new_base_type_float | -7 create_new_array | -8 create_new_subroutine_type | -9 create_full_members | -18 create_short_members | -18 create_new_class | +1 create_new_union | +1 create_new_enumeration | -19 create_new_forward_decl | -2 create_new_typedef | +3 create_new_tag | -5 load_types | +16 class__fixup_ctf_bitfields | -3 17 functions changed, 21 bytes added, 131 bytes removed, diff: -110 /home/acme/git/pahole/dwarf_loader.c: 17 structs changed zalloc | -56 tag__init | +3 array_type__new | +20 type__init | -24 class_member__new | +46 inline_expansion__new | +12 class__new | +81 lexblock__init | +19 function__new | +43 die__create_new_array | +20 die__create_new_parameter | +4 die__create_new_label | +4 die__create_new_subroutine_type | +113 die__create_new_enumeration | -21 die__process_class | +79 die__process_namespace | +76 die__create_new_inline_expansion | +4 die__process_function | +147 __die__process_tag | +34 die__process_unit | +56 die__process | +90 21 functions changed, 851 bytes added, 101 bytes removed, diff: +750 /home/acme/git/pahole/dwarves.c: struct ptr_table | +16 struct cu_orig_info | +32 2 structs changed tag__decl_line | +68 tag__decl_file | +70 tag__orig_id | +71 ptr_table__init | +46 ptr_table__exit | +37 ptr_table__add | +183 ptr_table__add_with_id | +165 ptr_table__entry | +64 cu__table_add_tag | +171 cu__table_nullify_type_entry | +38 10 functions changed, 913 bytes added, diff: +913 /home/acme/git/pahole/ctf_loader.c: 2 structs changed tag__alloc | +52 1 function changed, 52 bytes added, diff: +52 /home/acme/git/pahole/dwarf_loader.c: struct dwarf_tag | +48 struct dwarf_cu | +4104 4 structs changed dwarf_cu__init | +83 hashtags__hash | +61 hash_64 | +124 hlist_add_head | +78 hashtags__find | +161 cu__hash | +95 tag__is_tag_type | +171 tag__is_type | +85 tag__is_union | +28 tag__is_struct | +57 tag__is_typedef | +28 tag__is_enumeration | +28 dwarf_cu__find_tag_by_id | +56 dwarf_cu__find_type_by_id | +63 tag__alloc | +114 __tag__print_type_not_found | +108 namespace__recode_dwarf_types | +346 tag__namespace | +14 tag__has_namespace | +86 tag__is_namespace | +28 type__recode_dwarf_specification | +182 tag__type | +14 __tag__print_abstract_origin_not_found | +105 ftype__recode_dwarf_types | +322 tag__ftype | +14 tag__parameter | +14 lexblock__recode_dwarf_types | +736 tag__lexblock | +14 tag__label | +14 tag__recode_dwarf_type | +766 tag__ptr_to_member_type | +14 cu__recode_dwarf_types_table | +88 cu__recode_dwarf_types | +48 dwarf_tag__decl_file | +77 strings__ptr | +33 dwarf_tag__decl_line | +59 dwarf_tag__orig_id | +59 dwarf_tag__orig_type | +59 38 functions changed, 4432 bytes added, diff: +4432 build/libdwarves.so.1.0.0: 147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496 Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
{
return member->name;
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
}
static __pure inline int tag__is_class_member(const struct tag *tag)
{
return tag->tag == DW_TAG_member;
}
int tag__is_base_type(const struct tag *tag, const struct cu *cu);
bool tag__is_array(const struct tag *tag, const struct cu *cu);
pahole: Add == class member filtering Simplest one, wanna see just the PERF_RECORD_CGROUP records? $ pahole ~/bin/perf --seek_bytes=0x130 -C 'perf_event_header(sizeof=size,type=type,type_enum=perf_event_type,filter=type==PERF_RECORD_CGROUP)' < perf.data { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x28, }, .id = 0x1, .path = "/", }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x30, }, .id = 0x611, .path = "/system.slice", }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x30, }, .id = 0x8, .path = "/machine.slice", }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x80, }, .id = 0x1e94, .path = "/machine.slice/libpod-42be8e8d4eb9d22405845005f0d04ea398548dccc934a150fbaa3c1f1f9492c2.scope", }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x58, }, .id = 0xd, .path = "/machine.slice/machine-qemu\x2d1\x2drhel6.sandy.scope", }, Couldn't read record: 25441 bytes $ --seek_bytes was found from output of the data specific tool: perf record -D Then we didn't specify a --count because we don't know how many are in this specific perf.data file, the validations in place ended up producing the right result, with a warning about an invalid perf_event_header->size. In time we'll read this: $ pahole ~/bin/perf -C perf_file_header --count 1 < perf.data { .magic = 0x32454c4946524550, .size = 0x68, .attr_size = 0x88, .attrs = { .offset = 0xa8, .size = 0x88, }, .data = { .offset = 0x130, .size = 0x588, }, .event_types = { .offset = 0, .size = 0, }, .adds_features = { 0x16717ffc, 0, 0, 0 }, }, $ Like this: $ pahole ~/bin/perf header=perf_file_header --seek_bytes='$header.data.offset' --size='$header.data.size' \ -C 'perf_event_header(sizeof=size,type=type,type_enum=perf_event_type,filter=type==PERF_RECORD_CGROUP)' < perf.data I.e. strings outside options with a '=' assignment operator will be considered a pretty printing variable, one that we can subsequently use in options, expressions, etc. At some point we'll be able to describe an arbitrary file format and have a generic type based (BTF, DWARF, CTF, whatever) raw data pretty printer. As-is it is works already with any of the -C type fields: $ pahole ~/bin/perf --seek_bytes=0x130 -C 'perf_event_header(sizeof=size,type=type,type_enum=perf_event_type,filter=size==0x30)' --count 3 < perf.data { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x30, }, .id = 0x611, .path = "/system.slice", }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x30, }, .id = 0x8, .path = "/machine.slice", }, { .type = PERF_RECORD_EXIT, .misc = 0, .size = 0x30, }, $ pahole ~/bin/perf --seek_bytes=0x130 -C 'perf_event_header(sizeof=size,type=type,type_enum=perf_event_type,filter=misc==0)' --count 3 < perf.data { .type = 0x4f, .misc = 0, .size = 0x20, }, { .type = 0x49, .misc = 0, .size = 0x28, }, { .type = 0x4a, .misc = 0, .size = 0x20, }, $ Shouldn't be difficult to filter based on the demultiplexed types (i.e. filters like path==/etc/*). Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-07-17 17:35:26 +02:00
struct class_member_filter;
struct tag_cu_node {
struct list_head node;
struct tag_cu tc;
};
/**
* struct type - base type for enumerations, structs and unions
*
* @nnr_members: number of non static DW_TAG_member entries
* @nr_static_members: number of static DW_TAG_member entries
* @nr_tags: number of tags
* @alignment: DW_AT_alignement, zero if not present, gcc emits since circa 7.3.1
core: Improve the natural alignment calculation We need to take more than just arrays into account when figuring out the natural alignment of struct members, looking recursively at types till we get to basic types and pointers. Before this patch the 'new' struct field in the 'v' union was considered __packed__, when in fact it is not, as the natural alignment for the 'state_id' typedef is 4, so it can start at offset 36 (or 4 considering just its container struct), see below: $ pahole -IC nfsd4_lock /home/acme/git/build/v5.1-rc4+/fs/nfsd/nfs4xdr.o /* Used at: /home/acme/git/linux/fs/nfsd/nfs4xdr.c */ /* <1717a> /home/acme/git/linux/fs/nfsd/xdr4.h:156 */ struct nfsd4_lock { u32 lk_type; /* 0 4 */ u32 lk_reclaim; /* 4 4 */ u64 lk_offset; /* 8 8 */ u64 lk_length; /* 16 8 */ u32 lk_is_new; /* 24 4 */ /* XXX 4 bytes hole, try to pack */ union { struct { u32 open_seqid; /* 32 4 */ stateid_t open_stateid; /* 36 16 */ u32 lock_seqid; /* 52 4 */ clientid_t clientid; /* 56 8 */ /* --- cacheline 1 boundary (64 bytes) --- */ struct xdr_netobj owner; /* 64 16 */ } __attribute__((__packed__)) new; /* 32 48 */ struct { stateid_t lock_stateid; /* 32 16 */ u32 lock_seqid; /* 48 4 */ } __attribute__((__packed__)) old; /* 32 20 */ } v; /* 32 48 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ union { struct { stateid_t stateid; /* 80 16 */ } ok; /* 80 16 */ struct nfsd4_lock_denied denied; /* 80 48 */ } u; /* 80 48 */ /* size: 128, cachelines: 2, members: 7 */ /* sum members: 124, holes: 1, sum holes: 4 */ }; $ Asking for -rEIC, i.e. relative offsets, expand types we can see that stateid_t opaque type: struct { /* typedef u32 -> __u32 */ unsigned int open_seqid; /* 0 4 */ /* typedef stateid_t */ struct { /* typedef u32 -> __u32 */ unsigned int si_generation; /* 0 4 */ /* typedef stateid_opaque_t */ struct { /* typedef clientid_t */ struct { /* typedef u32 -> __u32 */ unsigned int cl_boot; /* 0 4 */ /* typedef u32 -> __u32 */ unsigned int cl_id; /* 4 4 */ } so_clid; /* 0 8 */ /* typedef u32 -> __u32 */ unsigned int so_id; /* 8 4 */ } si_opaque; /* 4 12 */ } open_stateid; /* 4 16 */ With the algorithm implemented in this patch we get it correctly as not packed: $ pahole -IC nfsd4_lock /home/acme/git/build/v5.1-rc4+/fs/nfsd/nfs4xdr.o /* Used at: /home/acme/git/linux/fs/nfsd/nfs4xdr.c */ /* <1717a> /home/acme/git/linux/fs/nfsd/xdr4.h:156 */ struct nfsd4_lock { u32 lk_type; /* 0 4 */ u32 lk_reclaim; /* 4 4 */ u64 lk_offset; /* 8 8 */ u64 lk_length; /* 16 8 */ u32 lk_is_new; /* 24 4 */ /* XXX 4 bytes hole, try to pack */ union { struct { u32 open_seqid; /* 32 4 */ stateid_t open_stateid; /* 36 16 */ u32 lock_seqid; /* 52 4 */ clientid_t clientid; /* 56 8 */ /* --- cacheline 1 boundary (64 bytes) --- */ struct xdr_netobj owner; /* 64 16 */ } new; /* 32 48 */ struct { stateid_t lock_stateid; /* 32 16 */ u32 lock_seqid; /* 48 4 */ } old; /* 32 20 */ } v; /* 32 48 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ union { struct { stateid_t stateid; /* 80 16 */ } ok; /* 80 16 */ struct nfsd4_lock_denied denied; /* 80 48 */ } u; /* 80 48 */ /* size: 128, cachelines: 2, members: 7 */ /* sum members: 124, holes: 1, sum holes: 4 */ }; Fixes: f2641ce169d6 ("core: Take arrays into account when inferring if a struct is packed") Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-11 21:36:49 +02:00
* @natural_alignment: For inferring __packed__, normally the widest scalar in it, recursively
* @sizeof_member: Use this to find the size of the record
pahole: Add the 'type' modifier to make a struct member be used to find a cast type This is the first step: $ pahole -V -C 'perf_event_header(sizeof=size,type=type)' ~/bin/perf pahole: sizeof_operator for 'perf_event_header' is 'size' pahole: type member for 'perf_event_header' is 'type' struct perf_event_header { __u32 type; /* 0 4 */ __u16 misc; /* 4 2 */ __u16 size; /* 6 2 */ /* size: 8, cachelines: 1, members: 3 */ /* last cacheline: 8 bytes */ }; $ Next step is to add another modifier that will point to an enum that maps the value in perf_event_header->type to a string that can then be used to lookup the type to be used to pretty print what is after 'sizeof(struct perf_event_header)', i.e. things like: $ pahole -EC perf_record_mmap ~/bin/perf struct perf_record_mmap { struct perf_event_header { /* typedef __u32 */ unsigned int type; /* 0 4 */ /* typedef __u16 */ short unsigned int misc; /* 4 2 */ /* typedef __u16 */ short unsigned int size; /* 6 2 */ } header; /* 0 8 */ /* typedef __u32 */ unsigned int pid; /* 8 4 */ /* typedef __u32 */ unsigned int tid; /* 12 4 */ /* typedef __u64 */ long long unsigned int start; /* 16 8 */ /* typedef __u64 */ long long unsigned int len; /* 24 8 */ /* typedef __u64 */ long long unsigned int pgoff; /* 32 8 */ char filename[4096]; /* 40 4096 */ /* size: 4136, cachelines: 65, members: 7 */ /* last cacheline: 40 bytes */ }; $ The various validations performed: $ pahole -V -C 'perf_event_header(sizeof=size,typ=type)' ~/bin/perf pahole: sizeof_operator for 'perf_event_header' is 'size' pahole: invalid arg 'typ' in 'perf_event_header(sizeof=size,typ=type)' (known args: sizeof=member, type=member) $ $ pahole -V -C 'perf_event_header(sizeof=size,type=bla)' ~/bin/perf pahole: sizeof_operator for 'perf_event_header' is 'size' pahole: type member for 'perf_event_header' is 'bla' pahole: the type member 'bla' wasn't found in the 'perf_event_header' type $ $ pahole -V -C 'perf_event_header(sizeof=size,type=type)' ~/bin/perf pahole: sizeof_operator for 'perf_event_header' is 'size' pahole: type member for 'perf_event_header' is 'type' struct perf_event_header { __u32 type; /* 0 4 */ __u16 misc; /* 4 2 */ __u16 size; /* 6 2 */ /* size: 8, cachelines: 1, members: 3 */ /* last cacheline: 8 bytes */ }; $ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-07-14 17:50:09 +02:00
* @type_member: Use this to select a member from where to get an id on an enum to find a type
* to cast for, needs to be used with the upcoming type_enum.
* @type_enum: enumeration(s) to use together with type_member to find a type to cast
* @member_prefix: the common prefix for all members, say in an enum, this should be calculated on demand
* @member_prefix_len: the lenght of the common prefix for all members
*/
struct type {
struct namespace namespace;
struct list_head node;
uint32_t size;
int32_t size_diff;
uint16_t nr_static_members;
uint16_t nr_members;
uint32_t alignment;
struct class_member *sizeof_member;
pahole: Add the 'type' modifier to make a struct member be used to find a cast type This is the first step: $ pahole -V -C 'perf_event_header(sizeof=size,type=type)' ~/bin/perf pahole: sizeof_operator for 'perf_event_header' is 'size' pahole: type member for 'perf_event_header' is 'type' struct perf_event_header { __u32 type; /* 0 4 */ __u16 misc; /* 4 2 */ __u16 size; /* 6 2 */ /* size: 8, cachelines: 1, members: 3 */ /* last cacheline: 8 bytes */ }; $ Next step is to add another modifier that will point to an enum that maps the value in perf_event_header->type to a string that can then be used to lookup the type to be used to pretty print what is after 'sizeof(struct perf_event_header)', i.e. things like: $ pahole -EC perf_record_mmap ~/bin/perf struct perf_record_mmap { struct perf_event_header { /* typedef __u32 */ unsigned int type; /* 0 4 */ /* typedef __u16 */ short unsigned int misc; /* 4 2 */ /* typedef __u16 */ short unsigned int size; /* 6 2 */ } header; /* 0 8 */ /* typedef __u32 */ unsigned int pid; /* 8 4 */ /* typedef __u32 */ unsigned int tid; /* 12 4 */ /* typedef __u64 */ long long unsigned int start; /* 16 8 */ /* typedef __u64 */ long long unsigned int len; /* 24 8 */ /* typedef __u64 */ long long unsigned int pgoff; /* 32 8 */ char filename[4096]; /* 40 4096 */ /* size: 4136, cachelines: 65, members: 7 */ /* last cacheline: 40 bytes */ }; $ The various validations performed: $ pahole -V -C 'perf_event_header(sizeof=size,typ=type)' ~/bin/perf pahole: sizeof_operator for 'perf_event_header' is 'size' pahole: invalid arg 'typ' in 'perf_event_header(sizeof=size,typ=type)' (known args: sizeof=member, type=member) $ $ pahole -V -C 'perf_event_header(sizeof=size,type=bla)' ~/bin/perf pahole: sizeof_operator for 'perf_event_header' is 'size' pahole: type member for 'perf_event_header' is 'bla' pahole: the type member 'bla' wasn't found in the 'perf_event_header' type $ $ pahole -V -C 'perf_event_header(sizeof=size,type=type)' ~/bin/perf pahole: sizeof_operator for 'perf_event_header' is 'size' pahole: type member for 'perf_event_header' is 'type' struct perf_event_header { __u32 type; /* 0 4 */ __u16 misc; /* 4 2 */ __u16 size; /* 6 2 */ /* size: 8, cachelines: 1, members: 3 */ /* last cacheline: 8 bytes */ }; $ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-07-14 17:50:09 +02:00
struct class_member *type_member;
pahole: Add == class member filtering Simplest one, wanna see just the PERF_RECORD_CGROUP records? $ pahole ~/bin/perf --seek_bytes=0x130 -C 'perf_event_header(sizeof=size,type=type,type_enum=perf_event_type,filter=type==PERF_RECORD_CGROUP)' < perf.data { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x28, }, .id = 0x1, .path = "/", }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x30, }, .id = 0x611, .path = "/system.slice", }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x30, }, .id = 0x8, .path = "/machine.slice", }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x80, }, .id = 0x1e94, .path = "/machine.slice/libpod-42be8e8d4eb9d22405845005f0d04ea398548dccc934a150fbaa3c1f1f9492c2.scope", }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x58, }, .id = 0xd, .path = "/machine.slice/machine-qemu\x2d1\x2drhel6.sandy.scope", }, Couldn't read record: 25441 bytes $ --seek_bytes was found from output of the data specific tool: perf record -D Then we didn't specify a --count because we don't know how many are in this specific perf.data file, the validations in place ended up producing the right result, with a warning about an invalid perf_event_header->size. In time we'll read this: $ pahole ~/bin/perf -C perf_file_header --count 1 < perf.data { .magic = 0x32454c4946524550, .size = 0x68, .attr_size = 0x88, .attrs = { .offset = 0xa8, .size = 0x88, }, .data = { .offset = 0x130, .size = 0x588, }, .event_types = { .offset = 0, .size = 0, }, .adds_features = { 0x16717ffc, 0, 0, 0 }, }, $ Like this: $ pahole ~/bin/perf header=perf_file_header --seek_bytes='$header.data.offset' --size='$header.data.size' \ -C 'perf_event_header(sizeof=size,type=type,type_enum=perf_event_type,filter=type==PERF_RECORD_CGROUP)' < perf.data I.e. strings outside options with a '=' assignment operator will be considered a pretty printing variable, one that we can subsequently use in options, expressions, etc. At some point we'll be able to describe an arbitrary file format and have a generic type based (BTF, DWARF, CTF, whatever) raw data pretty printer. As-is it is works already with any of the -C type fields: $ pahole ~/bin/perf --seek_bytes=0x130 -C 'perf_event_header(sizeof=size,type=type,type_enum=perf_event_type,filter=size==0x30)' --count 3 < perf.data { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x30, }, .id = 0x611, .path = "/system.slice", }, { .header = { .type = PERF_RECORD_CGROUP, .misc = 0, .size = 0x30, }, .id = 0x8, .path = "/machine.slice", }, { .type = PERF_RECORD_EXIT, .misc = 0, .size = 0x30, }, $ pahole ~/bin/perf --seek_bytes=0x130 -C 'perf_event_header(sizeof=size,type=type,type_enum=perf_event_type,filter=misc==0)' --count 3 < perf.data { .type = 0x4f, .misc = 0, .size = 0x20, }, { .type = 0x49, .misc = 0, .size = 0x28, }, { .type = 0x4a, .misc = 0, .size = 0x20, }, $ Shouldn't be difficult to filter based on the demultiplexed types (i.e. filters like path==/etc/*). Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-07-17 17:35:26 +02:00
struct class_member_filter *filter;
struct list_head type_enum;
char *member_prefix;
uint16_t member_prefix_len;
uint16_t max_tag_name_len;
core: Improve the natural alignment calculation We need to take more than just arrays into account when figuring out the natural alignment of struct members, looking recursively at types till we get to basic types and pointers. Before this patch the 'new' struct field in the 'v' union was considered __packed__, when in fact it is not, as the natural alignment for the 'state_id' typedef is 4, so it can start at offset 36 (or 4 considering just its container struct), see below: $ pahole -IC nfsd4_lock /home/acme/git/build/v5.1-rc4+/fs/nfsd/nfs4xdr.o /* Used at: /home/acme/git/linux/fs/nfsd/nfs4xdr.c */ /* <1717a> /home/acme/git/linux/fs/nfsd/xdr4.h:156 */ struct nfsd4_lock { u32 lk_type; /* 0 4 */ u32 lk_reclaim; /* 4 4 */ u64 lk_offset; /* 8 8 */ u64 lk_length; /* 16 8 */ u32 lk_is_new; /* 24 4 */ /* XXX 4 bytes hole, try to pack */ union { struct { u32 open_seqid; /* 32 4 */ stateid_t open_stateid; /* 36 16 */ u32 lock_seqid; /* 52 4 */ clientid_t clientid; /* 56 8 */ /* --- cacheline 1 boundary (64 bytes) --- */ struct xdr_netobj owner; /* 64 16 */ } __attribute__((__packed__)) new; /* 32 48 */ struct { stateid_t lock_stateid; /* 32 16 */ u32 lock_seqid; /* 48 4 */ } __attribute__((__packed__)) old; /* 32 20 */ } v; /* 32 48 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ union { struct { stateid_t stateid; /* 80 16 */ } ok; /* 80 16 */ struct nfsd4_lock_denied denied; /* 80 48 */ } u; /* 80 48 */ /* size: 128, cachelines: 2, members: 7 */ /* sum members: 124, holes: 1, sum holes: 4 */ }; $ Asking for -rEIC, i.e. relative offsets, expand types we can see that stateid_t opaque type: struct { /* typedef u32 -> __u32 */ unsigned int open_seqid; /* 0 4 */ /* typedef stateid_t */ struct { /* typedef u32 -> __u32 */ unsigned int si_generation; /* 0 4 */ /* typedef stateid_opaque_t */ struct { /* typedef clientid_t */ struct { /* typedef u32 -> __u32 */ unsigned int cl_boot; /* 0 4 */ /* typedef u32 -> __u32 */ unsigned int cl_id; /* 4 4 */ } so_clid; /* 0 8 */ /* typedef u32 -> __u32 */ unsigned int so_id; /* 8 4 */ } si_opaque; /* 4 12 */ } open_stateid; /* 4 16 */ With the algorithm implemented in this patch we get it correctly as not packed: $ pahole -IC nfsd4_lock /home/acme/git/build/v5.1-rc4+/fs/nfsd/nfs4xdr.o /* Used at: /home/acme/git/linux/fs/nfsd/nfs4xdr.c */ /* <1717a> /home/acme/git/linux/fs/nfsd/xdr4.h:156 */ struct nfsd4_lock { u32 lk_type; /* 0 4 */ u32 lk_reclaim; /* 4 4 */ u64 lk_offset; /* 8 8 */ u64 lk_length; /* 16 8 */ u32 lk_is_new; /* 24 4 */ /* XXX 4 bytes hole, try to pack */ union { struct { u32 open_seqid; /* 32 4 */ stateid_t open_stateid; /* 36 16 */ u32 lock_seqid; /* 52 4 */ clientid_t clientid; /* 56 8 */ /* --- cacheline 1 boundary (64 bytes) --- */ struct xdr_netobj owner; /* 64 16 */ } new; /* 32 48 */ struct { stateid_t lock_stateid; /* 32 16 */ u32 lock_seqid; /* 48 4 */ } old; /* 32 20 */ } v; /* 32 48 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ union { struct { stateid_t stateid; /* 80 16 */ } ok; /* 80 16 */ struct nfsd4_lock_denied denied; /* 80 48 */ } u; /* 80 48 */ /* size: 128, cachelines: 2, members: 7 */ /* sum members: 124, holes: 1, sum holes: 4 */ }; Fixes: f2641ce169d6 ("core: Take arrays into account when inferring if a struct is packed") Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-11 21:36:49 +02:00
uint16_t natural_alignment;
bool packed_attributes_inferred;
uint8_t declaration; /* only one bit used */
uint8_t definition_emitted:1;
uint8_t fwd_decl_emitted:1;
uint8_t resized:1;
};
void __type__init(struct type *type);
static inline struct class *type__class(const struct type *type)
{
return (struct class *)type;
}
[PAHOLE]: Print cacheline boundaries Cacheline size defaults to 32, sample output changing the default to 64 bytes: pahole --cacheline=64 ../../acme/OUTPUT/qemu/net-2.6/net/ipv4/tcp.o inode /* /pub/scm/linux/kernel/git/acme/net-2.6/include/linux/dcache.h:86 */ struct inode { struct hlist_node i_hash; /* 0 8 */ struct list_head i_list; /* 8 8 */ struct list_head i_sb_list; /* 16 8 */ struct list_head i_dentry; /* 24 8 */ long unsigned int i_ino; /* 32 4 */ atomic_t i_count; /* 36 4 */ umode_t i_mode; /* 40 2 */ /* XXX 2 bytes hole, try to pack */ unsigned int i_nlink; /* 44 4 */ uid_t i_uid; /* 48 4 */ gid_t i_gid; /* 52 4 */ dev_t i_rdev; /* 56 4 */ loff_t i_size; /* 60 8 */ struct timespec i_atime; /* 68 8 */ struct timespec i_mtime; /* 76 8 */ struct timespec i_ctime; /* 84 8 */ unsigned int i_blkbits; /* 92 4 */ long unsigned int i_version; /* 96 4 */ blkcnt_t i_blocks; /* 100 4 */ short unsigned int i_bytes; /* 104 2 */ spinlock_t i_lock; /* 106 0 */ /* XXX 2 bytes hole, try to pack */ struct mutex i_mutex; /* 108 24 */ /* ---------- cacheline 2 boundary ---------- */ struct rw_semaphore i_alloc_sem; /* 132 12 */ struct inode_operations * i_op; /* 144 4 */ const struct file_operations * i_fop; /* 148 4 */ struct super_block * i_sb; /* 152 4 */ struct file_lock * i_flock; /* 156 4 */ struct address_space * i_mapping; /* 160 4 */ struct address_space i_data; /* 164 72 */ struct list_head i_devices; /* 236 8 */ union ; /* 244 4 */ int i_cindex; /* 248 4 */ __u32 i_generation; /* 252 4 */ long unsigned int i_dnotify_mask; /* 256 4 */ /* ---------- cacheline 4 boundary ---------- */ struct dnotify_struct * i_dnotify; /* 260 4 */ struct list_head inotify_watches; /* 264 8 */ struct mutex inotify_mutex; /* 272 24 */ long unsigned int i_state; /* 296 4 */ long unsigned int dirtied_when; /* 300 4 */ unsigned int i_flags; /* 304 4 */ atomic_t i_writecount; /* 308 4 */ void * i_private; /* 312 4 */ }; /* size: 316, sum members: 312, holes: 2, sum holes: 4 */ Has to be improved to show the other cacheline boundaries, that may be buried into a included struct or union. Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 18:34:54 +01:00
static inline struct tag *type__tag(const struct type *type)
{
return (struct tag *)type;
}
void type__delete(struct type *type);
/**
* type__for_each_tag - iterate thru all the tags
* @type: struct type instance to iterate
* @pos: struct tag iterator
*/
#define type__for_each_tag(type, pos) \
list_for_each_entry(pos, &(type)->namespace.tags, node)
/**
* type__for_each_enumerator - iterate thru the enumerator entries
* @type: struct type instance to iterate
* @pos: struct enumerator iterator
*/
#define type__for_each_enumerator(type, pos) \
struct list_head *__type__for_each_enumerator_head = \
(type)->namespace.shared_tags ? \
(type)->namespace.tags.next : \
&(type)->namespace.tags; \
list_for_each_entry(pos, __type__for_each_enumerator_head, tag.node)
/**
* type__for_each_enumerator_safe_reverse - safely iterate thru the enumerator entries, in reverse order
* @type: struct type instance to iterate
* @pos: struct enumerator iterator
* @n: struct enumerator temp iterator
*/
#define type__for_each_enumerator_safe_reverse(type, pos, n) \
if ((type)->namespace.shared_tags) /* Do nothing */ ; else \
list_for_each_entry_safe_reverse(pos, n, &(type)->namespace.tags, tag.node)
/**
* type__for_each_member - iterate thru the entries that use space
* (data members and inheritance entries)
* @type: struct type instance to iterate
* @pos: struct class_member iterator
*/
#define type__for_each_member(type, pos) \
list_for_each_entry(pos, &(type)->namespace.tags, tag.node) \
if (!(pos->tag.tag == DW_TAG_member || \
pos->tag.tag == DW_TAG_inheritance)) \
continue; \
else
/**
* type__for_each_data_member - iterate thru the data member entries
* @type: struct type instance to iterate
* @pos: struct class_member iterator
*/
#define type__for_each_data_member(type, pos) \
list_for_each_entry(pos, &(type)->namespace.tags, tag.node) \
if (pos->tag.tag != DW_TAG_member) \
continue; \
else
/**
* type__for_each_member_safe - safely iterate thru the entries that use space
* (data members and inheritance entries)
* @type: struct type instance to iterate
* @pos: struct class_member iterator
* @n: struct class_member temp iterator
*/
#define type__for_each_member_safe(type, pos, n) \
list_for_each_entry_safe(pos, n, &(type)->namespace.tags, tag.node) \
if (pos->tag.tag != DW_TAG_member) \
continue; \
else
/**
* type__for_each_data_member_safe - safely iterate thru the data member entries
* @type: struct type instance to iterate
* @pos: struct class_member iterator
* @n: struct class_member temp iterator
*/
#define type__for_each_data_member_safe(type, pos, n) \
list_for_each_entry_safe(pos, n, &(type)->namespace.tags, tag.node) \
if (pos->tag.tag != DW_TAG_member) \
continue; \
else
/**
* type__for_each_tag_safe_reverse - safely iterate thru all tags in a type, in reverse order
* @type: struct type instance to iterate
* @pos: struct class_member iterator
* @n: struct class_member temp iterator
*/
#define type__for_each_tag_safe_reverse(type, pos, n) \
list_for_each_entry_safe_reverse(pos, n, &(type)->namespace.tags, tag.node)
void type__add_member(struct type *type, struct class_member *member);
struct class_member *
type__find_first_biggest_size_base_type_member(struct type *type,
const struct cu *cu);
struct class_member *type__find_member_by_name(const struct type *type, const char *name);
uint32_t type__nr_members_of_type(const struct type *type, const type_id_t oftype);
struct class_member *type__last_member(struct type *type);
void enumerations__calc_prefix(struct list_head *enumerations);
size_t typedef__fprintf(const struct tag *tag_type, const struct cu *cu,
const struct conf_fprintf *conf, FILE *fp);
static inline struct type *tag__type(const struct tag *tag)
{
return (struct type *)tag;
}
struct class {
struct type type;
struct list_head vtable;
uint16_t nr_vtable_entries;
uint8_t nr_holes;
uint8_t nr_bit_holes;
uint16_t pre_hole;
uint16_t padding;
uint8_t pre_bit_hole;
uint8_t bit_padding;
bool holes_searched;
core: Infer if a struct is packed by the offsets/natural alignments As DWARF (nor BTF) provides explicit attributes, we need to look at the natural alignments, a byte is always alignted, etc. This probably fails with things like __attribute__(__aligned(power-of-two)), but with it most of the kernel data structures are full circled, i.e. 'pfunct --compile' regenerates source code from debug info that when compiled generats debug info that end up matching the original sources. $ cat a.c #define __packed __attribute__((__packed__)) struct filename { const char * name; const char * uptr; int refcnt; }; void m(struct filename *f) {} $ gcc -g -c a.c $ pahole a.o struct filename { const char * name; /* 0 8 */ const char * uptr; /* 8 8 */ int refcnt; /* 16 4 */ /* size: 24, cachelines: 1, members: 3 */ /* padding: 4 */ /* last cacheline: 24 bytes */ }; $ cat a.c #define __packed __attribute__((__packed__)) struct filename { const char * name; const char * uptr; int refcnt; } __packed; void m(struct filename *f) {} $ gcc -g -c a.c $ pahole a.o struct filename { const char * name; /* 0 8 */ const char * uptr; /* 8 8 */ int refcnt; /* 16 4 */ /* size: 20, cachelines: 1, members: 3 */ /* last cacheline: 20 bytes */ } __attribute__((__packed__)); $ cat a.c #define __packed __attribute__((__packed__)) struct filename { const char * name; int refcnt; const char * uptr; }; void m(struct filename *f) {} $ gcc -g -c a.c $ pahole a.o struct filename { const char * name; /* 0 8 */ int refcnt; /* 8 4 */ /* XXX 4 bytes hole, try to pack */ const char * uptr; /* 16 8 */ /* size: 24, cachelines: 1, members: 3 */ /* sum members: 20, holes: 1, sum holes: 4 */ /* last cacheline: 24 bytes */ }; $ cat a.c #define __packed __attribute__((__packed__)) struct filename { const char * name; int refcnt; const char * uptr; } __packed; void m(struct filename *f) {} $ gcc -g -c a.c $ pahole a.o struct filename { const char * name; /* 0 8 */ int refcnt; /* 8 4 */ const char * uptr; /* 12 8 */ /* size: 20, cachelines: 1, members: 3 */ /* last cacheline: 20 bytes */ } __attribute__((__packed__)); $ cat a.c #define __packed __attribute__((__packed__)) struct filename { const char * name; const char * uptr; unsigned char refcnt; }; void m(struct filename *f) {} $ gcc -g -c a.c $ pahole a.o struct filename { const char * name; /* 0 8 */ const char * uptr; /* 8 8 */ unsigned char refcnt; /* 16 1 */ /* size: 24, cachelines: 1, members: 3 */ /* padding: 7 */ /* last cacheline: 24 bytes */ }; $ cat a.c #define __packed __attribute__((__packed__)) struct filename { const char * name; const char * uptr; unsigned char refcnt; } __packed; void m(struct filename *f) {} $ gcc -g -c a.c $ pahole a.o struct filename { const char * name; /* 0 8 */ const char * uptr; /* 8 8 */ unsigned char refcnt; /* 16 1 */ /* size: 17, cachelines: 1, members: 3 */ /* last cacheline: 17 bytes */ } __attribute__((__packed__)); $ cat a.c #define __packed __attribute__((__packed__)) struct filename { const char * name; unsigned char refcnt; const char * uptr; }; void m(struct filename *f) {} $ gcc -g -c a.c $ pahole a.o struct filename { const char * name; /* 0 8 */ unsigned char refcnt; /* 8 1 */ /* XXX 7 bytes hole, try to pack */ const char * uptr; /* 16 8 */ /* size: 24, cachelines: 1, members: 3 */ /* sum members: 17, holes: 1, sum holes: 7 */ /* last cacheline: 24 bytes */ }; $ cat a.c #define __packed __attribute__((__packed__)) struct filename { const char * name; unsigned char refcnt; const char * uptr; } __packed; void m(struct filename *f) {} $ gcc -g -c a.c $ pahole a.o struct filename { const char * name; /* 0 8 */ unsigned char refcnt; /* 8 1 */ const char * uptr; /* 9 8 */ /* size: 17, cachelines: 1, members: 3 */ /* last cacheline: 17 bytes */ } __attribute__((__packed__)); $ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-10 22:41:59 +02:00
bool is_packed;
void *priv;
};
static inline struct class *tag__class(const struct tag *tag)
{
return (struct class *)tag;
}
static inline struct tag *class__tag(const struct class *cls)
{
return (struct tag *)cls;
}
struct class *class__clone(const struct class *from, const char *new_class_name);
void class__delete(struct class *cls);
static inline struct list_head *class__tags(struct class *cls)
{
return &cls->type.namespace.tags;
}
static __pure inline const char *namespace__name(const struct namespace *nspace)
{
return nspace->name;
}
static __pure inline const char *type__name(const struct type *type)
{
return namespace__name(&type->namespace);
}
static __pure inline const char *class__name(struct class *cls)
{
return type__name(&cls->type);
}
static inline int class__is_struct(const struct class *cls)
{
return tag__is_struct(&cls->type.namespace.tag);
}
void class__find_holes(struct class *cls);
int class__has_hole_ge(const struct class *cls, const uint16_t size);
core: Infer if a struct is packed by the offsets/natural alignments As DWARF (nor BTF) provides explicit attributes, we need to look at the natural alignments, a byte is always alignted, etc. This probably fails with things like __attribute__(__aligned(power-of-two)), but with it most of the kernel data structures are full circled, i.e. 'pfunct --compile' regenerates source code from debug info that when compiled generats debug info that end up matching the original sources. $ cat a.c #define __packed __attribute__((__packed__)) struct filename { const char * name; const char * uptr; int refcnt; }; void m(struct filename *f) {} $ gcc -g -c a.c $ pahole a.o struct filename { const char * name; /* 0 8 */ const char * uptr; /* 8 8 */ int refcnt; /* 16 4 */ /* size: 24, cachelines: 1, members: 3 */ /* padding: 4 */ /* last cacheline: 24 bytes */ }; $ cat a.c #define __packed __attribute__((__packed__)) struct filename { const char * name; const char * uptr; int refcnt; } __packed; void m(struct filename *f) {} $ gcc -g -c a.c $ pahole a.o struct filename { const char * name; /* 0 8 */ const char * uptr; /* 8 8 */ int refcnt; /* 16 4 */ /* size: 20, cachelines: 1, members: 3 */ /* last cacheline: 20 bytes */ } __attribute__((__packed__)); $ cat a.c #define __packed __attribute__((__packed__)) struct filename { const char * name; int refcnt; const char * uptr; }; void m(struct filename *f) {} $ gcc -g -c a.c $ pahole a.o struct filename { const char * name; /* 0 8 */ int refcnt; /* 8 4 */ /* XXX 4 bytes hole, try to pack */ const char * uptr; /* 16 8 */ /* size: 24, cachelines: 1, members: 3 */ /* sum members: 20, holes: 1, sum holes: 4 */ /* last cacheline: 24 bytes */ }; $ cat a.c #define __packed __attribute__((__packed__)) struct filename { const char * name; int refcnt; const char * uptr; } __packed; void m(struct filename *f) {} $ gcc -g -c a.c $ pahole a.o struct filename { const char * name; /* 0 8 */ int refcnt; /* 8 4 */ const char * uptr; /* 12 8 */ /* size: 20, cachelines: 1, members: 3 */ /* last cacheline: 20 bytes */ } __attribute__((__packed__)); $ cat a.c #define __packed __attribute__((__packed__)) struct filename { const char * name; const char * uptr; unsigned char refcnt; }; void m(struct filename *f) {} $ gcc -g -c a.c $ pahole a.o struct filename { const char * name; /* 0 8 */ const char * uptr; /* 8 8 */ unsigned char refcnt; /* 16 1 */ /* size: 24, cachelines: 1, members: 3 */ /* padding: 7 */ /* last cacheline: 24 bytes */ }; $ cat a.c #define __packed __attribute__((__packed__)) struct filename { const char * name; const char * uptr; unsigned char refcnt; } __packed; void m(struct filename *f) {} $ gcc -g -c a.c $ pahole a.o struct filename { const char * name; /* 0 8 */ const char * uptr; /* 8 8 */ unsigned char refcnt; /* 16 1 */ /* size: 17, cachelines: 1, members: 3 */ /* last cacheline: 17 bytes */ } __attribute__((__packed__)); $ cat a.c #define __packed __attribute__((__packed__)) struct filename { const char * name; unsigned char refcnt; const char * uptr; }; void m(struct filename *f) {} $ gcc -g -c a.c $ pahole a.o struct filename { const char * name; /* 0 8 */ unsigned char refcnt; /* 8 1 */ /* XXX 7 bytes hole, try to pack */ const char * uptr; /* 16 8 */ /* size: 24, cachelines: 1, members: 3 */ /* sum members: 17, holes: 1, sum holes: 7 */ /* last cacheline: 24 bytes */ }; $ cat a.c #define __packed __attribute__((__packed__)) struct filename { const char * name; unsigned char refcnt; const char * uptr; } __packed; void m(struct filename *f) {} $ gcc -g -c a.c $ pahole a.o struct filename { const char * name; /* 0 8 */ unsigned char refcnt; /* 8 1 */ const char * uptr; /* 9 8 */ /* size: 17, cachelines: 1, members: 3 */ /* last cacheline: 17 bytes */ } __attribute__((__packed__)); $ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-10 22:41:59 +02:00
bool class__infer_packed_attributes(struct class *cls, const struct cu *cu);
core: Infer __packed__ for union struct members I.e. check that all the structs that are embedded in a union have their natural alignment satisfied by the size of the array they are contained in, Before this change we ended up not marking union struct members that didn't had natural alignment violations as __packed__ even tho they had to be to be in a struct that didn't satisfied their natural alignment requirements, which would violate them when said union was in an array, i.e. the second entry would have the non __packed__ union struct member in a bad position. E.g. Before: $ pahole -C ceph_osd_op /home/acme/git/build/v5.1-rc4+/net/ceph/osd_client.o struct ceph_osd_op { __le16 op; /* 0 2 */ __le32 flags; /* 2 4 */ union { struct { __le64 offset; /* 6 8 */ __le64 length; /* 14 8 */ __le64 truncate_size; /* 22 8 */ __le32 truncate_seq; /* 30 4 */ } __attribute__((__packed__)) extent; /* 6 28 */ struct { __le32 name_len; /* 6 4 */ __le32 value_len; /* 10 4 */ __u8 cmp_op; /* 14 1 */ __u8 cmp_mode; /* 15 1 */ } __attribute__((__packed__)) xattr; /* 6 10 */ struct { __u8 class_len; /* 6 1 */ __u8 method_len; /* 7 1 */ __u8 argc; /* 8 1 */ __le32 indata_len; /* 9 4 */ } __attribute__((__packed__)) cls; /* 6 7 */ struct { __le64 cookie; /* 6 8 */ __le64 count; /* 14 8 */ } pgls; /* 6 16 */ struct { __le64 snapid; /* 6 8 */ } snap; /* 6 8 */ struct { __le64 cookie; /* 6 8 */ __le64 ver; /* 14 8 */ __u8 op; /* 22 1 */ __le32 gen; /* 23 4 */ } __attribute__((__packed__)) watch; /* 6 21 */ struct { __le64 cookie; /* 6 8 */ } notify; /* 6 8 */ struct { __le64 offset; /* 6 8 */ __le64 length; /* 14 8 */ __le64 src_offset; /* 22 8 */ } clonerange; /* 6 24 */ struct { __le64 expected_object_size; /* 6 8 */ __le64 expected_write_size; /* 14 8 */ } alloc_hint; /* 6 16 */ struct { __le64 snapid; /* 6 8 */ __le64 src_version; /* 14 8 */ __u8 flags; /* 22 1 */ __le32 src_fadvise_flags; /* 23 4 */ } __attribute__((__packed__)) copy_from; /* 6 21 */ }; /* 6 28 */ __le32 payload_len; /* 34 4 */ /* size: 38, cachelines: 1, members: 4 */ /* last cacheline: 38 bytes */ } __attribute__((__packed__)); After: $ pahole -C ceph_osd_op /home/acme/git/build/v5.1-rc4+/net/ceph/osd_client.o struct ceph_osd_op { __le16 op; /* 0 2 */ __le32 flags; /* 2 4 */ union { struct { __le64 offset; /* 6 8 */ __le64 length; /* 14 8 */ __le64 truncate_size; /* 22 8 */ __le32 truncate_seq; /* 30 4 */ } __attribute__((__packed__)) extent; /* 6 28 */ struct { __le32 name_len; /* 6 4 */ __le32 value_len; /* 10 4 */ __u8 cmp_op; /* 14 1 */ __u8 cmp_mode; /* 15 1 */ } __attribute__((__packed__)) xattr; /* 6 10 */ struct { __u8 class_len; /* 6 1 */ __u8 method_len; /* 7 1 */ __u8 argc; /* 8 1 */ __le32 indata_len; /* 9 4 */ } __attribute__((__packed__)) cls; /* 6 7 */ struct { __le64 cookie; /* 6 8 */ __le64 count; /* 14 8 */ } pgls; /* 6 16 */ struct { __le64 snapid; /* 6 8 */ } snap; /* 6 8 */ struct { __le64 cookie; /* 6 8 */ __le64 ver; /* 14 8 */ __u8 op; /* 22 1 */ __le32 gen; /* 23 4 */ } __attribute__((__packed__)) watch; /* 6 21 */ struct { __le64 cookie; /* 6 8 */ } notify; /* 6 8 */ struct { __le64 offset; /* 6 8 */ __le64 length; /* 14 8 */ __le64 src_offset; /* 22 8 */ } clonerange; /* 6 24 */ struct { __le64 expected_object_size; /* 6 8 */ __le64 expected_write_size; /* 14 8 */ } alloc_hint; /* 6 16 */ struct { __le64 snapid; /* 6 8 */ __le64 src_version; /* 14 8 */ __u8 flags; /* 22 1 */ __le32 src_fadvise_flags; /* 23 4 */ } __attribute__((__packed__)) copy_from; /* 6 21 */ }; /* 6 28 */ __le32 payload_len; /* 34 4 */ /* size: 38, cachelines: 1, members: 4 */ /* last cacheline: 38 bytes */ } __attribute__((__packed__)); $ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-12 22:08:41 +02:00
void union__infer_packed_attributes(struct type *type, const struct cu *cu);
core: Use unnatural alignment of struct embedded in another to infer __packed__ Since we don't have something like DW_AT_alignment for __attribute__((__packed__)), we need to use whatever hints that are there in the alignments to figure out if a naturally packed struct has the __attribute__((packed)) in the original sources, because that is needed to waiver its natural alignment requisites. For instance, /* Used at: btrfs.c */ /* <1e7b> /home/acme/git/pahole/btrfs.c:199 */ struct btrfs_block_group_cache { struct btrfs_key key; /* 0 17 */ struct btrfs_block_group_item item; /* 17 24 */ /* XXX 7 bytes hole, try to pack */ struct btrfs_fs_info * fs_info; /* 48 8 */ struct inode * inode; /* 56 8 */ In the original source code, btrfs_block_group_item is marked __packed__, and being so, even seemingly unnecessarily, makes it, when embedded in another struct, like the above, forfeit its natural alingment, that would be 8 bytes, and instead appear right at the 17th byte offset... struct btrfs_block_group_item { __le64 used; /* 0 8 */ __le64 chunk_objectid; /* 8 8 */ __le64 flags; /* 16 8 */ /* size: 24, cachelines: 1, members: 3 */ /* last cacheline: 24 bytes */ } __attribute__((__packed__)); So we need to, seeing its use at a unnatural offset, go backwards to the btrfs_block_group_item pahole internal data structure, 'struct type' and mark is_packed field as 'true', despite it not looking like a packed struct. Same thing with: struct ieee80211_mcs_info { u8 rx_mask[10]; /* 0 10 */ __le16 rx_highest; /* 10 2 */ u8 tx_params; /* 12 1 */ u8 reserved[3]; /* 13 3 */ /* size: 16, cachelines: 1, members: 4 */ /* last cacheline: 16 bytes */ }; That is naturally aligned and as 16 bytes, a power of two, then when it appears at the end of: $ pahole -IC ieee80211_sta_ht_cap vht.o /* Used at: vht.c */ /* <31ea> /home/acme/git/pahole/vht.c:1769 */ struct ieee80211_sta_ht_cap { u16 cap; /* 0 2 */ bool ht_supported; /* 2 1 */ u8 ampdu_factor; /* 3 1 */ u8 ampdu_density; /* 4 1 */ /* XXX 1 byte hole, try to pack */ struct ieee80211_mcs_info mcs; /* 6 16 */ /* size: 22, cachelines: 1, members: 5 */ /* sum members: 21, holes: 1, sum holes: 1 */ /* last cacheline: 22 bytes */ }; $ We get that one byte hole if ieee80211_mcs_info isn't marked __packed__, as soon as we mark it: $ pahole -IC ieee80211_sta_ht_cap vht.o /* Used at: vht.c */ /* <31ea> /home/acme/git/pahole/vht.c:1769 */ struct ieee80211_sta_ht_cap { u16 cap; /* 0 2 */ bool ht_supported; /* 2 1 */ u8 ampdu_factor; /* 3 1 */ u8 ampdu_density; /* 4 1 */ struct ieee80211_mcs_info mcs; /* 5 16 */ /* size: 22, cachelines: 1, members: 5 */ /* padding: 1 */ /* last cacheline: 22 bytes */ }; [acme@quaco pahole]$ It works, so __packed__ in this case just says: trow away the natural alignment, make it 1 in whatever container structs. So, before emitting the types for some struct, we go back looking at each of its members and checking for such unnatural offsets, marking the types as __packed__. Now: $ pfunct --compile /home/acme/git/build/v5.1-rc4+/net/mac80211/vht.o | grep "^struct ieee80211_mcs_info" -A8 struct ieee80211_mcs_info { u8 rx_mask[10]; /* 0 10 */ __le16 rx_highest; /* 10 2 */ u8 tx_params; /* 12 1 */ u8 reserved[3]; /* 13 3 */ /* size: 16, cachelines: 1, members: 4 */ /* last cacheline: 16 bytes */ } __attribute__((__packed__)); $ $ pfunct --compile /home/acme/git/build/v5.1-rc4+/fs/btrfs/free-space-tree.o | grep "^struct btrfs_block_group_item" -A7 struct btrfs_block_group_item { __le64 used; /* 0 8 */ __le64 chunk_objectid; /* 8 8 */ __le64 flags; /* 16 8 */ /* size: 24, cachelines: 1, members: 3 */ /* last cacheline: 24 bytes */ } __attribute__((__packed__)); $ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-15 20:51:16 +02:00
void type__check_structs_at_unnatural_alignments(struct type *type, const struct cu *cu);
size_t class__fprintf(struct class *cls, const struct cu *cu, FILE *fp);
void class__add_vtable_entry(struct class *cls, struct function *vtable_entry);
static inline struct class_member *
class__find_member_by_name(const struct class *cls,
const struct cu *cu, const char *name)
{
return type__find_member_by_name(&cls->type, name);
}
static inline uint16_t class__nr_members(const struct class *cls)
{
return cls->type.nr_members;
}
static inline uint32_t class__size(const struct class *cls)
{
return cls->type.size;
}
static inline int class__is_declaration(const struct class *cls)
{
return cls->type.declaration;
}
[CODIFF]: Detect and print all sorts of changes in structs [acme@newtoy examples]$ cat struct.c static struct foo { char a:2; unsigned int b; unsigned long c; unsigned long d; unsigned long e; } bar; int main(int argc, char *argv[]) { printf("%d", bar.a); } [acme@newtoy examples]$ Then change "a:2" to "a:4": [acme@newtoy examples]$ codiff -V old_struct new_struct struct.c: struct foo | +0 a:2; from: char /* 0(6) 1(2) */ to: char /* 0(4) 1(4) */ 1 struct changed Now, on top of that move a after b: [acme@newtoy examples]$ codiff -V old_struct new_struct struct.c: struct foo | +0 a:2; from: char /* 0(6) 1(2) */ to: char /* 4(4) 1(4) */ b; from: unsigned int /* 4(0) 4(0) */ to: unsigned int /* 0(0) 4(0) */ 1 struct changed [acme@newtoy examples]$ Move it back a to before b and change the type of e without changing its size, i.e. from unsigned long to long: [acme@newtoy examples]$ codiff -V old_struct new_struct struct.c: struct foo | +0 a:2; from: char /* 0(6) 1(2) */ to: char /* 0(4) 1(4) */ e; from: long unsigned int /* 16(0) 4(0) */ to: long int /* 16(0) 4(0) */ 1 struct changed [acme@newtoy examples]$ Now on top of this lets delete the c member: [acme@newtoy examples]$ codiff -V old_struct new_struct struct.c: struct foo | -4 nr_members: -1 -long unsigned int c; /* 8 4 */ a:2; from: char /* 0(6) 1(2) */ to: char /* 0(4) 1(4) */ d; from: long unsigned int /* 12(0) 4(0) */ to: long unsigned int /* 8(0) 4(0) */ e; from: long unsigned int /* 16(0) 4(0) */ to: long int /* 12(0) 4(0) */ 1 struct changed [acme@newtoy examples]$ WOW, many changes, what an ABI breakage, no? :-) It started as: [acme@newtoy examples]$ pahole old_struct foo /* /home/acme/pahole/examples/struct.c:3 */ struct foo { char a:2; /* 0 1 */ /* XXX 3 bytes hole, try to pack */ unsigned int b; /* 4 4 */ long unsigned int c; /* 8 4 */ long unsigned int d; /* 12 4 */ long unsigned int e; /* 16 4 */ }; /* size: 20, sum members: 17, holes: 1, sum holes: 3 */ And ended up as: [acme@newtoy examples]$ pahole new_struct foo /* /home/acme/pahole/examples/struct.c:3 */ struct foo { char a:4; /* 0 1 */ /* XXX 3 bytes hole, try to pack */ unsigned int b; /* 4 4 */ long unsigned int d; /* 8 4 */ long int e; /* 12 4 */ }; /* size: 16, sum members: 13, holes: 1, sum holes: 3 */ [acme@newtoy examples]$ Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 18:07:21 +01:00
const struct class_member *class__find_bit_hole(const struct class *cls,
const struct class_member *trailer,
const uint16_t bit_hole_size);
#define class__for_each_member_from(cls, from, pos) \
pos = list_prepare_entry(from, class__tags(cls), tag.node); \
list_for_each_entry_from(pos, class__tags(cls), tag.node) \
if (!tag__is_class_member(&pos->tag)) \
continue; \
else
#define class__for_each_member_safe_from(cls, from, pos, tmp) \
pos = list_prepare_entry(from, class__tags(cls), tag.node); \
list_for_each_entry_safe_from(pos, tmp, class__tags(cls), tag.node) \
if (!tag__is_class_member(&pos->tag)) \
continue; \
else
#define class__for_each_member_continue(cls, from, pos) \
pos = list_prepare_entry(from, class__tags(cls), tag.node); \
list_for_each_entry_continue(pos, class__tags(cls), tag.node) \
if (!tag__is_class_member(&pos->tag)) \
continue; \
else
#define class__for_each_member_reverse(cls, member) \
list_for_each_entry_reverse(member, class__tags(cls), tag.node) \
if (member->tag.tag != DW_TAG_member) \
continue; \
else
enum base_type_float_type {
BT_FP_SINGLE = 1,
BT_FP_DOUBLE,
BT_FP_CMPLX,
BT_FP_CMPLX_DBL,
BT_FP_CMPLX_LDBL,
BT_FP_LDBL,
BT_FP_INTVL,
BT_FP_INTVL_DBL,
BT_FP_INTVL_LDBL,
BT_FP_IMGRY,
BT_FP_IMGRY_DBL,
BT_FP_IMGRY_LDBL
};
struct base_type {
struct tag tag;
const char *name;
uint16_t bit_size;
uint8_t name_has_encoding:1;
uint8_t is_signed:1;
uint8_t is_bool:1;
uint8_t is_varargs:1;
uint8_t float_type:4;
};
static inline struct base_type *tag__base_type(const struct tag *tag)
{
return (struct base_type *)tag;
}
static inline uint16_t base_type__size(const struct tag *tag)
{
return tag__base_type(tag)->bit_size / 8;
}
const char *__base_type__name(const struct base_type *bt);
const char *base_type__name(const struct base_type *btype, char *bf, size_t len);
size_t base_type__name_to_size(struct base_type *btype, struct cu *cu);
struct array_type {
struct tag tag;
uint32_t *nr_entries;
uint8_t dimensions;
bool is_vector;
};
static inline struct array_type *tag__array_type(const struct tag *tag)
{
return (struct array_type *)tag;
}
struct string_type {
struct tag tag;
uint32_t nr_entries;
};
static inline struct string_type *tag__string_type(const struct tag *tag)
{
return (struct string_type *)tag;
}
struct enumerator {
struct tag tag;
const char *name;
uint32_t value;
struct tag_cu type_enum; // To cache the type_enum searches
};
static inline const char *enumerator__name(const struct enumerator *enumerator)
{
return enumerator->name;
}
void enumeration__delete(struct type *type);
void enumeration__add(struct type *type, struct enumerator *enumerator);
size_t enumeration__fprintf(const struct tag *tag_enum,
const struct conf_fprintf *conf, FILE *fp);
int dwarves__init(uint16_t user_cacheline_size);
void dwarves__exit(void);
const char *dwarf_tag_name(const uint32_t tag);
struct argp_state;
void dwarves_print_version(FILE *fp, struct argp_state *state);
void dwarves_print_numeric_version(FILE *fp);
extern bool print_numeric_version;;
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
extern bool no_bitfield_type_recode;
extern const char tabs[];
#endif /* _DWARVES_H_ */