Commit Graph

48 Commits

Author SHA1 Message Date
Arnaldo Carvalho de Melo 7cfc9be1f2 man-pages: Improve the --nr_methods/-m pahole man page entry
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-08-20 16:40:27 -03:00
Arnaldo Carvalho de Melo d2d83be1e2 pahole: Allow tweaking the size of the loader hash tables
To experiment with different sizes as time goes by and the number of symbols in
the kernel grows.

The current default, 15, is suboptimal for the fedora rawhide kernel, we can do
better using 12.

Default: 15:

  $ sudo ~acme/bin/perf stat -d -r5 pahole -j --btf_encode_detached vmlinux-j.btf vmlinux

   Performance counter stats for 'pahole -j --btf_encode_detached vmlinux-j.btf vmlinux' (5 runs):

            8,107.73 msec task-clock                #    2.749 CPUs utilized            ( +-  0.05% )
               1,723      context-switches          #  212.562 /sec                     ( +-  1.86% )
                   5      cpu-migrations            #    0.641 /sec                     ( +- 46.07% )
              68,802      page-faults               #    8.486 K/sec                    ( +-  0.05% )
      29,221,590,880      cycles                    #    3.604 GHz                      ( +-  0.04% )
      63,438,138,612      instructions              #    2.17  insn per cycle           ( +-  0.00% )
      15,125,172,105      branches                  #    1.866 G/sec                    ( +-  0.00% )
         119,983,284      branch-misses             #    0.79% of all branches          ( +-  0.06% )
      13,964,248,638      L1-dcache-loads           #    1.722 G/sec                    ( +-  0.00% )
         375,110,346      L1-dcache-load-misses     #    2.69% of all L1-dcache accesses( +-  0.01% )
          91,712,402      LLC-loads                 #   11.312 M/sec                    ( +-  0.14% )
          28,025,289      LLC-load-misses           #   30.56% of all LL-cache accesses ( +-  0.23% )

             2.94980 +- 0.00193 seconds time elapsed  ( +-  0.07% )

  $

New default, to be set in an upcoming patch, 12:

  $ sudo ~acme/bin/perf stat -d -r5 pahole --hashbits=12 -j --btf_encode_detached vmlinux-j.btf vmlinux

   Performance counter stats for 'pahole --hashbits=12 -j --btf_encode_detached vmlinux-j.btf vmlinux' (5 runs):

            7,687.31 msec task-clock                #    2.704 CPUs utilized            ( +-  0.02% )
               1,677      context-switches          #  218.126 /sec                     ( +-  0.70% )
                   4      cpu-migrations            #    0.468 /sec                     ( +- 18.84% )
              67,827      page-faults               #    8.823 K/sec                    ( +-  0.03% )
      27,711,744,058      cycles                    #    3.605 GHz                      ( +-  0.02% )
      63,032,539,630      instructions              #    2.27  insn per cycle           ( +-  0.00% )
      15,062,001,666      branches                  #    1.959 G/sec                    ( +-  0.00% )
         127,728,818      branch-misses             #    0.85% of all branches          ( +-  0.07% )
      13,972,184,314      L1-dcache-loads           #    1.818 G/sec                    ( +-  0.00% )
         364,962,883      L1-dcache-load-misses     #    2.61% of all L1-dcache accesses( +-  0.02% )
          83,969,109      LLC-loads                 #   10.923 M/sec                    ( +-  0.13% )
          19,141,055      LLC-load-misses           #   22.80% of all LL-cache accesses ( +-  0.25% )

            2.842440 +- 0.000952 seconds time elapsed  ( +-  0.03% )

  $ sudo ~acme/bin/perf stat -d -r5 pahole --hashbits=11 -j --btf_encode_detached vmlinux-j.btf vmlinux

   Performance counter stats for 'pahole --hashbits=11 -j --btf_encode_detached vmlinux-j.btf vmlinux' (5 runs):

            7,704.29 msec task-clock                #    2.702 CPUs utilized            ( +-  0.05% )
               1,676      context-switches          #  217.515 /sec                     ( +-  1.04% )
                   2      cpu-migrations            #    0.286 /sec                     ( +- 17.01% )
              67,813      page-faults               #    8.802 K/sec                    ( +-  0.05% )
      27,786,710,102      cycles                    #    3.607 GHz                      ( +-  0.05% )
      63,027,795,038      instructions              #    2.27  insn per cycle           ( +-  0.00% )
      15,066,316,987      branches                  #    1.956 G/sec                    ( +-  0.00% )
         130,431,772      branch-misses             #    0.87% of all branches          ( +-  0.20% )
      13,981,516,517      L1-dcache-loads           #    1.815 G/sec                    ( +-  0.00% )
         369,525,466      L1-dcache-load-misses     #    2.64% of all L1-dcache accesses( +-  0.03% )
          83,328,524      LLC-loads                 #   10.816 M/sec                    ( +-  0.27% )
          18,704,020      LLC-load-misses           #   22.45% of all LL-cache accesses ( +-  0.18% )

             2.85109 +- 0.00281 seconds time elapsed  ( +-  0.10% )

  $ sudo ~acme/bin/perf stat -d -r5 pahole --hashbits=8 -j --btf_encode_detached vmlinux-j.btf vmlinux

   Performance counter stats for 'pahole --hashbits=8 -j --btf_encode_detached vmlinux-j.btf vmlinux' (5 runs):

            8,190.55 msec task-clock                #    2.774 CPUs utilized            ( +-  0.03% )
               1,607      context-switches          #  196.226 /sec                     ( +-  0.67% )
                   3      cpu-migrations            #    0.317 /sec                     ( +- 15.38% )
              67,869      page-faults               #    8.286 K/sec                    ( +-  0.05% )
      29,511,213,192      cycles                    #    3.603 GHz                      ( +-  0.02% )
      63,347,196,598      instructions              #    2.15  insn per cycle           ( +-  0.00% )
      15,198,023,498      branches                  #    1.856 G/sec                    ( +-  0.00% )
         131,113,100      branch-misses             #    0.86% of all branches          ( +-  0.14% )
      14,118,162,884      L1-dcache-loads           #    1.724 G/sec                    ( +-  0.00% )
         422,048,384      L1-dcache-load-misses     #    2.99% of all L1-dcache accesses( +-  0.01% )
         105,878,910      LLC-loads                 #   12.927 M/sec                    ( +-  0.05% )
          21,022,664      LLC-load-misses           #   19.86% of all LL-cache accesses ( +-  0.20% )

            2.952678 +- 0.000858 seconds time elapsed  ( +-  0.03% )

  $ sudo ~acme/bin/perf stat -d -r5 pahole --hashbits=13 -j --btf_encode_detached vmlinux-j.btf vmlinux

   Performance counter stats for 'pahole --hashbits=13 -j --btf_encode_detached vmlinux-j.btf vmlinux' (5 runs):

            7,728.71 msec task-clock                #    2.707 CPUs utilized            ( +-  0.07% )
               1,661      context-switches          #  214.887 /sec                     ( +-  0.70% )
                   2      cpu-migrations            #    0.259 /sec                     ( +- 22.36% )
              67,893      page-faults               #    8.785 K/sec                    ( +-  0.04% )
      27,874,322,843      cycles                    #    3.607 GHz                      ( +-  0.07% )
      63,079,425,815      instructions              #    2.26  insn per cycle           ( +-  0.00% )
      15,067,279,408      branches                  #    1.950 G/sec                    ( +-  0.00% )
         125,706,874      branch-misses             #    0.83% of all branches          ( +-  1.00% )
      13,967,177,801      L1-dcache-loads           #    1.807 G/sec                    ( +-  0.00% )
         363,566,754      L1-dcache-load-misses     #    2.60% of all L1-dcache accesses( +-  0.02% )
          86,583,482      LLC-loads                 #   11.203 M/sec                    ( +-  0.13% )
          20,629,871      LLC-load-misses           #   23.83% of all LL-cache accesses ( +-  0.21% )

             2.85551 +- 0.00124 seconds time elapsed  ( +-  0.04% )

  $

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-08-20 16:40:27 -03:00
Arnaldo Carvalho de Melo 3e1c7a2077 pahole: Introduce --sort
To ask for sorting output, initially by name.

This is needed in 'btfdiff' to diff the output of 'pahole -F dwarf
--jobs N', where N threads will go on consuming DWARF compile units and
and pretty printing them, producing a non deterministic output.

So we need to sort the output for both BTF and DWARF, and then diff
them.

This is still not enough for some cases where different types have the
same name, things like "usb_priv" that exists in multiple DWARF compile
units, the first processed is "winning", i.e. being the only one
considered.

I have to look how BTF handles this to adopt a similar algorithm and
keep btfdiff usable as a regression test for the BTF and DWARF loader
and the BTF encoder.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-08-12 09:41:13 -03:00
Arnaldo Carvalho de Melo 33e0d5f874 pahole: Introduce --prettify option
The use of isatty(0) to switch into pretty printing is problematic as
reported by Bernd Buschinski, that ran into problems with his scripts:

========================================================================
  I am using pahole 1.21 and I recently noticed that I no longer have
  any pahole output in several scripts.

  Using (on the command line):

    $ pahole -V -E -C my_struct /path/to/my/debug.o

  works fine and gives the expected output.

  But:

    $ parallel -j 1 pahole -V -E -C my_struct ::: /path/to/my/debug.o

  gives nothing, no stderr, no stdout and ret code 0.

  After testing some versions, it works fine in 1.17 and no longer works in 1.18.
========================================================================

Since the pretty printer broke existing scripts, and its a relatively
new feature, lets switch to using a explicit command line option to
activate the pretty printer, i.e. where we used:

  $ pahole --header elf64_hdr < /bin/bash

We now use one of:

  ⬢[acme@toolbox pahole]$ pahole --header elf64_hdr --prettify=/bin/bash
  {
  	.e_ident = { 127, 69, 76, 70, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  	.e_type = 3,
  	.e_machine = 62,
  	.e_version = 1,
  	.e_entry = 204016,
  	.e_phoff = 64,
  	.e_shoff = 1388096,
  	.e_flags = 0,
  	.e_ehsize = 64,
  	.e_phentsize = 56,
  	.e_phnum = 13,
  	.e_shentsize = 64,
  	.e_shnum = 31,
  	.e_shstrndx = 30,
  },
  ⬢[acme@toolbox pahole]$ pahole --header elf64_hdr --prettify /bin/bash
  {
  	.e_ident = { 127, 69, 76, 70, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  	.e_type = 3,
  	.e_machine = 62,
  	.e_version = 1,
  	.e_entry = 204016,
  	.e_phoff = 64,
  	.e_shoff = 1388096,
  	.e_flags = 0,
  	.e_ehsize = 64,
  	.e_phentsize = 56,
  	.e_phnum = 13,
  	.e_shentsize = 64,
  	.e_shnum = 31,
  	.e_shstrndx = 30,
  },
  ⬢[acme@toolbox pahole]$ pahole --header elf64_hdr --prettify - < /bin/bash
  {
  	.e_ident = { 127, 69, 76, 70, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  	.e_type = 3,
  	.e_machine = 62,
  	.e_version = 1,
  	.e_entry = 204016,
  	.e_phoff = 64,
  	.e_shoff = 1388096,
  	.e_flags = 0,
  	.e_ehsize = 64,
  	.e_phentsize = 56,
  	.e_phnum = 13,
  	.e_shentsize = 64,
  	.e_shnum = 31,
  	.e_shstrndx = 30,
  },
  ⬢[acme@toolbox pahole]$ pahole --header elf64_hdr --prettify=- < /bin/bash
  {
  	.e_ident = { 127, 69, 76, 70, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  	.e_type = 3,
  	.e_machine = 62,
  	.e_version = 1,
  	.e_entry = 204016,
  	.e_phoff = 64,
  	.e_shoff = 1388096,
  	.e_flags = 0,
  	.e_ehsize = 64,
  	.e_phentsize = 56,
  	.e_phnum = 13,
  	.e_shentsize = 64,
  	.e_shnum = 31,
  	.e_shstrndx = 30,
  },
  ⬢[acme@toolbox pahole]$

Reported-by: Bernd Buschinski <b.buschinski@googlemail.com>
Report-Link: https://lore.kernel.org/dwarves/CACN-hLVoz2tWrtgDLabOv6S1-H_8RD2fh8SV6EnADF1ikMxrmw@mail.gmail.com/
Tested-by-by: Bernd Buschinski <b.buschinski@googlemail.com>
Test-Link: https://lore.kernel.org/dwarves/CACN-hLXgHWdBkyMz+w58qX8DaV+WJ1mj1qheGBHbPv4fqozi5w@mail.gmail.com/
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-08-12 09:41:13 -03:00
Arnaldo Carvalho de Melo 1a65d232b0 man-page: Move the PRETTY PRINTING header earlier
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-08-12 09:41:13 -03:00
Arnaldo Carvalho de Melo a3fcbcacf7 pahole: Allow specifying the number of threads to use while loading files
Using the same command line option as 'make' and 'ninja': -j.
Unfortunately the argp parser in glibc expects a '=' for single letter
args, so it is:

  $ pahole -j=10

or, like with 'make':

  $ make --jobs=10

This is unwired at the moment, probably I'll reorder the patch, but for
testing, add it first.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-07-28 15:18:16 -03:00
Arnaldo Carvalho de Melo d70b2562ee pahole: Make '-j' available for use as number of jobs (threads)
The '-j' option, to generate detached BTF files wasn't published in any
tagged release, so leave it as just --btf_encode_detached and make '-j'
available for specifying the number of jobs/threads, as is the case with
'make -j', 'ninja -j', etc.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-07-28 15:18:16 -03:00
Arnaldo Carvalho de Melo 89be5646a0 pahole: Allow encoding BTF into a detached file
Previously the newly encoded BTF info was stored into a ELF section in
the file where the DWARF info was obtained, but it is useful to just
dump it into a separate file, do it.

  $ ls -la vmlinux.btf
  ls: cannot access 'vmlinux.btf': No such file or directory
  $ pahole -j vmlinux.btf vmlinux
  $ ls -la vmlinux.btf
  -rw-r-----. 1 acme acme 4630082 Jun  1 16:15 vmlinux.btf
  $ pahole -C list_head ./vmlinux.btf
  struct list_head {
  	struct list_head *         next;                 /*     0     8 */
  	struct list_head *         prev;                 /*     8     8 */

  	/* size: 16, cachelines: 1, members: 2 */
  	/* last cacheline: 16 bytes */
  };
  acme@toolbox pahole]$ pahole -C raw_spinlock_t ./vmlinux.btf
  typedef struct raw_spinlock raw_spinlock_t;
  acme@toolbox pahole]$ pahole -EC raw_spinlock ./vmlinux.btf
  struct raw_spinlock {
  	/* typedef arch_spinlock_t */ struct qspinlock {
  		union {
  			/* typedef atomic_t */ struct {
  				int counter;                                                  /*     0     4 */
  			} val;                                                                /*     0     4 */
  			struct {
  				/* typedef u8 -> __u8 */ unsigned char locked;                /*     0     1 */
  				/* typedef u8 -> __u8 */ unsigned char pending;               /*     1     1 */
  			};                                                                    /*     0     2 */
  			struct {
  				/* typedef u16 -> __u16 */ short unsigned int locked_pending; /*     0     2 */
  				/* typedef u16 -> __u16 */ short unsigned int tail;           /*     2     2 */
  			};                                                                    /*     0     4 */
  		};                                                                            /*     0     4 */
  	} raw_lock;                                                                           /*     0     4 */

  	/* size: 4, cachelines: 1, members: 1 */
  	/* last cacheline: 4 bytes */
  };
  ⬢[acme@toolbox pahole]$

Requested-by: Andrii Nakryiko <andrii@kernel.org>
Acked-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-06-04 17:28:54 -03:00
Shuyi Cheng 3d510406ff pahole: Add --kabi_prefix flag
To solve problems similar to _RH_KABI_REPLACE. The _RH_KABI_REPLACE(_orig, _new) macros perserve size alignment and kabi agreement between _orig and _new.Below is the definition of this macro:

    union {                        \
        _new;                    \
        struct {                \
            _orig;                \
        } __UNIQUE_ID(rh_kabi_hide);        \
        __RH_KABI_CHECK_SIZE_ALIGN(_orig, _new);    \
    }

__UNIQUE_ID uses the __COUNTER__ macro, and the __COUNTER__ macro is automatically incremented by 1 every time it is precompiled. Therefore, in different compilation units, the same structure has different names.Here is a concrete example:

struct acpi_dev_node {
    union {
        struct acpi_device *companion;
        struct {
            void *handle;
        } __UNIQUE_ID_rh_kabi_hide29;
        union {        };
    };
};
struct acpi_dev_node {
    union {
        struct acpi_device *companion;
        struct {
            void *handle;
        } __UNIQUE_ID_rh_kabi_hide31;
        union {        };
    };
};

Finally, it will cause the btf algorithm to de-duplication efficiency is not high, and time-consuming. For example, running ./pahole -J vmlinux-3.10.0-1160.el7.x86_64 without --kabi_prefix flag, the running time is:
                real 8m28.912s
                user 8m27.271s
                sys 0m1.471s
And the size of the generated btf segment is 30678240 bytes.

After adding the patch, running ./pahole --kabi_prefix=__UNIQUE_ID_rh_kabi_hide -J vmlinux-3.10.0-1160.el7.x86_64. The running time of the command is:
                real 0m19.634s
                user 0m18.457s
                sys 0m1.169s
And the size of the generated btf segment is 3117719 bytes.

Signed-off-by: Shuyi Cheng <chengshuyi@linux.alibaba.com>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Cc: Andrii Nakryiko <andrii.nakryiko@gmail.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Wenan Mao <wenan.mao@linux.alibaba.com>
Cc: dwarves@vger.kernel.org
Link: https://lore.kernel.org/dwarves/482e5543-d7da-7bed-098d-cc879d8db253@linux.alibaba.com/
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-05-27 13:44:35 -03:00
Arnaldo Carvalho de Melo 7eea706c14 pahole: Introduce --with_flexible_array option to show just types ending in a flexible array
The kernel has lotsa:

  $ pahole --sizes --with_flexible_array | wc -l
  1134
  $

  $ pahole --with_flexible_array | tail -18
  struct pci_setup_rom {
  	struct setup_data          data;                 /*     0    16 */
  	uint16_t                   vendor;               /*    16     2 */
  	uint16_t                   devid;                /*    18     2 */

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

  	uint64_t                   pcilen;               /*    24     8 */
  	long unsigned int          segment;              /*    32     8 */
  	long unsigned int          bus;                  /*    40     8 */
  	long unsigned int          device;               /*    48     8 */
  	long unsigned int          function;             /*    56     8 */
  	/* --- cacheline 1 boundary (64 bytes) --- */
  	uint8_t                    romdata[];            /*    64     0 */

  	/* size: 64, cachelines: 1, members: 9 */
  	/* sum members: 60, holes: 1, sum holes: 4 */
  };
  $

Works together with other filters:

  $ pahole --contains setup_data --with_flexible_array
  pci_setup_rom
  $ pahole pci_setup_rom
  struct pci_setup_rom {
  	struct setup_data          data;                 /*     0    16 */
  	uint16_t                   vendor;               /*    16     2 */
  	uint16_t                   devid;                /*    18     2 */

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

  	uint64_t                   pcilen;               /*    24     8 */
  	long unsigned int          segment;              /*    32     8 */
  	long unsigned int          bus;                  /*    40     8 */
  	long unsigned int          device;               /*    48     8 */
  	long unsigned int          function;             /*    56     8 */
  	/* --- cacheline 1 boundary (64 bytes) --- */
  	uint8_t                    romdata[];            /*    64     0 */

  	/* size: 64, cachelines: 1, members: 9 */
  	/* sum members: 60, holes: 1, sum holes: 4 */
  };
  $

  $ pahole --find_pointers_to net_device --with_flexible_array
  neighbour: dev
  pneigh_entry: dev
  xsk_buff_pool: netdev
  cfg80211_sched_scan_request: dev
  switchdev_deferred_item: dev
  $ pahole xsk_buff_pool
  struct xsk_buff_pool {
  	struct device *            dev;                  /*     0     8 */
  	struct net_device *        netdev;               /*     8     8 */
  	struct list_head           xsk_tx_list;          /*    16    16 */
  	spinlock_t                 xsk_tx_list_lock;     /*    32     4 */
  	refcount_t                 users;                /*    36     4 */
  	struct xdp_umem *          umem;                 /*    40     8 */
  	struct work_struct         work;                 /*    48    32 */
  	/* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */
  	struct list_head           free_list;            /*    80    16 */
  	u32                        heads_cnt;            /*    96     4 */
  	u16                        queue_id;             /*   100     2 */

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

  	/* --- cacheline 2 boundary (128 bytes) --- */
  	struct xsk_queue *         fq;                   /*   128     8 */
  	struct xsk_queue *         cq;                   /*   136     8 */
  	dma_addr_t *               dma_pages;            /*   144     8 */
  	struct xdp_buff_xsk *      heads;                /*   152     8 */
  	u64                        chunk_mask;           /*   160     8 */
  	u64                        addrs_cnt;            /*   168     8 */
  	u32                        free_list_cnt;        /*   176     4 */
  	u32                        dma_pages_cnt;        /*   180     4 */
  	u32                        free_heads_cnt;       /*   184     4 */
  	u32                        headroom;             /*   188     4 */
  	/* --- cacheline 3 boundary (192 bytes) --- */
  	u32                        chunk_size;           /*   192     4 */
  	u32                        frame_len;            /*   196     4 */
  	u8                         cached_need_wakeup;   /*   200     1 */
  	bool                       uses_need_wakeup;     /*   201     1 */
  	bool                       dma_need_sync;        /*   202     1 */
  	bool                       unaligned;            /*   203     1 */

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

  	void *                     addrs;                /*   208     8 */
  	spinlock_t                 cq_lock;              /*   216     4 */

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

  	struct xdp_buff_xsk *      free_heads[];         /*   224     0 */

  	/* size: 256, cachelines: 4, members: 29 */
  	/* sum members: 190, holes: 3, sum holes: 34 */
  	/* padding: 32 */
  };
  $

Cc: "Gustavo A. R. Silva" <gustavoars@kernel.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-04-12 13:52:34 -03:00
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