pahole: Pretty print bitfields
So for such a bitfieldy struct: $ pahole perf_event_attr | grep : __u64 disabled:1; /* 40: 0 8 */ __u64 inherit:1; /* 40: 1 8 */ __u64 pinned:1; /* 40: 2 8 */ __u64 exclusive:1; /* 40: 3 8 */ __u64 exclude_user:1; /* 40: 4 8 */ __u64 exclude_kernel:1; /* 40: 5 8 */ __u64 exclude_hv:1; /* 40: 6 8 */ __u64 exclude_idle:1; /* 40: 7 8 */ __u64 mmap:1; /* 40: 8 8 */ __u64 comm:1; /* 40: 9 8 */ __u64 freq:1; /* 40:10 8 */ __u64 inherit_stat:1; /* 40:11 8 */ __u64 enable_on_exec:1; /* 40:12 8 */ __u64 task:1; /* 40:13 8 */ __u64 watermark:1; /* 40:14 8 */ __u64 precise_ip:2; /* 40:15 8 */ __u64 mmap_data:1; /* 40:17 8 */ __u64 sample_id_all:1; /* 40:18 8 */ __u64 exclude_host:1; /* 40:19 8 */ __u64 exclude_guest:1; /* 40:20 8 */ __u64 exclude_callchain_kernel:1; /* 40:21 8 */ __u64 exclude_callchain_user:1; /* 40:22 8 */ __u64 mmap2:1; /* 40:23 8 */ __u64 comm_exec:1; /* 40:24 8 */ __u64 use_clockid:1; /* 40:25 8 */ __u64 context_switch:1; /* 40:26 8 */ __u64 write_backward:1; /* 40:27 8 */ __u64 namespaces:1; /* 40:28 8 */ __u64 ksymbol:1; /* 40:29 8 */ __u64 bpf_event:1; /* 40:30 8 */ __u64 aux_output:1; /* 40:31 8 */ __u64 cgroup:1; /* 40:32 8 */ __u64 __reserved_1:31; /* 40:33 8 */ /* size: 120, cachelines: 2, members: 53 */ /* last cacheline: 56 bytes */ $ Using a domain specific tool to show which of those bitfield entries have non-zero value for a given perf.data file (the default input file for perf): $ perf evlist -v cycles:u: size: 120, { sample_period, sample_freq }: 4000, sample_type: IP|TID|TIME|PERIOD, read_format: ID, disabled: 1, inherit: 1, exclude_kernel: 1, mmap: 1, comm: 1, freq: 1, enable_on_exec: 1, task: 1, precise_ip: 3, sample_id_all: 1, exclude_guest: 1, mmap2: 1, comm_exec: 1, ksymbol: 1, bpf_event: 1 $ We can see that we now manage to decode them, at least on x86_64 using a x86_64 perf.data file: $ pahole --seek_bytes=0xa8 -C 'perf_event_attr(sizeof=size,type=type,type_enum=perf_type_id)' --count 1 < perf.data | grep -v ' = 0,' { .type = PERF_TYPE_HARDWARE, .size = 0x78, .sample_period = 0xfa0, .sample_freq = 0xfa0, .sample_type = 0x107, .read_format = 0x4, .disabled = 0x1, .inherit = 0x1, .exclude_kernel = 0x1, .mmap = 0x1, .comm = 0x1, .freq = 0x1, .enable_on_exec = 0x1, .task = 0x1, .precise_ip = 0x3, .sample_id_all = 0x1, .exclude_guest = 0x1, .mmap2 = 0x1, .comm_exec = 0x1, .ksymbol = 0x1, .bpf_event = 0x1, }, $ And this reminds me that defaulting to eliding fields with a zero value is valuable... Also, this was in a rush, probably processing files from a different arch will produce bad results as bitfields are tricky, so probably we'll need more features to state how bitfields should be processed, etc. The plan is to have a way to create variables on the command line, where we'll read a header, give it a name, keep its contents accessible, then in subsequent entries in the command line, refer to them and, say, set the endianness from fields in the header, refer to offsets in header members to state what type to use to pretty print a range of the provided file or stdin, etc. A rabbit hole... Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
451d66ec02
commit
3c4ee1d91f
25
pahole.c
25
pahole.c
|
@ -1274,6 +1274,29 @@ static int base_type__fprintf_value(void *instance, int _sizeof, FILE *fp)
|
|||
return fprintf(fp, "%#" PRIx64, value);
|
||||
}
|
||||
|
||||
static uint64_t class_member__bitfield_value(struct class_member *member, void *instance)
|
||||
{
|
||||
int byte_size = member->byte_size;
|
||||
uint64_t value = base_type__value(instance, byte_size);
|
||||
uint64_t mask = 0;
|
||||
int bits = member->bitfield_size;
|
||||
|
||||
while (bits) {
|
||||
mask |= 1;
|
||||
if (--bits)
|
||||
mask <<= 1;
|
||||
}
|
||||
|
||||
mask <<= member->bitfield_offset;
|
||||
|
||||
return (value & mask) >> member->bitfield_offset;
|
||||
}
|
||||
|
||||
static int class_member__fprintf_bitfield_value(struct class_member *member, void *instance, FILE *fp)
|
||||
{
|
||||
return fprintf(fp, "%#" PRIx64, class_member__bitfield_value(member, instance));
|
||||
}
|
||||
|
||||
static const char *enumeration__lookup_value(struct type *enumeration, struct cu *cu, uint64_t value)
|
||||
{
|
||||
struct enumerator *entry;
|
||||
|
@ -1370,6 +1393,8 @@ static int __class__fprintf_value(struct tag *tag, struct cu *cu, void *instance
|
|||
|
||||
if (member == type->type_member && type->type_enum) {
|
||||
printed += base_type__fprintf_enum_value(member_contents, member->byte_size, type->type_enum, cu, fp);
|
||||
} else if (member->bitfield_size) {
|
||||
printed += class_member__fprintf_bitfield_value(member, member_contents, fp);
|
||||
} else if (tag__is_base_type(member_type, cu)) {
|
||||
printed += base_type__fprintf_value(member_contents, member->byte_size, fp);
|
||||
} else if (tag__is_array(member_type, cu)) {
|
||||
|
|
Loading…
Reference in New Issue