Commit Graph

38 Commits

Author SHA1 Message Date
Ilya Leoshkevich ffe0ef4d73 btf: Add --btf_gen_all flag
By default, pahole makes use only of BTF features introduced with kernel
v5.2. Features that are added later need to be turned on with explicit
feature flags, such as --btf_gen_floats. According to [1], this will
hinder the people who generate BTF for kernels externally (e.g. for old
kernels to support BPF CO-RE).

Introduce --btf_gen_all that allows using all BTF features supported
by pahole.

[1] https://lore.kernel.org/dwarves/CAEf4Bzbyugfb2RkBkRuxNGKwSk40Tbq4zAvhQT8W=fVMYWuaxA@mail.gmail.com/

Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
Suggested-by: Andrii Nakryiko <andrii@kernel.org>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Heiko Carstens <hca@linux.ibm.com>
Cc: Vasily Gorbik <gor@linux.ibm.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>
2021-03-12 10:36:45 -03:00
Ilya Leoshkevich de708b3311 btf: Add support for the floating-point types
Some BPF programs compiled on s390 fail to load, because s390
arch-specific linux headers contain float and double types.

Fix as follows:

- Make the DWARF loader fill base_type.float_type.

- Introduce the --btf_gen_floats command-line parameter, so that
  pahole could be used to build both the older and the newer kernels.

- libbpf introduced the support for the floating-point types in commit
  986962fade5, so update the libbpf submodule to that version and use
  the new btf__add_float() function in order to emit the floating-point
  types when not in the compatibility mode.

- Make the BTF loader recognize the new BTF kind.

Example of the resulting entry in the vmlinux BTF:

    [7164] FLOAT 'double' size=8

when building with:

    LLVM_OBJCOPY=${OBJCOPY} ${PAHOLE} -J ${1} --btf_gen_floats

Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
Acked-by: Andrii Nakryiko <andrii@kernel.org>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Heiko Carstens <hca@linux.ibm.com>
Cc: Vasily Gorbik <gor@linux.ibm.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>
2021-03-11 14:45:38 -03:00
Arnaldo Carvalho de Melo 4a1479305b pahole: Add heuristic to auto-add --btf_base for /sys/kernel/btf/ prefixed files
Before:

  $ pahole /sys/kernel/btf/wmi -C wmi_block
  libbpf: Invalid BTF string section
  pahole: /sys/kernel/btf/wmi: No such device
  $

After:

  $ pahole /sys/kernel/btf/wmi -C wmi_block
  struct wmi_block {
  	struct wmi_device          dev;                  /*     0   760 */

  	/* XXX last struct has 7 bytes of padding */

  	/* --- cacheline 11 boundary (704 bytes) was 56 bytes ago --- */
  	struct list_head           list;                 /*   760    16 */
  	/* --- cacheline 12 boundary (768 bytes) was 8 bytes ago --- */
  	struct guid_block          gblock;               /*   776    20 */

  	/* XXX 4 bytes hole, try to pack */

  	struct miscdevice          char_dev;             /*   800    80 */

  	/* XXX last struct has 6 bytes of padding */

  	/* --- cacheline 13 boundary (832 bytes) was 48 bytes ago --- */
  	struct mutex               char_mutex;           /*   880    32 */
  	/* --- cacheline 14 boundary (896 bytes) was 16 bytes ago --- */
  	struct acpi_device *       acpi_device;          /*   912     8 */
  	wmi_notify_handler         handler;              /*   920     8 */
  	void *                     handler_data;         /*   928     8 */
  	u64                        req_buf_size;         /*   936     8 */
  	bool                       read_takes_no_args;   /*   944     1 */

  	/* size: 952, cachelines: 15, members: 10 */
  	/* sum members: 941, holes: 1, sum holes: 4 */
  	/* padding: 7 */
  	/* paddings: 2, sum paddings: 13 */
  	/* last cacheline: 56 bytes */
  };
  $

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-11-18 11:10:23 -03:00
Arnaldo Carvalho de Melo 7293c7fcea pahole: The --btf_base option receives a PATH, not a SIZE
Fixup copy'n'paste error.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-11-18 09:21:31 -03:00
Arnaldo Carvalho de Melo aa8fb8c091 man-pages: Add entry for -J/--btf_encode to pahole's man page
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-11-13 08:36:32 -03:00
Andrii Nakryiko ace05ba941 btf: Add support for split BTF loading and encoding
Add support for generating split BTF, in which there is a designated base
BTF, containing a base set of types, and a split BTF, which extends main BTF
with extra types, that can reference types and strings from the main BTF.

This is going to be used to generate compact BTFs for kernel modules, with
vmlinux BTF being a main BTF, which all kernel modules are based off of.

These changes rely on patch set [0] to be present in libbpf submodule.

  [0] https://patchwork.kernel.org/project/netdevbpf/list/?series=377859&state=*

Committer notes:

Fixed up wrt ARGP_numeric_version and added a man page entry.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Cc: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
Cc: kernel-team@fb.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-11-11 09:12:44 -03:00
Arnaldo Carvalho de Melo bc1afd4585 pahole: Introduce --numeric_version for use in scripts and Makefiles
In Makefiles we want to do purely numeric comparisions, such as in the
Linux kernel Makefiles and scripts, that have things like this at the
moment:

  $ grep PAHOLE */*.sh
  scripts/link-vmlinux.sh:	if ! [ -x "$(command -v ${PAHOLE})" ]; then
  scripts/link-vmlinux.sh:		echo >&2 "BTF: ${1}: pahole (${PAHOLE}) is not available"
  scripts/link-vmlinux.sh:	pahole_ver=$(${PAHOLE} --version | sed -E 's/v([0-9]+)\.([0-9]+)/\1\2/')
  scripts/link-vmlinux.sh:		echo >&2 "BTF: ${1}: pahole version $(${PAHOLE} --version) is too old, need at least v1.16"
  scripts/link-vmlinux.sh:	LLVM_OBJCOPY=${OBJCOPY} ${PAHOLE} -J ${1}
  $

So just provide:

  $ pahole --numeric_version
  118
  $

While keeping the --version output for older Makefiles and scripts.

Cc: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-11-10 13:04:22 -03:00
Arnaldo Carvalho de Melo cc3f9dce33 pahole: Implement --packed
To show just packed structs.

For instance, here are the top packed structures in the Linux kernel,
using BTF data:

  $ pahole --packed --sizes | sort -k2 -nr | head
  e820_table		64004	0
  boot_params		 4096	0
  btrfs_super_block	 3531	0
  efi_variable		 2084	0
  ntb_info_regs		  800	0
  tboot			  568	0
  _legacy_mbr		  512	0
  disklabel		  512	0
  btrfs_root_item	  439	0
  saved_context		  317	0
  $

If you then look at:

  $ pahole e820_table
  struct e820_table {
  	__u32                      nr_entries;           /*     0     4 */
  	struct e820_entry          entries[3200];        /*     4 64000 */

  	/* size: 64004, cachelines: 1001, members: 2 */
  	/* last cacheline: 4 bytes */
  } __attribute__((__packed__));
  $

In arch/x86/include/asm/e820/types.h we have:

  /*
   * The whole array of E820 entries:
   */
  struct e820_table {
          __u32 nr_entries;
          struct e820_entry entries[E820_MAX_ENTRIES];
  };

I.e. no explicit __packed__ attributes, but if we expand this a bit:

  $ pahole -E e820_table
  struct e820_table {
  	/* typedef __u32 */ unsigned int               nr_entries;                       /*     0     4 */
  	struct e820_entry {
  		/* typedef u64 -> __u64 */ long long unsigned int addr;                  /*     4     8 */
  		/* typedef u64 -> __u64 */ long long unsigned int size;                  /*    12     8 */
  		enum e820_type     type;                                                 /*    20     4 */
  	} __attribute__((__packed__)) entries[3200]; /*     4 64000 */

  	/* size: 64004, cachelines: 1001, members: 2 */
  	/* last cacheline: 4 bytes */
  } __attribute__((__packed__));
  $

We see that is that entries member that is packed, because:

  $ pahole e820_entry
  struct e820_entry {
  	u64                        addr;                 /*     0     8 */
  	u64                        size;                 /*     8     8 */
  	enum e820_type             type;                 /*    16     4 */

  	/* size: 20, cachelines: 1, members: 3 */
  	/* last cacheline: 20 bytes */
  } __attribute__((__packed__));
  $

In arch/x86/include/asm/e820/types.h we have:

  /*
   * A single E820 map entry, describing a memory range of [addr...addr+size-1],
   * of 'type' memory type:
   *
   * (We pack it because there can be thousands of them on large systems.)
   */
  struct e820_entry {
          u64                     addr;
          u64                     size;
          enum e820_type          type;
  } __attribute__((packed));

So yeah, it is there, BTF doesn't explicitly states it is packed (as
DWARF does) and pahole was able to infer that correctly.

Tested-by: Richard Weinberger <richard@nod.at>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-10-08 10:11:31 -03:00
Arnaldo Carvalho de Melo 08f49262f4 man-pages: Fix 'coimbine' typo
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-10-08 09:10:34 -03:00
Hao Luo 1abc001417 btf_encoder: Introduce option '--btf_encode_force'
Commit f3d9054ba8 ("btf_encoder: Teach pahole to store percpu
variables in vmlinux BTF.") introduced an option '-j' that makes
effort in emitting VAR entries in BTF. Before no one has been using
this flag, replace the one-letter option '-j' with a full flag name
'--btf_encode_force' to save '-j' for future uses.

Committer notes:

Added missing man page entry.

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: Yonghong Song <yhs@fb.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-09-21 17:02:57 -03:00
Hao Luo da4ad2f650 btf_encoder: Allow disabling BTF var encoding.
A new feature was introduced in commit f3d9054ba8 ("btf_encoder: Teach
pahole to store percpu variables in vmlinux BTF.") which encodes kernel
percpu variables into BTF. Add a flag --skip_encoding_btf_vars to allow
users to toggle this feature off, so that the rollout of pahole v1.18
can be protected by potential bugs in this feature.

Committer notes:

Added missing man page entry.

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: Yonghong Song <yhs@fb.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-09-21 17:00:16 -03:00
Arnaldo Carvalho de Melo 22f93766cf pahole: Support multiple types for pretty printing
For now one has to specify them in the order they appear in the file,
i.e. for perf.data files where we have:

  $ pahole --hex ~/bin/perf --header=perf_file_header < perf.data
  {
  	.magic = 0x32454c4946524550,
  	.size = 0x68,
  	.attr_size = 0x88,
  	.attrs = {
  		.offset = 0x168,
  		.size = 0x220,
  	},
  	.data = {
  		.offset = 0x388,
  		.size = 0x306698,
  	},
  	.event_types = {
  		.offset = 0,
  		.size = 0,
  	},
  	.adds_features = { 0x16717ffc, 0, 0, 0 },
  },
  $

We need to ask for pretty printing the attrs then the data sections, as:

  $ pahole ~/bin/perf --header=perf_file_header \
     -C 'perf_file_attr(range=attrs),perf_event_header(range=data,sizeof,type,type_enum=perf_event_type+perf_user_event_type)' < perf.data

Notice that both types have the range= setting where in the header it
should find the instances of its respective types, the result for this
perf.data file:

  $ perf evlist
  instructions
  cycles
  cache-misses
  dummy:HG
  $

Those events have these attributes, which we'll match in the pahole
output for the header 'attrs' range:

  $ perf evlist -v
  instructions: size: 120, config: 0x1, { sample_period, sample_freq }: 4000, sample_type: IP|TID|TIME|ID|CPU|PERIOD, read_format: ID, disabled: 1, inherit: 1, freq: 1, sample_id_all: 1, exclude_guest: 1
  cycles: size: 120, { sample_period, sample_freq }: 4000, sample_type: IP|TID|TIME|ID|CPU|PERIOD, read_format: ID, disabled: 1, inherit: 1, freq: 1, sample_id_all: 1, exclude_guest: 1
  cache-misses: size: 120, config: 0x3, { sample_period, sample_freq }: 4000, sample_type: IP|TID|TIME|ID|CPU|PERIOD, read_format: ID, disabled: 1, inherit: 1, freq: 1, sample_id_all: 1, exclude_guest: 1
  dummy:HG: type: 1, size: 120, config: 0x9, { sample_period, sample_freq }: 4000, sample_type: IP|TID|TIME|ID|CPU|PERIOD, read_format: ID, inherit: 1, mmap: 1, comm: 1, freq: 1, task: 1, sample_id_all: 1, mmap2: 1, comm_exec: 1, ksymbol: 1, bpf_event: 1
  $

To make it more compact lets remove zeroed fields using grep:

  $ pahole ~/bin/perf --header=perf_file_header -C 'perf_file_attr(range=attrs),perf_event_header(range=data,sizeof,type,type_enum=perf_event_type+perf_user_event_type)' < perf.data | grep -v '= 0,'
  {
  	.attr = {
  		.size = 120,
  		.config = 1,
  		.sample_period = 4000,
  		.sample_freq = 4000,
  		.sample_type = 455,
  		.read_format = 4,
  		.disabled = 1,
  		.inherit = 1,
  		.freq = 1,
  		.sample_id_all = 1,
  		.exclude_guest = 1,
  	},
  	.ids = {
  		.offset = 104,
  		.size = 64,
  	},
  },
  {
  	.attr = {
  		.size = 120,
  		.sample_period = 4000,
  		.sample_freq = 4000,
  		.sample_type = 455,
  		.read_format = 4,
  		.disabled = 1,
  		.inherit = 1,
  		.freq = 1,
  		.sample_id_all = 1,
  		.exclude_guest = 1,
  	},
  	.ids = {
  		.offset = 168,
  		.size = 64,
  	},
  },
  {
  	.attr = {
  		.size = 120,
  		.config = 3,
  		.sample_period = 4000,
  		.sample_freq = 4000,
  		.sample_type = 455,
  		.read_format = 4,
  		.disabled = 1,
  		.inherit = 1,
  		.freq = 1,
  		.sample_id_all = 1,
  		.exclude_guest = 1,
  	},
  	.ids = {
  		.offset = 232,
  		.size = 64,
  	},
  },
  {
  	.attr = {
  		.type = 1,
  		.size = 120,
  		.config = 9,
  		.sample_period = 4000,
  		.sample_freq = 4000,
  		.sample_type = 455,
  		.read_format = 4,
  		.inherit = 1,
  		.mmap = 1,
  		.comm = 1,
  		.freq = 1,
  		.task = 1,
  		.sample_id_all = 1,
  		.mmap2 = 1,
  		.comm_exec = 1,
  		.ksymbol = 1,
  		.bpf_event = 1,
  	},
  	.ids = {
  		.offset = 296,
  		.size = 64,
  	},
  },
  {
  	.header = {
  		.type = PERF_RECORD_TIME_CONV,
  		.size = 32,
  	},
  	.time_shift = 31,
  	.time_mult = 1016798081,
  	.time_zero = 670877213069232,
  },
  {
  	.header = {
  		.type = PERF_RECORD_MMAP,
  		.misc = 1,
  		.size = 96,
  	},
  	.pid = -1,
  	.start = -1929379840,
  	.len = 14683553,
  	.pgoff = -1929379840,
  	.filename = "[kernel.kallsyms]_text",
  },
  {
  	.header = {
  		.type = PERF_RECORD_MMAP,
  		.misc = 1,
  		.size = 136,
  	},
  	.pid = -1,
  	.start = -1072852992,
  	.len = 139264,
  	.filename = "/lib/modules/5.7.8-200.fc32.x86_64/kernel/fs/fuse/fuse.ko.xz",
  },
<SNIP>
  {
  	.header = {
  		.type = PERF_RECORD_SAMPLE,
  		.misc = 1,
  		.size = 56,
  	},
  	.array = { -1927972873, 14267881360602, 671090228720656, 8685165, 7, 93802 },
  },
  {
  	.header = {
  		.type = PERF_RECORD_SAMPLE,
  		.misc = 1,
  		.size = 56,
  	},
  	.array = { -1928098583, 0, 671090229714951, 8685165, 7, 79438 },
  },
  {
  	.type = PERF_RECORD_FINISHED_ROUND,
  	.size = 8,
  },
  $

Validation is done all around:

  $ pahole ~/bin/perf --header=paerf_file_header -C 'perf_file_attr(range=attrs),perf_event_header(range=data,sizeof,type,type_enum=perf_event_type+perf_user_event_type)' < perf.data | grep -v '= 0,'
  pahole: --header_type=paerf_file_header not found
  $

  $ pahole ~/bin/perf --header=perf_file_header -C 'perf_file_atatr(range=attrs),perf_event_header(range=data,sizeof,type,type_enum=perf_event_type+perf_user_event_type)' < perf.data | grep -v '= 0,'
  pahole: type 'perf_file_atatr' not found
  $

  $ pahole ~/bin/perf --header=perf_file_header -C 'perf_file_attr(range=atrs),perf_event_header(range=data,sizeof,type,type_enum=perf_event_type+perf_user_event_type)' < perf.data | grep -v '= 0,'
  pahole: couldn't read the 'atrs.offset' member of 'perf_file_header' for evaluating range=atrs
  $
  $ pahole ~/bin/perf --header=perf_file_header -C 'perf_file_attr(range=attrs),perf_event_hader(range=data,sizeof,type,type_enum=perf_event_type+perf_user_event_type)' < perf.data | grep -v '= 0,'
  pahole: type 'perf_event_hader' not found
  $
  $ pahole ~/bin/perf --header=perf_file_header -C 'perf_file_attr(range=attrs),perf_event_header(range=daata,sizeof,type,type_enum=perf_event_type+perf_user_event_type)' < perf.data | grep -v '= 0,' > /dev/null
  pahole: couldn't read the 'daata.offset' member of 'perf_file_header' for evaluating range=daata
  $
  $ pahole ~/bin/perf --header=perf_file_header -C 'perf_file_attr(range=attrs),perf_event_header(range=data,sizeof=fads,type,type_enum=perf_event_type+perf_user_event_type)' < perf.data | grep -v '= 0,' > /dev/null
  pahole: the sizeof member 'fads' wasn't found in the 'perf_event_header' type
  pahole: type 'perf_event_header' not found or attributes not validated
  $

The algorithm to find the types was improved to not fallback at the end,
but instead go on saving types that were found, which increases the
possibility of resolving all of them, at the end we just need to check
if all that is needed was found, printing relevant messages when this
isn't the case.

More to do, like pretty printing flags such as sample_type, etc.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-08-05 17:58:09 -03:00
Arnaldo Carvalho de Melo fdfc64ec44 pahole: Introduce --range
For a data structure like:

  $ pahole --hex ~/bin/perf --header perf_file_header < 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 },
  },
  $

These are now equivalent:

  $ pahole ~/bin/perf --header=perf_file_header --seek_bytes '$header.data.offset' --size_bytes='$header.data.size' -C 'perf_event_header(sizeof,type,type_enum=perf_event_type+perf_user_event_type)' --count 1 --hex < perf.data
  {
  	.header = {
  		.type = PERF_RECORD_TIME_CONV,
  		.misc = 0,
  		.size = 0x20,
  	},
  	.time_shift = 0x1f,
  	.time_mult = 0x3c9b3031,
  	.time_zero = 0x18c520cf8532e,
  },
  $ pahole ~/bin/perf --header=perf_file_header --range=data -C 'perf_event_header(sizeof,type,type_enum=perf_event_type+perf_user_event_type)' --count 1 --hex < perf.data
  {
  	.header = {
  		.type = PERF_RECORD_TIME_CONV,
  		.misc = 0,
  		.size = 0x20,
  	},
  	.time_shift = 0x1f,
  	.time_mult = 0x3c9b3031,
  	.time_zero = 0x18c520cf8532e,
  },
  $

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-08-05 15:16:19 -03:00
Arnaldo Carvalho de Melo f63d3677e3 pahole: Support multiple enums in type_enum=
See the pahole man page:

Some of the records are not found in 'type_enum=perf_event_type' so some of the
records don't get converted to a type that fully shows its contents. For perf
we know that those are in another enumeration, 'enum perf_user_event_type', so,
for these  cases,  we can create a 'virtual enum', i.e. the sum of two enums
and then get all those entries decoded and properly casted, first few records
with just 'enum perf_event_type':

  $ pahole ~/bin/perf --header=perf_file_header --seek_bytes '$header.data.offset' --size_bytes='$header.data.size' -C 'perf_event_header(sizeof,type,type_enum=perf_event_type)' --count 4 < perf.data
  {
       .type = 79,
       .misc = 0,
       .size = 32,
  },
  {
       .type = 73,
       .misc = 0,
       .size = 40,
  },
  {
       .type = 74,
       .misc = 0,
       .size = 32,
  },
  {
       .header = {
            .type = PERF_RECORD_CGROUP,
            .misc = 0,
            .size = 40,
       },
       .id = 1,
       .path = "/",
  },
  $

Now with both enumerations, i.e. with 'type_enum=perf_event_type+perf_user_event_type':

  $ pahole ~/bin/perf --header=perf_file_header --seek_bytes '$header.data.offset' --size_bytes='$header.data.size' -C 'perf_event_header(sizeof,type,type_enum=perf_event_type+perf_user_event_type)' --count 5 < perf.data
  {
       .header = {
            .type = PERF_RECORD_TIME_CONV,
            .misc = 0,
            .size = 32,
       },
       .time_shift = 31,
       .time_mult = 1016803377,
       .time_zero = 435759009518382,
  },
  {
       .header = {
            .type = PERF_RECORD_THREAD_MAP,
            .misc = 0,
            .size = 40,
       },
       .nr = 1,
       .entries = 0x50 0x7e 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00,
  },
  {
       .header = {
            .type = PERF_RECORD_CPU_MAP,
            .misc = 0,
            .size = 32,
       },
       .data = {
            .type = 1,
            .data = "",
       },
  },
  {
       .header = {
            .type = PERF_RECORD_CGROUP,
            .misc = 0,
            .size = 40,
       },
       .id = 1,
       .path = "/",
  },
  {
       .header = {
            .type = PERF_RECORD_CGROUP,
            .misc = 0,
            .size = 48,
       },
       .id = 1553,
       .path = "/system.slice",
  },
  $

And since the fun never ends, this needs to be properly supported (arrays of
structs):

  $ pahole ~/bin/perf -C perf_record_thread_map_entry
  struct perf_record_thread_map_entry {
  	__u64                      pid;                  /*     0     8 */
  	char                       comm[16];             /*     8    16 */

  	/* size: 24, cachelines: 1, members: 2 */
  	/* last cacheline: 24 bytes */
  };
  $

that 'nr' field:

  $ pahole ~/bin/perf -C perf_record_thread_map
  struct perf_record_thread_map {
  	struct perf_event_header   header;               /*     0     8 */
  	__u64                      nr;                   /*     8     8 */
  	struct perf_record_thread_map_entry entries[];   /*    16     0 */

  	/* size: 16, cachelines: 1, members: 3 */
  	/* last cacheline: 16 bytes */
  };
  $

So probably we need something like a file with types and its pretty printing
details, with one for 'struct perf_record_thread_map':

perf_record_thread_map(entries.nr_entries=$nr)

Meaning: the perf_record_thread_map 'entries' has a number of
sizeof(typeof entries) that is defined in the perf_record_thread_map
'nr' member.  Everything starting with a '$' needs to be evaluated, like
the '$header.*' we already have, since there is no 'namespace selector'
($header. in the header case) this means: the current record.

So, when pretty printing a record that has such type (perf_record_thread_map)
this has to be taken into account, and validated by the containing 'struct
perf_event_header->size' field.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-08-05 15:16:19 -03:00
Arnaldo Carvalho de Melo aa7ab3e875 pahole: Allow for more compact enum filters by suppressing common prefix
I.e. these are all equivalent:

	filter=type==PERF_RECORD_MMAP
	type==PERF_RECORD_MMAP
	filter=type==MMAP
	type==MMAP

Update docs about it.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-08-05 15:16:19 -03:00
Arnaldo Carvalho de Melo d28bc97b5c man-pages: Document pretty printing capabilities and provide examples
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-08-05 15:16:19 -03:00
Arnaldo Carvalho de Melo fe28422144 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 09:25:57 -03:00
Arnaldo Carvalho de Melo 44af7c02b5 pahole: Implement --skip, just like dd
$ 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 3 -C modversion_info drivers/scsi/sg.ko < versions
  {
  	.crc = 0x8dabd84,
  	.name = "module_layout",
  },
  {
  	.crc = 0x45e4617b,
  	.name = "no_llseek",
  },
  {
  	.crc = 0xa23fae8c,
  	.name = "param_ops_int",
  },
  $ pahole --skip 1 --count 2 -C modversion_info drivers/scsi/sg.ko < versions
  {
  	.crc = 0x45e4617b,
  	.name = "no_llseek",
  },
  {
  	.crc = 0xa23fae8c,
  	.name = "param_ops_int",
  },
  $

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-07-01 08:36:28 -03:00
Arnaldo Carvalho de Melo 5631fdcea1 pahole: Introduce --count, just like dd's
$ objcopy -O binary --only-section=.altinstructions ~/git/build/v5.7-rc2+/vmlinux .altinstructions
  $ pahole --count 2 alt_instr  < .altinstructions
  {
  	.instr_offset = 0xffffffffffe0e690,
  	.repl_offset = 0x4873,
  	.cpuid = 0x70,
  	.instrlen = 0x5,
  	.replacementlen = 0x5,
  	.padlen = 0,
  },
  {
  	.instr_offset = 0xffffffffffe0e683,
  	.repl_offset = 0x486b,
  	.cpuid = 0x129,
  	.instrlen = 0x5,
  	.replacementlen = 0x5,
  	.padlen = 0,
  },
  $

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-07-01 08:18:42 -03:00
Arnaldo Carvalho de Melo 272bc75024 man-pages: Add information about stdin raw data pretty printing
And an example.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-06-27 09:40:51 -03:00
Arnaldo Carvalho de Melo 277c2b3d1b man-pages: Add section about --hex + -E to locate offsets deep into sub structs
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-01-16 12:10:54 -03:00
Arnaldo Carvalho de Melo 812c980b3f man-pages: Update some info, expand BTF info, add some EXAMPLES
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-01-16 11:36:20 -03:00
Arnaldo Carvalho de Melo 88d99562e5 pahole: Add --structs to ask just for structs, counterpart of --unions
The default is to show structs and unions, if just structs should be
considered, use --structs, just don't use it together with --unions or
nothing will be shown 8-)

  $ pahole --find_pointers_to ehci_qh
  ehci_hcd: qh_scan_next
  ehci_hcd: async
  ehci_hcd: dummy
  ehci_shadow: qh
  $ pahole --structs --find_pointers_to ehci_qh
  ehci_hcd: qh_scan_next
  ehci_hcd: async
  ehci_hcd: dummy
  $ pahole --unions --find_pointers_to ehci_qh
  ehci_shadow: qh
  $ pahole --structs --unions --find_pointers_to ehci_qh
  $

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-01-15 12:41:28 -03:00
Arnaldo Carvalho de Melo 3661f17d0b pahole: Introduce --unions to consider just unions
Most filters can be used together with it, for instance to see the
biggest unions in the kernel:

  $ pahole --unions --sizes | sort -k2 -nr | head
  thread_union            16384 0
  swap_header              4096 0
  fpregs_state             4096 0
  autofs_v5_packet_union    304 0
  autofs_packet_union       272 0
  pptp_ctrl_union           208 0
  acpi_parse_object         200 0
  acpi_descriptor           200 0
  bpf_attr                  120 0
  phy_configure_opts        112 0
  $

Or just some unions that have some specific prefix:

  $ pahole --unions --prefix tcp
  union tcp_md5_addr {
  	struct in_addr             a4;                 /*     0     4 */
  	struct in6_addr            a6;                 /*     0    16 */
  };
  union tcp_word_hdr {
  	struct tcphdr              hdr;                /*     0    20 */
  	__be32                     words[5];           /*     0    20 */
  };
  union tcp_cc_info {
  	struct tcpvegas_info       vegas;              /*     0    16 */
  	struct tcp_dctcp_info      dctcp;              /*     0    16 */
  	struct tcp_bbr_info        bbr;                /*     0    20 */
  };
  $

What are the biggest unions in terms of number of members?

  $ pahole --unions --nr_members | sort -k2 -nr | head
  security_list_options 218
  aml_resource		 36
  acpi_resource_data	 29
  acpi_operand_object	 26
  iwreq_data		 18
  sctp_params		 15
  ib_flow_spec		 14
  ethtool_flow_union	 14
  pptp_ctrl_union	 13
  bpf_attr		 12
  $

If you want to script most of the queries can change the separator:

  $ pahole --unions --nr_members -t, | sort -t, -k2 -nr | head
  security_list_options,218
  aml_resource,36
  acpi_resource_data,29
  acpi_operand_object,26
  iwreq_data,18
  sctp_params,15
  ib_flow_spec,14
  ethtool_flow_union,14
  pptp_ctrl_union,13
  bpf_attr,12
  $

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-01-15 12:31:47 -03:00
Arnaldo Carvalho de Melo 9a4d719304 fprintf: Allow suppressing the inferred __attribute__((__packed__))
We use things like DW_AT_alignment, so not all of those attributes are
inferred by formats like BTF that lack that info, allow suppressing the
output and make btfdiff ask for both DWARF and BTF output to have this
suppressed.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-15 15:01:53 -03:00
Arnaldo Carvalho de Melo ec935ee422 fprintf: Allow suppressing the output of force paddings at the end of structs
Things like 'struct timex' in the linux kernel led to this output:

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-15 14:45:29 -03:00
Arnaldo Carvalho de Melo 6cd6a6bd87 dwarves_fprintf: Allow suppressing the __attribute__((__aligned__(N))
So that we can use it in things like btfdiff.

Cc: Alexei Starovoitov <ast@fb.com>
Cc: Andrii Nakryiko <andriin@fb.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Mark Wielaard <mark@klomp.org>
Cc: Yonghong Song <yhs@fb.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-03 18:10:16 -03:00
Arnaldo Carvalho de Melo 5f057919a0 man-pages: Add entry for --hex
Flavio needed this and found it only after some head scratching, add it.

Someone could help here by looking at other missing entries in the man
page, getting it in synch with 'pahole --help' ;-)

Reported-by: Flavio Leitner <fbl@redhat.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2017-09-05 10:13:06 -03:00
Arnaldo Carvalho de Melo 5a57eb0741 man-pages: Update URL to the dwarves paper
The ghostprotocols.net domain is busted for a while, point to the
more permanent OLS proceedings pdf hosted at kernel.org.

Reported-by: Borislav Petkov <bp@alien8.de>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2017-02-01 10:42:59 -03:00
Arnaldo Carvalho de Melo 519d1d3d96 pahole: Allow list of class names to be passed to -C/--class_name
CSV, and also supports file://class_list.txt as one of the entries
in the list, so:

[acme@doppio pahole]$ pahole -C str_node,strings build/libdwarves.so.1.0.0
struct strings {
	void *              tree;                 /*     0     8 */
	struct gobuffer     gb;                   /*     8    24 */

	/* size: 32, cachelines: 1, members: 2 */
	/* last cacheline: 32 bytes */
};
struct str_node {
	struct rb_node      rb_node;              /*     0    24 */
	const char  *       s;                    /*    24     8 */

	/* size: 32, cachelines: 1, members: 2 */
	/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$

And also:

[acme@doppio pahole]$ pahole -C file://classes.txt,tag build/libdwarves.so.1.0.0
struct strings {
	void *              tree;                 /*     0     8 */
	struct gobuffer     gb;                   /*     8    24 */

	/* size: 32, cachelines: 1, members: 2 */
	/* last cacheline: 32 bytes */
};
struct tag {
	struct list_head    node;                 /*     0    16 */
	uint16_t            type;                 /*    16     2 */
	uint16_t            tag;                  /*    18     2 */
	uint16_t            visited:1;            /*    20:15  2 */
	uint16_t            top_level:1;          /*    20:14  2 */

	/* XXX 14 bits hole, try to pack */

	uint16_t            recursivity_level;    /*    22     2 */
	void *              priv;                 /*    24     8 */

	/* size: 32, cachelines: 1, members: 7 */
	/* bit holes: 1, sum bit holes: 14 bits */
	/* last cacheline: 32 bytes */
};
struct str_node {
	struct rb_node      rb_node;              /*     0    24 */
	const char  *       s;                    /*    24     8 */

	/* size: 32, cachelines: 1, members: 2 */
	/* last cacheline: 32 bytes */
};
[acme@doppio pahole]$

Suggested-by: Zack Weinberg <zweinberg@mozilla.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-18 14:58:51 -03:00
Arnaldo Carvalho de Melo fc0827327b pahole: Remove a not needed "the" article in the man page.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-23 16:53:54 -03:00
Arnaldo Carvalho de Melo ac7778099a pahole: Introduce --fixup_silly_bitfields
$ pahole -C acpi_device_perf_flags ac.o
struct acpi_device_perf_flags {
	u8          reserved:8;           /*     0: 0  1 */

	/* size: 1, cachelines: 1, members: 1 */
	/* last cacheline: 1 bytes */
};
$ pahole --fixup_silly_bitfields -C acpi_device_perf_flags ac.o
struct acpi_device_perf_flags {
	u8          reserved;             /*     0     1 */

	/* size: 1, cachelines: 1, members: 1 */
	/* last cacheline: 1 bytes */
};
$

Used in ctfdwdiff as in CTF land we can't express such sillyness.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-20 13:54:04 -03:00
Arnaldo Carvalho de Melo 57127d45fc pahole: Introduce --flat_array
CTF doesn't have support for multiple array dimensions, so it flattens
the arrays.

This caused a large number of false positives in ctfdwdiff, so introduce
this conf_fprintf option, use it in pahole and ctfdwdiff.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-20 10:29:50 -03:00
Arnaldo Carvalho de Melo 45255ec6b6 pahole: Add --format_path/-F to specify a list of formats to try
For a file with just DWARF info:

$ pahole -F ctf build/pahole
$

But if we ask that it also try dwarf:

$ pahole -F ctf,dwarf build/pahole | head -2
struct _IO_FILE {
	int          _flags;    /*     0     4 */
$

Useful when testing the new CTF support in these tools, as we'll be able to,
from the DWARF info in objects, generate the CTF equivalent and add to the same
object, then run pahole -A -F ctf, pahole -A -F dwarf and compare the outputs.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-19 12:19:37 -03:00
Arnaldo Carvalho de Melo bcb2e11dcf man-pages: Fixup typo
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-03 15:32:47 -03:00
Arnaldo Carvalho de Melo f9d24098fc man-pages: Add URL for dwarves paper and info about where it is useful
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-02-13 11:52:58 -02:00
Arnaldo Carvalho de Melo 2a5d435053 man-pages: Add comments about CONFIG_DEBUG_INFO to pahole.1
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-02-13 11:35:24 -02:00
Arnaldo Carvalho de Melo 7b6c135e7c pahole: finally the beginnings of a man page
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-02-11 12:19:46 -02:00