Commit Graph

1162 Commits

Author SHA1 Message Date
Andrii Nakryiko 21507cd3e9 pahole: add libbpf as submodule under lib/bpf
This change allows to use libbpf definitions and APIs from pahole.

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-02-11 12:56:40 -03:00
Andrii Nakryiko c25ada500d pahole: Add build dir, config.h to .gitignore
These are build-only and are not meant to be checked in.

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-02-11 12:55:46 -03:00
Martin Lau a58c746c4c Fixup copyright notices for BTF files authored by Facebook engineers
Cc: Andrii Nakryiko <andriin@fb.com>
Cc: Domenico Andreoli <domenico.andreoli@linux.com>
Cc: Yonghong Song <yhs@fb.com>
Signed-off-by: Martin Lau <kafai@fb.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-01-18 20:34:05 -03:00
Domenico Andreoli e714d2eaa1 Adopt SPDX-License-Identifier
Signed-off-by: Domenico Andreoli <domenico.andreoli@linux.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-01-18 15:41:48 -03:00
Arnaldo Carvalho de Melo c86960dce5 btf_loader: We can set class_member->type_offset earlier
Because we don't have to lookup the member type that is encoded after
it, i.e. some member fields depend on first processing everything, then
lookup the types to get the sizes, etc.

But the:

    member->byte_offset = member->bit_offset / 8;

Can be done soon after we have member->bit_offset loaded from the BTF
section.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-01-17 15:42:02 -03:00
Arnaldo Carvalho de Melo 278b64c3ee btfdiff: Use diff's -p option to show the struct/union
To help in looking up the change and figure out its reason.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-01-17 10:07:13 -03:00
Arnaldo Carvalho de Melo 1182664d6a dwarves_fprintf: Handle negative bit_offsets in packed structs with bitfields
Andrii reported that structs with bitfields and with __attribute__((packed)) were
not producing correct output, that is because pahole and friends didn't
knew about something Yonghong discovered: DW_AT_bit_offset may be
negative when a bitfield straddles a 4 byte boundary, fix it so that we
produce a saner output:

  $ cat examples/yonghong/packed_bitfield.c
  struct packed {
          char x1: 1;
          char x2: 3;
          char x3: 3;
          int y1: 7;
          int y2: 20;
  } __attribute__((packed));
  struct packed g;
  $

  cc -g -c examples/yonghong/packed_bitfield.c

  $ readelf -wi packed_bitfield.o | grep bit_offset
    <37>   DW_AT_bit_offset  : 7
    <46>   DW_AT_bit_offset  : 4
    <55>   DW_AT_bit_offset  : 1
    <64>   DW_AT_bit_offset  : 18
    <73>   DW_AT_bit_offset  : -2
  $

Before:

  $ pahole packed_bitfield.o
  struct packed {
          char                       x1:1;                 /*     0: 7  1 */
          char                       x2:3;                 /*     0: 4  1 */
          char                       x3:3;                 /*     0: 1  1 */
          int                        y1:7;                 /*     0:18  4 */
          int                        y2:20;                /*     0:4294967294  4 */

          /* size: 5, cachelines: 1, members: 5 */
          /* padding: 1 */
          /* bit_padding: 254 bits */
          /* last cacheline: 5 bytes */

          /* BRAIN FART ALERT! 5 != 1 + 0(holes), diff = 4 */
  };
  $

Now:

  $ pahole packed_bitfield.o
  struct packed {
          char                       x1:1;                 /*     0: 7  1 */
          char                       x2:3;                 /*     0: 4  1 */
          char                       x3:3;                 /*     0: 1  1 */
          int                        y1:7;                 /*     0:18  4 */
          int                        y2:20;                /*     4:30  4 */

          /* size: 5, cachelines: 1, members: 5 */
          /* padding: 1 */
          /* bit_padding: 254 bits */
          /* last cacheline: 5 bytes */

          /* BRAIN FART ALERT! 5 != 1 + 0(holes), diff = 4 */
  };
  $

And for two big endian archs, one 32-bit and the other 64-bit:

  $ file ~acme/git/tmp/packed_bitfield.powerpc.o
  /home/acme/git/tmp/packed_bitfield.powerpc.o: ELF 32-bit MSB relocatable, PowerPC or cisco 4500, version 1 (SYSV), with debug_info, not stripped
  $ pahole ~acme/git/tmp/packed_bitfield.powerpc.o
  struct packed {
          char                       x1:1;                 /*     0: 0  1 */
          char                       x2:3;                 /*     0: 1  1 */
          char                       x3:3;                 /*     0: 4  1 */
          int                        y1:7;                 /*     0: 7  4 */
          int                        y2:20;                /*     0:14  4 */

          /* size: 5, cachelines: 1, members: 5 */
          /* padding: 1 */
          /* bit_padding: 254 bits */
          /* last cacheline: 5 bytes */

          /* BRAIN FART ALERT! 5 != 1 + 0(holes), diff = 4 */
  };
  $
  $ file ~acme/git/tmp/packed_bitfield.sparc64.o
  /home/acme/git/tmp/packed_bitfield.sparc64.o: ELF 64-bit MSB relocatable, SPARC V9, relaxed memory ordering, version 1 (SYSV), with debug_info, not stripped
  $
  $ pahole ~acme/git/tmp/packed_bitfield.sparc64.o
  struct packed {
          char                       x1:1;                 /*     0: 0  1 */
          char                       x2:3;                 /*     0: 1  1 */
          char                       x3:3;                 /*     0: 4  1 */
          int                        y1:7;                 /*     0: 7  4 */
          int                        y2:20;                /*     0:14  4 */

          /* size: 5, cachelines: 1, members: 5 */
          /* padding: 1 */
          /* bit_padding: 254 bits */
          /* last cacheline: 5 bytes */

          /* BRAIN FART ALERT! 5 != 1 + 0(holes), diff = 4 */
  };

Now to fix the holes calculations.

Reported-by: Andrii Nakryiko <andrii.nakryiko@gmail.com>
Acked-by: Yonghong Song <yhs@fb.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Martin Lau <kafai@fb.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-01-15 15:12:38 -03:00
Yonghong Song b0cf845e02 dwarves: Change type of bitfield_offset from uint8_t to int8_t
The dwarves class_member field bitfield_offset represents the dwarf tag
DW_AT_bit_offset. For dwarf2, this field can be negative for little
endian for bitfields in packed data structures which cross type
boundary.

  -bash-4.4$ cat bitfield.c
  struct packed {
    char x1: 1;
    char x2: 3;
    char x3: 3;
    int y1: 7;
    int y2: 20;
  } __attribute__((packed));
  struct packed g;
  -bash-4.4$ gcc -O2 -c -g bitfield.c
  -bash-4.4$ pahole -JV bitfield.o
  File bitfield.o:
  [1] STRUCT packed kind_flag=1 size=5 vlen=5
        x1 type_id=2 bitfield_size=1 bits_offset=0
        x2 type_id=2 bitfield_size=3 bits_offset=1
        x3 type_id=2 bitfield_size=3 bits_offset=4
        y1 type_id=3 bitfield_size=7 bits_offset=7
        y2 type_id=3 bitfield_size=255 bits_offset=16776974
  [2] INT char size=1 bit_offset=0 nr_bits=8 encoding=(none)
  [3] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
  -bash-4.4$

The above large negative bits_offset and bitfield_size=255 results from
negative bitfield_offset which is interpreted as positive value in btf
encoding.

With this fix, the pahole works properly for BTF:
  -bash-4.4$ pahole -JV bitfield.o
  File bitfield.o:
  [1] STRUCT packed kind_flag=1 size=5 vlen=5
        x1 type_id=2 bitfield_size=1 bits_offset=0
        x2 type_id=2 bitfield_size=3 bits_offset=1
        x3 type_id=2 bitfield_size=3 bits_offset=4
        y1 type_id=3 bitfield_size=7 bits_offset=7
        y2 type_id=3 bitfield_size=20 bits_offset=14
  [2] INT char size=1 bit_offset=0 nr_bits=8 encoding=(none)
  [3] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
  -bash-4.4$

Note that change bitfield_offset from uint8_t to int8_t is safe as the
maximum int type we support is __int128 and maximum bitfield_offset is
127.

Signed-off-by: Yonghong Song <yhs@fb.com>
Reported-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Andrii Nakryiko <andriin@fb.com>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: dwarves@vger.kernel.org
Link: https://www.spinics.net/lists/dwarves/msg00199.html
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-01-14 10:35:04 -03:00
Arnaldo Carvalho de Melo 06e364bc62 btfdiff: Add utility to compare pahole output produced from DWARF and BTF
$ btfdiff
  Usage: btfdiff <filename_with_BTF_and_DWARF_info>
  $ btfdiff ~/git/build/v4.20-rc5+/net/ipv4/tcp.o
  --- /tmp/btfdiff.LRlcgc	2019-01-11 13:55:16.808989679 -0300
  +++ /tmp/btfdiff.SHuCev	2019-01-11 13:55:16.819989781 -0300
  @@ -585,11 +585,17 @@
   	__u16                      vesapm_off;           /*    48     2 */
   	__u16                      pages;                /*    50     2 */
   	__u16                      vesa_attributes;      /*    52     2 */
  -	__u32                      capabilities;         /*    54     4 */
  -	__u32                      ext_lfb_base;         /*    58     4 */
  +	__u32                      capabilities;         /*    52     4 */
  +	__u32                      ext_lfb_base;         /*    56     4 */
  +
  +	/* XXX 2 bytes hole, try to pack */
  +
   	__u8                       _reserved[2];         /*    62     2 */

   	/* size: 64, cachelines: 1, members: 36 */
  +	/* sum members: 60, holes: 1, sum holes: 2 */
  +
  +	/* BRAIN FART ALERT! 64 != 60 + 2(holes), diff = 2 */
   };
   struct apm_bios_info {
   	__u16                      version;              /*     0     2 */
  <SNIP>
  $

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-01-11 13:54:22 -03:00
Yonghong Song b79db4cab4 dwarves: add __int128 types in base_type_name_to_size
Added int128 types to dwarf base_type_name_to_size table
so that the correct base type size can be retrieved in certain
cases. Note that for type "unsigned __int128", the dwarf in gcc
has type name "__int128 unsigned" while clang has
"unsigned __int128".

  -bash-4.4$ cat t.c
  struct t {
        __int128 si128a;
        __int128 si128b;
        unsigned __int128 bits3:3;
        unsigned __int128 bits80:80;
        unsigned __int128 ui128;
  } g;
  -bash-4.4$ clang -O2 -c -g -target bpf -Xclang -target-feature -Xclang +dwarfris t.c
  -bash-4.4$ pahole -F dwarf t.o
  struct t {
        __int128                   si128a;               /*     0    16 */
        __int128                   si128b;               /*    16    16 */
        unsigned __int128          bits3:3;              /*    32:125 16 */
        unsigned __int128          bits80:80;            /*    32:45 16 */

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

        unsigned __int128          ui128;                /*    48    16 */

        /* size: 64, cachelines: 1, members: 5 */
        /* bit holes: 1, sum bit holes: 45 bits */
  };
  -bash-4.4$ pahole -F btf t.o
  struct t {
        __int128                   si128a;               /*     0    16 */
        __int128                   si128b;               /*    16    16 */
        unsigned __int128          bits3:3;              /*    32:125 16 */
        unsigned __int128          bits80:80;            /*    32:45 16 */

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

        unsigned __int128          ui128;                /*    48    16 */

        /* size: 64, cachelines: 1, members: 5 */
        /* bit holes: 1, sum bit holes: 45 bits */
  };
  -bash-4.4$ pahole -JV t.o
  File t.o:
  [1] STRUCT t kind_flag=1 size=64 vlen=5
        si128a type_id=2 bitfield_size=0 bits_offset=0
        si128b type_id=2 bitfield_size=0 bits_offset=128
        bits3 type_id=3 bitfield_size=3 bits_offset=256
        bits80 type_id=3 bitfield_size=80 bits_offset=259
        ui128 type_id=3 bitfield_size=0 bits_offset=384
  [2] INT __int128 size=16 bit_offset=0 nr_bits=128 encoding=SIGNED
  [3] INT unsigned __int128 size=16 bit_offset=0 nr_bits=128 encoding=(none)
  [4] INT (anon) size=4 bit_offset=0 nr_bits=32 encoding=(none)
  -bash-4.4$

Committer testing:

Before:

  $ cat __int128.c
    struct t {
          __int128 si128a;
          __int128 si128b;
          unsigned __int128 bits3:3;
          unsigned __int128 bits80:80;
          unsigned __int128 ui128;
    } g;
  $ clang -O2 -c -g -target bpf -Xclang -target-feature -Xclang +dwarfris __int128.c
  $ pahole __int128.o
  base_type__name_to_size: base_type unsigned __int128
  base_type__name_to_size: base_type unsigned __int128
  struct t {
  	__int128                   si128a;               /*     0    16 */
  	__int128                   si128b;               /*    16    16 */
  	unsigned __int128          bits3:3;              /*    32:125  0 */
  	unsigned __int128          bits80:80;            /*    32:45  0 */

  	/* XXX 173 bits hole, try to pack */
  	/* XXX 16 bytes hole, try to pack */

  	unsigned __int128          ui128;                /*    48    16 */

  	/* size: 64, cachelines: 1, members: 5 */
  	/* sum members: 48, holes: 1, sum holes: 16 */
  	/* bit holes: 1, sum bit holes: 173 bits */
  };
  $ pahole -J __int128.o
  base_type__name_to_size: base_type unsigned __int128
  base_type__name_to_size: base_type unsigned __int128

After:

  $ pahole -F dwarf __int128.o
  struct t {
  	__int128                   si128a;               /*     0    16 */
  	__int128                   si128b;               /*    16    16 */
  	unsigned __int128          bits3:3;              /*    32:125 16 */
  	unsigned __int128          bits80:80;            /*    32:45 16 */

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

  	unsigned __int128          ui128;                /*    48    16 */

  	/* size: 64, cachelines: 1, members: 5 */
  	/* bit holes: 1, sum bit holes: 45 bits */
  };
  $
  $ pahole -J __int128.o
  $ pahole -F btf __int128.o
  struct t {
  	__int128                   si128a;               /*     0    16 */
  	__int128                   si128b;               /*    16    16 */
  	unsigned __int128          bits3:3;              /*    32:125 16 */
  	unsigned __int128          bits80:80;            /*    32:45 16 */

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

  	unsigned __int128          ui128;                /*    48    16 */

  	/* size: 64, cachelines: 1, members: 5 */
  	/* bit holes: 1, sum bit holes: 45 bits */
  };
  $

Signed-off-by: Yonghong Song <yhs@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-01-10 16:58:56 -03:00
Arnaldo Carvalho de Melo de3459cc0e btf_loader: BTF encodes the size of enums as bytes not bits
I wrote the BTF loader from the CTF loader, where the size of
enumerations is expressed in bits, while BTF encodes it in bytes, fix
it.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-01-10 15:26:53 -03:00
Andrii Nakryiko 693347f8de btf_encoder: Fix void handling in FUNC_PROTO.
When dealing with BTF encoding of multiple CUs, special `void` type
should be handled explicitly.

This is already handled for all BTF types except recently added
FUNC_PROTO.

Without this fix, any `void` type directly referenced from FUNC_PROTO
will turn into last type from previous CU (see example below, for
FUNC_PROTO [4]).

  $ cat test1.c
  void (*foo)(void);

  int main() {
      return 0;
  }

  $ cat test2.c
  void (*bar)(void);

  $ cc -g test1.c test2.c -o test

Without fix:

  $ LLVM_OBJCOPY=objcopy ~/local/pahole/build/pahole -JV /tmp/test
  File /tmp/test:
  [1] INT int size=4 bit_offset=0 nr_bits2 encoding=SIGNED
  [2] FUNC_PROTO (anon) return=0 args=(void)
  [3] PTR (anon) type_id=2
  [4] FUNC_PROTO (anon) return=3 args=(void)
  [5] PTR (anon) type_id=4

With fix:

  $ LLVM_OBJCOPY=objcopy ~/local/pahole/build/pahole -JV /tmp/test
  File /tmp/test:
  [1] INT int size=4 bit_offset=0 nr_bits2 encoding=SIGNED
  [2] FUNC_PROTO (anon) return=0 args=(void)
  [3] PTR (anon) type_id=2
  [4] FUNC_PROTO (anon) return=0 args=(void)
  [5] PTR (anon) type_id=4

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Acked-by: Yonghong Song <yhs@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: dwarves@vger.kernel.org
[ Applied patch by hand, came mangled ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-01-10 15:26:53 -03:00
Arnaldo Carvalho de Melo 2d0b70664f dwarves_fprintf: Separate basic type stats into separate type__fprintf() method
So that we can use it for unions, in the next cset.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-01-10 15:26:53 -03:00
Arnaldo Carvalho de Melo 18f5910f96 dwarves: Add type to tag helper
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-01-10 15:26:53 -03:00
Yonghong Song f2092f5658 btf: recognize BTF_KIND_FUNC in btf_loader
BTF_KIND_FUNC is generated by llvm (latest trunk, 8.0 or later).
Without BTF_KIND_FUNC support, we will see the following errors,

  -bash-4.4$ cat t.c
  struct t {
    int a;
    char b1:1;
    char b2:3;
    int c;
  } g;
  int main() { return 0; }
  -bash-4.4$ clang -O2 -target bpf -g -c t.c -Xclang -target-feature -Xclang +dwarfris

  -bash-4.4$ pahole -F btf t.o
  BTF: idx: 3, off: 28, Unknown
  struct t {
        int                        a;                    /*     0     4 */

        /* Bitfield combined with previous fields */

        <ERROR(__class__fprintf:1342): 5 not found!>

        /* Bitfield combined with previous fields */

        <ERROR(__class__fprintf:1342): 5 not found!>
        int                        c;                    /*     8     4 */

        /* size: 12, cachelines: 1, members: 4 */
        /* last cacheline: 12 bytes */

        /* BRAIN FART ALERT! 12 != 8 + 0(holes), diff = 4 */

  };
  -bash-4.4$

The reason is that llvm generates BTF_KIND_FUNC which btf_loader does not
recognize.

This patch added support for BTF_KIND_FUNC. Since BTF_KIND_FUNC represents
a defined subprogram and not a real type. A null type is used to
represent BTF_KIND_FUNC to avoid skipping type index.

With this fix:

  -bash-4.4$ pahole -F btf t.o
  struct t {
        int                        a;                    /*     0     4 */
        char                       b1:1;                 /*     4: 0  1 */
        char                       b2:3;                 /*     4: 1  1 */
        int                        c;                    /*     8     4 */

        /* size: 12, cachelines: 1, members: 4 */
        /* last cacheline: 12 bytes */

        /* BRAIN FART ALERT! 12 != 9 + 0(holes), diff = 3 */

  };

Signed-off-by: Yonghong Song <yhs@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-01-10 15:26:53 -03:00
Yonghong Song 1176661409 btf: Fix kind_flag usage in btf_loader
Commit 2a82d593be ("btf: Add kind_flag support for btf_loader") added
kind_flag supported in btf_loader to get correct bitfield_size and
bit_offset for struct/union members.  The commit unnecessarily stored
the bit in the structure type which is not used later.

So let us remove the kind_flag from the struct type and any other
changes whose purpose is to set this bit.

Signed-off-by: Yonghong Song <yhs@fb.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Martin KaFai Lau <kafai@fb.com>
Fixes: 2a82d593be ("btf: Add kind_flag support for btf_loader")
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-01-10 15:26:53 -03:00
Arnaldo Carvalho de Melo 68b93e6858 dutil: Add missing string.h header include
Addressing this build warning:

  In file included from /home/acme/git/pahole/dutil.c:10:
  /home/acme/git/pahole/dutil.h: In function ‘strstarts’:
  /home/acme/git/pahole/dutil.h:301:9: warning: implicit declaration of function ‘strncmp’ [-Wimplicit-function-declaration]
    return strncmp(str, prefix, strlen(prefix)) == 0;
           ^~~~~~~
  /home/acme/git/pahole/dutil.h:301:30: warning: implicit declaration of function ‘strlen’ [-Wimplicit-function-declaration]
    return strncmp(str, prefix, strlen(prefix)) == 0;
                                ^~~~~~
  /home/acme/git/pahole/dutil.h:301:30: warning: incompatible implicit declaration of built-in function ‘strlen’
  /home/acme/git/pahole/dutil.h:301:30: note: include ‘<string.h>’ or provide a declaration of ‘strlen’
  /home/acme/git/pahole/dutil.h:20:1:
  +#include <string.h>

  /home/acme/git/pahole/dutil.h:301:30:
    return strncmp(str, prefix, strlen(prefix)) == 0;
                                ^~~~~~

Fixes: a2cdc6c2a0 ("dutil: Adopt strstart() from the linux perf tools sources")
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-01-10 15:26:53 -03:00
Arnaldo Carvalho de Melo 851ef335e3 dutil: Drop 'noreturn' attribute for ____ilog2_NaN()
To clear this warning:

  [ 97%] Building C object CMakeFiles/pdwtags.dir/pdwtags.o
  In file included from /home/acme/git/pahole/dwarves.h:19,
                   from /home/acme/git/pahole/pdwtags.c:14:
  /home/acme/git/pahole/dutil.h:155:1: warning: ignoring attribute ‘noreturn’ because it conflicts with attribute ‘const’ [-Wattributes]
   int ____ilog2_NaN(void);
   ^~~

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-01-10 15:26:53 -03:00
Arnaldo Carvalho de Melo ab0cb33e54 btf_loader: Fixup class_member->bit_offset for !big_endian files
Yonghong explains:

<quote>
The bitfield offset in BTF starts from lower number to bigger one. That
is, it is always following the big endian convention, bitfield_offset
will be smaller if close to the top of structure.

This is different from what dwarf is doing, which will show different
things on little endian vs. big endian.

You can make simple adjustment based on all available info. In
btf_encoder.s, we did similar adjustment for little endian from
dwarf to btf.
</>

So fix it up while loading, so that the rebuilt C output shows the same
thing from BTF and from DWARF.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-01-10 15:26:53 -03:00
Arnaldo Carvalho de Melo b24718fe27 dwarves: Fix documentation for class_memer->bitfield_size
Just a cut'n'past thinko.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-01-10 15:26:53 -03:00
Arnaldo Carvalho de Melo 3ffe5ba93b pahole: Do not apply 'struct class' filters to 'struct type'
Now unions are handled as well in pahole, so bail out before checking
'struct class' members for struct specific filters when handling
non-structs in class__filter()

Tested-by: Andrii Nakryiko <andriin@fb.com>
Fixes: 31664d60ad ("pahole: Show tagged enums as well when no class is specified")
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-01-10 15:26:48 -03:00
Arnaldo Carvalho de Melo da18bb340b dwarves: Check if the tag is a 'struct class' in class__find_holes()
In pahole we started showing 'union' tags as well, and those are
represented by 'struct type', so be defensive in class__find_holes(),
checking if the tag is represented with a 'struct class'.

Tested-by: Andrii Nakryiko <andriin@fb.com>
Fixes: 31664d60ad ("pahole: Show tagged enums as well when no class is specified")
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-01-10 15:26:13 -03:00
Yonghong Song 2a82d593be btf: Add kind_flag support for btf_loader
For struct/union members, the struct/union type info kind_flag is needed
to calculate correct bitfield_size and bit_offset.

  if (kind_flag) {
    bitfield_size = BTF_MEMBER_BITFIELD_SIZE(member->offset);
    bit_offset = BTF_MEMBER_BIT_OFFSET(member->offset);
  } else {
    bitfield_size = 0;
    bit_offset = member->offset;
  }

Note that bitfield_size and bit_offset will not depend on the member
type. The member type will help calculate correct bitfield_offset,
byte_size, byte_offset, bit_size.

For example, with the fix, we will be able to display
bit offset and bitfield size properly.

  -bash-4.4$ cat t.c
  struct t {
    int a:2;
    int b:3;
    int c:2;
  } g;
  -bash-4.4$ gcc -c -O2 -g t.c
  -bash-4.4$ pahole -JV t.o
  File t.o:
  [1] STRUCT t kind_flag=1 size=4 vlen=3
          a type_id=2 bitfield_size=2 bits_offset=0
          b type_id=2 bitfield_size=3 bits_offset=2
          c type_id=2 bitfield_size=2 bits_offset=5
  [2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
  -bash-4.4$ pahole -F btf t.o
  struct t {
          int                        a:2;                  /*     0: 0  4 */
          int                        b:3;                  /*     0: 2  4 */
          int                        c:2;                  /*     0: 5  4 */

          /* size: 4, cachelines: 1, members: 3 */
          /* bit_padding: 25 bits */
          /* last cacheline: 4 bytes */
  };

Note that the above offset showing is different from the below dwarf as
BTF bitfield_offset is always the offset from the start of structure,
kindly like big endian encoding. This may need adjustment to be
conforming to the dwarf dump format.

  -bash-4.4$ pahole -F dwarf t.o
  struct t {
          int                        a:2;                  /*     0:30  4 */
          int                        b:3;                  /*     0:27  4 */
          int                        c:2;                  /*     0:25  4 */

          /* size: 4, cachelines: 1, members: 3 */
          /* bit_padding: 25 bits */
          /* last cacheline: 4 bytes */
  };

Signed-off-by: Yonghong Song <yhs@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-21 09:51:12 -03:00
Arnaldo Carvalho de Melo 472256d3c5 btf_loader: Introduce a loader for the BTF format
Show 'struct list_head' from DWARF info:

  $ pahole -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o
  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 */
  };

Try to show it from BTF, on a file without it:

  $ pahole -F btf -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o
  pahole: /home/acme/git/build/v4.20-rc5+/net/ipv4/tcp.o: No debugging information found

Encode BTF from the DWARF info:

  $ pahole -J ~/git/build/v4.20-rc5+/net/ipv4/tcp.o

Check that it is there:
  $ readelf -SW ~/git/build/v4.20-rc5+/net/ipv4/tcp.o  | grep BTF
  readelf: /home/acme/git/build/v4.20-rc5+/net/ipv4/tcp.o: Warning: possibly corrupt ELF header - it has a non-zero program header offset, but no program headers
    [136] .BTF              PROGBITS        0000000000000000 101d0e 042edf 00      0   0  1

Now try again printing 'struct list_head' from the BTF info just
encoded:

  $ pahole -F btf -C list_head ~/git/build/v4.20-rc5+/net/ipv4/tcp.o  2> /dev/null
  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 */
  };
  $

There is the bitfields case that BTF desn't have the bit_size info for
bitfield members that makes the output from dwarf to be different than
the one from BTF:

  $ pahole -F btf -C sk_buff ~/git/build/v4.20-rc5+/net/ipv4/tcp.o > /tmp/sk_buff.btf
  $ pahole -F dwarf -C sk_buff ~/git/build/v4.20-rc5+/net/ipv4/tcp.o > /tmp/sk_buff.dwarf
  $ diff -u /tmp/sk_buff.dwarf /tmp/sk_buff.btf
  --- /tmp/sk_buff.dwarf	2018-12-20 14:50:51.428653046 -0300
  +++ /tmp/sk_buff.btf	2018-12-20 14:50:46.302601516 -0300
  @@ -38,45 +38,45 @@
   	__u16                      hdr_len;              /*   138     2 */
   	__u16                      queue_mapping;        /*   140     2 */
   	__u8                       __cloned_offset[0];   /*   142     0 */
  -	__u8                       cloned:1;             /*   142: 7  1 */
  -	__u8                       nohdr:1;              /*   142: 6  1 */
  -	__u8                       fclone:2;             /*   142: 4  1 */
  -	__u8                       peeked:1;             /*   142: 3  1 */
  -	__u8                       head_frag:1;          /*   142: 2  1 */
  -	__u8                       xmit_more:1;          /*   142: 1  1 */
  -	__u8                       pfmemalloc:1;         /*   142: 0  1 */
  +	__u8                       cloned;               /*   142     1 */
  +	__u8                       nohdr;                /*   142     1 */
  +	__u8                       fclone;               /*   142     1 */
  +	__u8                       peeked;               /*   142     1 */
  +	__u8                       head_frag;            /*   142     1 */
  +	__u8                       xmit_more;            /*   142     1 */
  +	__u8                       pfmemalloc;           /*   142     1 */

   	/* XXX 1 byte hole, try to pack */

   	__u32                      headers_start[0];     /*   144     0 */
   	__u8                       __pkt_type_offset[0]; /*   144     0 */
  -	__u8                       pkt_type:3;           /*   144: 5  1 */
  -	__u8                       ignore_df:1;          /*   144: 4  1 */
  -	__u8                       nf_trace:1;           /*   144: 3  1 */
  -	__u8                       ip_summed:2;          /*   144: 1  1 */
  -	__u8                       ooo_okay:1;           /*   144: 0  1 */
  -	__u8                       l4_hash:1;            /*   145: 7  1 */
  -	__u8                       sw_hash:1;            /*   145: 6  1 */
  -	__u8                       wifi_acked_valid:1;   /*   145: 5  1 */
  -	__u8                       wifi_acked:1;         /*   145: 4  1 */
  -	__u8                       no_fcs:1;             /*   145: 3  1 */
  -	__u8                       encapsulation:1;      /*   145: 2  1 */
  -	__u8                       encap_hdr_csum:1;     /*   145: 1  1 */
  -	__u8                       csum_valid:1;         /*   145: 0  1 */
  -	__u8                       csum_complete_sw:1;   /*   146: 7  1 */
  -	__u8                       csum_level:2;         /*   146: 5  1 */
  -	__u8                       csum_not_inet:1;      /*   146: 4  1 */
  -	__u8                       dst_pending_confirm:1; /*   146: 3  1 */
  -	__u8                       ndisc_nodetype:2;     /*   146: 1  1 */
  -	__u8                       ipvs_property:1;      /*   146: 0  1 */
  -	__u8                       inner_protocol_type:1; /*   147: 7  1 */
  -	__u8                       remcsum_offload:1;    /*   147: 6  1 */
  -	__u8                       offload_fwd_mark:1;   /*   147: 5  1 */
  -	__u8                       offload_mr_fwd_mark:1; /*   147: 4  1 */
  -	__u8                       tc_skip_classify:1;   /*   147: 3  1 */
  -	__u8                       tc_at_ingress:1;      /*   147: 2  1 */
  -	__u8                       tc_redirected:1;      /*   147: 1  1 */
  -	__u8                       tc_from_ingress:1;    /*   147: 0  1 */
  +	__u8                       pkt_type;             /*   144     1 */
  +	__u8                       ignore_df;            /*   144     1 */
  +	__u8                       nf_trace;             /*   144     1 */
  +	__u8                       ip_summed;            /*   144     1 */
  +	__u8                       ooo_okay;             /*   144     1 */
  +	__u8                       l4_hash;              /*   145     1 */
  +	__u8                       sw_hash;              /*   145     1 */
  +	__u8                       wifi_acked_valid;     /*   145     1 */
  +	__u8                       wifi_acked;           /*   145     1 */
  +	__u8                       no_fcs;               /*   145     1 */
  +	__u8                       encapsulation;        /*   145     1 */
  +	__u8                       encap_hdr_csum;       /*   145     1 */
  +	__u8                       csum_valid;           /*   145     1 */
  +	__u8                       csum_complete_sw;     /*   146     1 */
  +	__u8                       csum_level;           /*   146     1 */
  +	__u8                       csum_not_inet;        /*   146     1 */
  +	__u8                       dst_pending_confirm;  /*   146     1 */
  +	__u8                       ndisc_nodetype;       /*   146     1 */
  +	__u8                       ipvs_property;        /*   146     1 */
  +	__u8                       inner_protocol_type;  /*   147     1 */
  +	__u8                       remcsum_offload;      /*   147     1 */
  +	__u8                       offload_fwd_mark;     /*   147     1 */
  +	__u8                       offload_mr_fwd_mark;  /*   147     1 */
  +	__u8                       tc_skip_classify;     /*   147     1 */
  +	__u8                       tc_at_ingress;        /*   147     1 */
  +	__u8                       tc_redirected;        /*   147     1 */
  +	__u8                       tc_from_ingress;      /*   147     1 */
   	__u16                      tc_index;             /*   148     2 */

   	/* XXX 2 bytes hole, try to pack */
  $

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-20 15:23:35 -03:00
Arnaldo Carvalho de Melo 93d6d00165 dwarves: No need to print the "signed ", the name has it already
So avoid duplicating, i.e. "signed signed int" was being used.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-20 14:55:38 -03:00
Arnaldo Carvalho de Melo 0a9bac9a3e dwarves: Relookup when searching for signed base types
Sometimes we lookup "signed int" and fail, try again with just "int",
which is equivalent.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-20 14:53:50 -03:00
Arnaldo Carvalho de Melo a2cdc6c2a0 dutil: Adopt strstart() from the linux perf tools sources
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-20 14:52:25 -03:00
Yonghong Song 3aa3fd506e btf: add func_proto support
Two new btf kinds, BTF_KIND_FUNC and BTF_KIND_FUNC_PROTO,
have been added in kernel since
  https://patchwork.ozlabs.org/cover/1000176/
to support better func introspection.

Currently, for a DW_TAG_subroutine_type dwarf type,
a simple "void *" is generated instead of real subroutine type.

This patch teaches pahole to generate BTF_KIND_FUNC_PROTO
properly. After this patch, pahole should have complete
type coverage for C frontend with types a bpf program cares.

For example,
  $ cat t1.c
  typedef int __int32;
  struct t1 {
    int a1;
    int (*f1)(char p1, __int32 p2);
  } g1;
  $ cat t2.c
  typedef int __int32;
  struct t2 {
    int a2;
    int (*f2)(char q1, __int32 q2, ...);
    int (*f3)();
  } g2;
  int main() { return 0; }
  $ gcc -O2 -o t1 -g t1.c t2.c
  $ pahole -JV t1
  File t1:
  [1] TYPEDEF __int32 type_id=2
  [2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
  [3] STRUCT t1 kind_flag=0 size=16 vlen=2
        a1 type_id=2 bits_offset=0
        f1 type_id=6 bits_offset=64
  [4] FUNC_PROTO (anon) return=2 args=(5 (anon), 1 (anon))
  [5] INT char size=1 bit_offset=0 nr_bits=8 encoding=(none)
  [6] PTR (anon) type_id=4
  [7] TYPEDEF __int32 type_id=8
  [8] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
  [9] STRUCT t2 kind_flag=0 size=24 vlen=3
        a2 type_id=8 bits_offset=0
        f2 type_id=12 bits_offset=64
        f3 type_id=14 bits_offset=128
  [10] FUNC_PROTO (anon) return=8 args=(11 (anon), 7 (anon), vararg)
  [11] INT char size=1 bit_offset=0 nr_bits=8 encoding=(none)
  [12] PTR (anon) type_id=10
  [13] FUNC_PROTO (anon) return=8 args=(vararg)
  [14] PTR (anon) type_id=13
  $

In the above example, type [4], [10] and [13] represent the
func_proto types.

BTF_KIND_FUNC, which represents a real subprogram, is not generated in
this patch and will be considered later.

Signed-off-by: Yonghong Song <yhs@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-20 11:33:35 -03:00
Yonghong Song 8630ce4042 btf: fix struct/union/fwd types with kind_flag
This patch fixed two issues with BTF. One is related to struct/union
bitfield encoding and the other is related to forward type.

Issue #1 and solution:
======================

Current btf encoding of bitfield follows what pahole generates.
For each bitfield, pahole will duplicate the type chain and
put the bitfield size at the final int or enum type.
Since the BTF enum type cannot encode bit size,
commit b18354f64c ("btf: Generate correct struct bitfield
member types") workarounds the issue by generating
an int type whenever the enum bit size is not 32.

The above workaround is not ideal as we lost original type
in BTF. Another undesiable fact is the type duplication
as the pahole duplicates the type chain.

To fix this issue, this patch implemented a compatible
change for BTF struct type encoding:
  . the bit 31 of type->info, previously reserved,
    now is used to indicate whether bitfield_size is
    encoded in btf_member or not.
  . if bit 31 of struct_type->info is set,
    btf_member->offset will encode like:
      bit 0 - 23: bit offset
      bit 24 - 31: bitfield size
    if bit 31 is not set, the old behavior is preserved:
      bit 0 - 31: bit offset

So if the struct contains a bit field, the maximum bit offset
will be reduced to (2^24 - 1) instead of MAX_UINT. The maximum
bitfield size will be 255 which is enough for today as maximum
bitfield in compiler can be 128 where int128 type is supported.

A new global, no_bitfield_type_recode, is introduced and which
will be set to true if BTF encoding is enabled. This global
will prevent pahole duplicating the bitfield types to avoid
type duplication in BTF.

Issue #2 and solution:
======================

Current forward type in BTF does not specify whether the original
type is struct or union. This will not work for type pretty print
and BTF-to-header-file conversion as struct/union must be specified.

To fix this issue, similar to issue #1, type->info bit 31
is used. If the bit is set, it is union type. Otherwise, it is
a struct type.

Examples:
=========

  -bash-4.4$ cat t.c
  struct s;
  union u;
  typedef int ___int;
  enum A { A1, A2, A3 };
  struct t {
	  int a[5];
	  ___int b:4;
	  volatile enum A c:4;
	  struct s *p1;
	  union u *p2;
  } g;
  -bash-4.4$ gcc -c -O2 -g t.c

Without this patch:

  $ pahole -JV t.o
  [1] TYPEDEF ___int type_id=2
  [2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
  [3] ENUM A size=4 vlen=3
        A1 val=0
        A2 val=1
        A3 val=2
  [4] STRUCT t size=40 vlen=5
        a type_id=5 bits_offset=0
        b type_id=13 bits_offset=160
        c type_id=15 bits_offset=164
        p1 type_id=9 bits_offset=192
        p2 type_id=11 bits_offset=256
  [5] ARRAY (anon) type_id=2 index_type_id=2 nr_elems=5
  [6] INT sizetype size=8 bit_offset=0 nr_bits=64 encoding=(none)
  [7] VOLATILE (anon) type_id=3
  [8] FWD s type_id=0
  [9] PTR (anon) type_id=8
  [10] FWD u type_id=0
  [11] PTR (anon) type_id=10
  [12] INT int size=1 bit_offset=0 nr_bits=4 encoding=(none)
  [13] TYPEDEF ___int type_id=12
  [14] INT (anon) size=1 bit_offset=0 nr_bits=4 encoding=SIGNED
  [15] VOLATILE (anon) type_id=14

With this patch:

  $ pahole -JV t.o
  File t.o:
  [1] TYPEDEF ___int type_id=2
  [2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
  [3] ENUM A size=4 vlen=3
        A1 val=0
        A2 val=1
        A3 val=2
  [4] STRUCT t kind_flag=1 size=40 vlen=5
        a type_id=5 bitfield_size=0 bits_offset=0
        b type_id=1 bitfield_size=4 bits_offset=160
        c type_id=7 bitfield_size=4 bits_offset=164
        p1 type_id=9 bitfield_size=0 bits_offset=192
        p2 type_id=11 bitfield_size=0 bits_offset=256
  [5] ARRAY (anon) type_id=2 index_type_id=2 nr_elems=5
  [6] INT sizetype size=8 bit_offset=0 nr_bits=64 encoding=(none)
  [7] VOLATILE (anon) type_id=3
  [8] FWD s struct
  [9] PTR (anon) type_id=8
  [10] FWD u union
  [11] PTR (anon) type_id=10

The fix removed the type duplication, preserved the enum type for the
bitfield, and have correct struct/union information for the forward
type.

Signed-off-by: Yonghong Song <yhs@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-20 11:27:20 -03:00
Andrii Nakryiko 65bd17abc7 btf: Allow multiple cu's in dwarf->btf conversion
Currently, the pahole dwarf->btf conversion only supports one
compilation unit. This is not ideal since we would like using pahole to
generate BTF for vmlinux which has a lot of compilation units.

This patch added support to process multiple compilation units per ELF
file. Multiple ELF files are also supported properly.

The following is a demonstration example:
  -bash-4.4$ cat t1.c
  struct t1 {
    int a1;
  } g1;
  int main(void) { return 0; }
  -bash-4.4$ cat t2.c
  struct t2 {
    char a2;
  } g2;
  int main() { return 0; }
  -bash-4.4$ cat t3.c
  struct t3 {
    unsigned char a1:4;
  } g1;
  int main(void) { return 0; }
  -bash-4.4$ cat t4.c
  struct t4 {
    volatile char a4;
  } g2;
  int main() { return 0; }
  -bash-4.4$ gcc -O2 -o t1 -g t1.c t2.c
  -bash-4.4$ gcc -O2 -o t3 -g t3.c t4.c

Note that both the binary "t1" and "t3" have two compilation units in
their respective dwarf debug_info sections. The following is the pahole
verbose output for BTF conversion for these two binaries.

  -bash-4.4$ pahole -JV t1 t3
  File t1:
  [1] STRUCT t1 size=4 vlen=1
        a1 type_id=2 bits_offset=0
  [2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
  [3] STRUCT t2 size=1 vlen=1
        a2 type_id=4 bits_offset=0
  [4] INT char size=1 bit_offset=0 nr_bits=8 encoding=(none)
  [5] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED

  File t3:
  [1] STRUCT t3 size=1 vlen=1
        a1 type_id=3 bits_offset=0
  [2] INT unsigned char size=1 bit_offset=0 nr_bits=8 encoding=(none)
  [3] INT unsigned char size=1 bit_offset=0 nr_bits=4 encoding=(none)
  [4] INT (anon) size=4 bit_offset=0 nr_bits=32 encoding=(none)
  [5] STRUCT t4 size=1 vlen=1
        a4 type_id=6 bits_offset=0
  [6] VOLATILE (anon) type_id=7
  [7] INT char size=1 bit_offset=0 nr_bits=8 encoding=(none)
  [8] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Signed-off-by: Yonghong Song <yhs@fb.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-20 10:44:48 -03:00
Arnaldo Carvalho de Melo d843945ba5 pahole: Search for unions as well with '-C'
So that this now works:

  $ pahole -C kvm_mmu_page_role ../build/v4.20-rc5/arch/x86/kvm/kvm.o
  union kvm_mmu_page_role {
	  struct {
		  unsigned int       level:4;            /*     0:28  4 */
		  unsigned int       cr4_pae:1;          /*     0:27  4 */
		  unsigned int       quadrant:2;         /*     0:25  4 */
		  unsigned int       direct:1;           /*     0:24  4 */
		  unsigned int       access:3;           /*     0:21  4 */
		  unsigned int       invalid:1;          /*     0:20  4 */
		  unsigned int       nxe:1;              /*     0:19  4 */
		  unsigned int       cr0_wp:1;           /*     0:18  4 */
		  unsigned int       smep_andnot_wp:1;   /*     0:17  4 */
		  unsigned int       smap_andnot_wp:1;   /*     0:16  4 */
		  unsigned int       ad_disabled:1;      /*     0:15  4 */
		  unsigned int       guest_mode:1;       /*     0:14  4 */
		  unsigned int       smm:8;              /*     0: 0  4 */
	  };                                             /*     0     4 */
  };
  $

Suggested-by: Matthew Wilcox <willy@infradead.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-03 13:15:14 -03:00
Arnaldo Carvalho de Melo da632a3686 dwarves: Introduce {cu,cus}__find_struct_or_union_by_name() methods
Since tools like 'pahole' now shows unions in addition to structs.

Cc: Matthew Wilcox <willy@infradead.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-03 13:13:51 -03:00
Arnaldo Carvalho de Melo 31664d60ad pahole: Show tagged enums as well when no class is specified
The pahole tool initial goal was to show struct holes, which can't
happen with a first level of a tagged union (a union with a name),
so those only were displayed when part of a higher level struct.

Show the first level tagged enums as well, as this is useful when just
wanting to see its members.

E.g.:

  $ pahole ../build/v4.20-rc5/net/core/sock.o | grep ^union
  union fpregs_state {
  union irq_stack_union {
  union sigval {
  union __sifields {
  union thread_union {
  union kernfs_node_id {
  union flowi_uli {
  union ethtool_flow_union {
  union key_payload {
  union bpf_attr {
  union tcp_md5_addr {
  $

Suggested-by: Matthew Wilcox <willy@infradead.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-03 12:51:30 -03:00
Yonghong Song b18354f64c btf: Generate correct struct bitfield member types
For int types, the correct type size will be generated.  For enum types,
if the bit size is not 32, current BTF enum cannot represent it so a
signed int type will be generated.

For the following example:

  $ cat test.c
  enum A { A1, A2, A3 };
  struct t {
    enum A a:3;
    volatile enum A b:4;
  } g;
  $ gcc -c -g -O2 test.c

Without this patch, we will have:

  $ pahole -JV test.o
  [1] ENUM A size=4 vlen=3
        A1 val=0
        A2 val=1
        A3 val=2
  [2] STRUCT t size=4 vlen=2
        a type_id=4 bits_offset=0
        b type_id=6 bits_offset=3
  [3] VOLATILE (anon) type_id=1
  [4] ENUM A size=1 vlen=3
        A1 val=0
        A2 val=1
        A3 val=2
  [5] ENUM A size=1 vlen=3
        A1 val=0
        A2 val=1
        A3 val=2
  [6] VOLATILE (anon) type_id=5
  [7] INT (anon) size=4 bit_offset=0 nr_bits=32 encoding=(none)

There are two issues in the above. The struct "t" member "a" points to
type [4]. But the nr_bits is lost in type [4].

The same for type [5] which is for struct "t" member "b".

Since BTF ENUM type cannot encode nr_bits, this patch fixed the issue by
generating a BTF INT type if the ENUM type number of bits in pahole is
not 32.

With this patch, the incorrect member nr_bits issue is fixed as below:

  $ pahole -JV test.o
  [1] ENUM A size=4 vlen=3
        A1 val=0
        A2 val=1
        A3 val=2
  [2] STRUCT t size=4 vlen=2
        a type_id=4 bits_offset=0
        b type_id=6 bits_offset=3
  [3] VOLATILE (anon) type_id=1
  [4] INT (anon) size=1 bit_offset=0 nr_bits=3 encoding=SIGNED
  [5] INT (anon) size=1 bit_offset=0 nr_bits=4 encoding=SIGNED
  [6] VOLATILE (anon) type_id=5
  [7] INT (anon) size=4 bit_offset=0 nr_bits=32 encoding=(none)

Signed-off-by: Yonghong Song <yhs@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Cc: Alexei Starovoitov <ast@fb.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-12-03 12:04:46 -03:00
Arnaldo Carvalho de Melo 70ef8c7f07 dwarves_fprintf: Set conf.cachelinep in union__fprintf() too
union__fprintf() unconditionally uses conf.cachelinep, assuming there is
where the current cacheline is being kept, but if we call
union__fprintf() from something other than __class__fprintf(), then that
pointer is NULL, fix that.

Reported-by: Eric Blake <eblake@redhat.com>
Tested-by: Eric Blake <eblake@redhat.com>
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1633348
Fixes: e975ff247a ("dwarves_fprintf: Print cacheline boundaries in multiple union members")
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-10-03 10:38:44 -03:00
Arnaldo Carvalho de Melo bfdea37668 dwarves_fprintf: Print the scope of variables
E.g.:

$ pfunct -iVT ../build/v4.18.0+/kernel/sched/core.o  -f tg_cfs_schedulable_down
int tg_cfs_schedulable_down(struct task_group * tg, void * data);
{ /* low_pc=0x10340 */
	struct cfs_schedulable_data * d; /* scope: optimized */       //  6681
	struct cfs_bandwidth * cfs_b; /* scope: optimized */          //  6682
	s64 quota; /* scope: optimized */                             //  6683
	s64 parent_quota; /* scope: register */                       //  6683
	{
		struct cfs_bandwidth * parent_b; /* scope: optimized */ //  6688
		{
			bool branch; /* scope: optimized */           //  6698
			arch_static_branch(struct static_key * key,
						bool branch); /* size=30, low_pc=0x103a3 */ //  6698
		} /* lexblock size=0 */
		{
			s64 __UNIQUE_ID___x272; /* scope: optimized *///  6699
			s64 __UNIQUE_ID___y273; /* scope: optimized *///  6699
		} /* lexblock size=0 */
		normalize_cfs_quota(struct task_group * tg,
					struct cfs_schedulable_data * d); /* size=94, low_pc=0x10355 */ //  6690
	} /* lexblock size=0 */
}/* size: 240, variables: 4 */

This is part of an investigation on how to lookup the struct types associated
to registers in instructions with offsets from registers.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-09-26 16:45:25 -03:00
Arnaldo Carvalho de Melo 465110ec99 dwarves: Add the DWARF location to struct variable
This is DWARF specific, we don't have in CTF, AFAIK, info about where a
variable is put, i.e. in a register? in the stack? etc.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-09-26 16:45:25 -03:00
Arnaldo Carvalho de Melo c65f2cf436 dwarves: Rename variable->location to ->scope
We'll use location in the DWARF sense, i.e. location lists, etc, i.e.
where is this variable? In a register? The stack? etc.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-09-26 16:45:25 -03:00
Yonghong Song 0d2511fd1d btf: Fix bitfield encoding
The btf bitfield encoding is broken.

For the following example:

  -bash-4.2$ cat t.c
  struct t {
     int a:2;
     int b:1;
     int :3;
     int c:1;
     int d;
     char e:1;
     char f:1;
     int g;
  };
  void test(struct t *t) {
     return;
  }
  -bash-4.2$ clang -S -g -emit-llvm t.c

The output for bpf "little and big" endian results with pahole dwarf2btf
conversion:

  -bash-4.2$ llc -march=bpfel -mattr=dwarfris -filetype=obj t.ll
  -bash-4.2$ pahole -JV t.o
  [1] PTR (anon) type_id=2
  [2] STRUCT t size=16 vlen=7
        a type_id=5 bits_offset=30
        b type_id=6 bits_offset=29
        c type_id=6 bits_offset=25
        d type_id=3 bits_offset=32
        e type_id=7 bits_offset=71
        f type_id=7 bits_offset=70
        g type_id=3 bits_offset=96
  [3] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
  [4] INT char size=1 bit_offset=0 nr_bits=8 encoding=(none)
  [5] INT int size=1 bit_offset=0 nr_bits=2 encoding=(none)
  [6] INT int size=1 bit_offset=0 nr_bits=1 encoding=(none)
  [7] INT char size=1 bit_offset=0 nr_bits=1 encoding=(none)
  -bash-4.2$ llc -march=bpfeb -mattr=dwarfris -filetype=obj t.ll
  -bash-4.2$ pahole -JV t.o
  [1] PTR (anon) type_id=2
  [2] STRUCT t size=16 vlen=7
        a type_id=5 bits_offset=0
        b type_id=6 bits_offset=2
        c type_id=6 bits_offset=6
        d type_id=3 bits_offset=32
        e type_id=7 bits_offset=64
        f type_id=7 bits_offset=65
        g type_id=3 bits_offset=96
  [3] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
  [4] INT char size=1 bit_offset=0 nr_bits=8 encoding=(none)
  [5] INT int size=1 bit_offset=0 nr_bits=2 encoding=(none)
  [6] INT int size=1 bit_offset=0 nr_bits=1 encoding=(none)
  [7] INT char size=1 bit_offset=0 nr_bits=1 encoding=(none)

The BTF struct member bits_offset counts bits from the beginning of the
containing entity regardless of endianness, similar to what
DW_AT_bit_offset from DWARF4 does. Such counting is equivalent to the
big endian conversion in the above.

But the little endian conversion is not correct since dwarf generates
DW_AT_bit_offset based on actual bit position in the little endian
architecture.  For example, for the above struct member "a", the dwarf
would generate DW_AT_bit_offset=30 for little endian, and
DW_AT_bit_offset=0 for big endian.

This patch fixed the little endian structure member bits_offset problem
with proper calculation based on dwarf attributes.

With the fix, we get:

  -bash-4.2$ llc -march=bpfel -mattr=dwarfris -filetype=obj t.ll
  -bash-4.2$ pahole -JV t.o
    [1] STRUCT t size=16 vlen=7
        a type_id=5 bits_offset=0
        b type_id=6 bits_offset=2
        c type_id=6 bits_offset=6
        d type_id=2 bits_offset=32
        e type_id=7 bits_offset=64
        f type_id=7 bits_offset=65
        g type_id=2 bits_offset=96
    [2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
    [3] INT char size=1 bit_offset=0 nr_bits=8 encoding=(none)
    [4] PTR (anon) type_id=1
    [5] INT int size=1 bit_offset=0 nr_bits=2 encoding=(none)
    [6] INT int size=1 bit_offset=0 nr_bits=1 encoding=(none)
    [7] INT char size=1 bit_offset=0 nr_bits=1 encoding=(none)
  -bash-4.2$ llc -march=bpfeb -mattr=dwarfris -filetype=obj t.ll
  -bash-4.2$ pahole -JV t.o
  [1] PTR (anon) type_id=2
  [2] STRUCT t size=16 vlen=7
        a type_id=5 bits_offset=0
        b type_id=6 bits_offset=2
        c type_id=6 bits_offset=6
        d type_id=3 bits_offset=32
        e type_id=7 bits_offset=64
        f type_id=7 bits_offset=65
        g type_id=3 bits_offset=96
  [3] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
  [4] INT char size=1 bit_offset=0 nr_bits=8 encoding=(none)
  [5] INT int size=1 bit_offset=0 nr_bits=2 encoding=(none)
  [6] INT int size=1 bit_offset=0 nr_bits=1 encoding=(none)
  [7] INT char size=1 bit_offset=0 nr_bits=1 encoding=(none)
  -bash-4.2$

For both little endian and big endian, we have correct and
same bits_offset for struct members.

We could fix pos->bit_offset, but pos->bit_offset will be inconsistent
to pos->bitfield_offset in the meaning and pos->bitfield_offset is used
to print out pahole data structure:

  -bash-4.2$ llc -march=bpfel -mattr=dwarfris -filetype=obj t.ll
  -bash-4.2$ /bin/pahole t.o
  struct t {
        int                        a:2;                  /*     0:30  4 */
        int                        b:1;                  /*     0:29  4 */
        int                        c:1;                  /*     0:25  4 */
  .....

So this patch just made the change in btf specific routines.

Signed-off-by: Yonghong Song <yhs@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Cc: Alexei Starovoitov <ast@fb.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-09-17 11:44:58 -03:00
Arnaldo Carvalho de Melo 92417082aa MANIFEST: Add missing COPYING file
That wasn't going into the tarballs generated when releasing new
versions.

Reported-by: Michal Schmidt <mschmidt@redhat.com>
Cc: Clark Williams <williams@redhat.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-09-11 11:22:41 -03:00
Yonghong Song eb6bd05766 dwarf_loader: Process DW_AT_count in DW_TAG_subrange_type
For array type, gcc and clang generates dwarf info with different tags.  For
example, with existing pahole,

  $ cat test.c
    int a[5][5];
  $ gcc -c -g test.c
  $ llvm-dwarfdump test.o
    ...
    0x0000001d:   DW_TAG_array_type
                  DW_AT_type    (0x0000003a "int")
                  DW_AT_sibling (0x00000033)

    0x00000026:     DW_TAG_subrange_type
                      DW_AT_type        (0x00000033 "long unsigned int")
                      DW_AT_upper_bound (0x04)

    0x0000002c:     DW_TAG_subrange_type
                      DW_AT_type        (0x00000033 "long unsigned int")
                      DW_AT_upper_bound (0x04)
  $ pahole -JV test.o
    [1] ARRAY (anon) type_id=3 index_type_id=3 nr_elems=25
    [2] INT long unsigned int size=8 bit_offset=0 nr_bits=64 encoding=(none)
    [3] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
  $ clang -c -g test.c
  $ llvm-dwarfdump test.o
    ...
    0x00000033:   DW_TAG_array_type
                    DW_AT_type  (0x00000045 "int")

    0x00000038:     DW_TAG_subrange_type
                      DW_AT_type        (0x0000004c "__ARRAY_SIZE_TYPE__")
                      DW_AT_count       (0x05)

    0x0000003e:     DW_TAG_subrange_type
                      DW_AT_type        (0x0000004c "__ARRAY_SIZE_TYPE__")
                      DW_AT_count       (0x05)
  $ pahole -JV test.o
    [1] ARRAY (anon) type_id=2 index_type_id=2 nr_elems=0
    [2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
    [3] INT __ARRAY_SIZE_TYPE__ size=8 bit_offset=0 nr_bits=64 encoding=(none)

Current pahole processed DW_AT_upper_bound under DW_TAG_subrange_type to
get array range, but it did not process DW_AT_count so during pahole
dwarf2btf conversion, the flattened array size is 0.

This patch fixed the issue by processing DW_AT_count properly.
With the change, for clang generated test.o, pahole btf conversion output is:
  $ pahole -JV test.o
    [1] ARRAY (anon) type_id=2 index_type_id=2 nr_elems=25
    [2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
    [3] INT __ARRAY_SIZE_TYPE__ size=8 bit_offset=0 nr_bits=64 encoding=(none)

Committer testing:

Before:

  # pahole -C augmented_enter_connect_args augmented_syscalls.bpf.o
  struct augmented_enter_connect_args {
          struct syscall_enter_connect_args args;          /*     0    40 */
          char                       addr[0];              /*    40     0 */

          /* size: 56, cachelines: 1, members: 2 */
          /* padding: 16 */
          /* last cacheline: 56 bytes */
  };
  # file augmented_syscalls.bpf.o
  augmented_syscalls.bpf.o: ELF 64-bit LSB relocatable, *unknown arch 0xf7* version 1 (SYSV), with debug_info, not stripped
  #

After:

  # pahole -C augmented_enter_connect_args augmented_syscalls.bpf.o
  struct augmented_enter_connect_args {
	  struct syscall_enter_connect_args args;          /*     0    40 */
	  char                       addr[14];             /*    40    14 */

	  /* size: 56, cachelines: 1, members: 2 */
	  /* padding: 2 */
	  /* last cacheline: 56 bytes */
  };
  #

Signed-off-by: Yonghong Song <yhs@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: Okash Khawaja <osk@fb.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-08-28 12:40:10 -03:00
Arnaldo Carvalho de Melo 4a21c5c8db v1.12 - New Release
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-08-16 16:15:27 -03:00
Arnaldo Carvalho de Melo 1ca2e351df README.btf: Add section on validating the .BTF section via the kernel
Run 'perf ftrace' to show *btf* functions called to load, validate and
put in place data structures with the .BTF ELF section contents.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-08-16 12:05:29 -03:00
Arnaldo Carvalho de Melo 9eda5e8163 README.btf: No need to use 'llvm.opts = -mattr=dwarfris' with elfutils >= 0.173
Updated elfutils to 0.173, using the fedora 28 packages and, as noted in
https://github.com/cilium/cilium/pull/5106/files ["bpf, doc: further
improvements on the BTF related section #5106"] there is no need to pass
the '-mattr=dwarfris' to llc to have DWARF sections correctly parsed by
tools like pahole.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-08-16 10:50:29 -03:00
Arnaldo Carvalho de Melo 7818af53f6 dwarves: Add a README.btf file with steps to test the BTF encoder
Using perf's integration to ease the whole process.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-08-15 17:43:43 -03:00
Arnaldo Carvalho de Melo f727c22191 dwarf_loader: Initial support for DW_TAG_partial_unit
This allows processing DW_TAG_partial_unit sections, which gets us from
no tags processed in files contained such tags to at least showing the
tags present in those sections.

Further work is required to support DW_TAG_compile_unit sections using
DW_TAG_imported_unit to import those DW_TAG_partial_unit sections, which
will be done by basically readding the contents of the
DW_TAG_partial_unit sections to the DW_TAG_compile_unit sections
importing them and then recoding as if all the tags in the partial units
were in the compile units.

This will make sure we have a contiguous series of types used in a
compile unit so that the converting routines to CTF and BTF can work
just as before.

On a fedora 27 system:

Before:

  $ pahole /usr/lib/debug/usr/lib64/libgtk-3.so.0.2200.19.debug
  die__process: DW_TAG_compile_unit or DW_TAG_type_unit expected got partial_unit!
  $

After:

  $ pahole /usr/lib/debug/usr/lib64/libgtk-3.so.0.2200.19.debug
  struct _GTimeVal {
          glong                      tv_sec;         /*     0     8 */
          glong                      tv_usec;        /*     8     8 */

          /* size: 16, cachelines: 1, members: 2 */
          /* last cacheline: 16 bytes */
  };
  struct _GError {
          GQuark                     domain;         /*     0     4 */
          gint                       code;           /*     4     4 */
          gchar *                    message;        /*     8     8 */

          /* size: 16, cachelines: 1, members: 3 */
          /* last cacheline: 16 bytes */
  };
  struct _GCond {
          gpointer                   p;              /*     0     8 */
          guint                      i[2];           /*     8     8 */

          /* size: 16, cachelines: 1, members: 2 */
          /* last cacheline: 16 bytes */
  };
<SNIP some more structs found in DW_TAG_partial unit sections...>
  struct _GSourceFuncs {
          gboolean                   (*prepare)(GSource *, gint *); /*     0     8 */
          gboolean                   (*check)(GSource *);  /*     8     8 */
          gboolean                   (*dispatch)(GSource *, GSourceFunc, gpointer); /*    16     8 */
          void                       (*finalize)(GSource *); /*    24     8 */
          GSourceFunc                closure_callback;     /*    32     8 */
          GSourceDummyMarshal        closure_marshal;      /*    40     8 */

          /* size: 48, cachelines: 1, members: 6 */
          /* last cacheline: 48 bytes */
  };
  struct _GThreadFunctions {
          GMutex *                   (*mutex_new)(void);   /*     0     8 */
          void                       (*mutex_lock)(GMutex *); /*     8     8 */
          gboolean                   (*mutex_trylock)(GMutex *)tag__recode_dwarf_type: couldn't find 0x74 type for 0x7fc (typedef)!
  tag__recode_dwarf_type: couldn't find 0x7e type for 0x829 (pointer_type)!
  tag__recode_dwarf_type: couldn't find 0x829 type for 0x844 (variable)!
  tag__recode_dwarf_type: couldn't find 0x7e type for 0x850 (variable)!
  tag__recode_dwarf_type: couldn't find 0x22 type for 0x85b (variable)!
  tag__recode_dwarf_type: couldn't find 0x22 type for 0x866 (variable)!
  tag__recode_dwarf_type: couldn't find 0x22 type for 0x871 (variable)!
  namespace__recode_dwarf_types: couldn't find 0x7fc type for 0x8a4 (member)!
  tag__recode_dwarf_type: couldn't find 0xfa type for 0x8e8 (volatile_type)!
  namespace__recode_dwarf_types: couldn't find 0x8b2 type for 0x90d (member)!
  tag__recode_dwarf_type: couldn't find 0x1b type for 0x941 (typedef)!
<SNIP>
  $

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-08-13 16:07:23 -03:00
Arnaldo Carvalho de Melo e975ff247a dwarves_fprintf: Print cacheline boundaries in multiple union members
In 'struct audit_context' we have an union that have member structs that
straddles cacheline boundaries, the existing logic was showing those
cacheline boundaries only for the first struct in the union where that
straddling took place, all the subsequent structs where straddling also
takes place were not showing it, the struct:

struct audit_context {
<SNIP>
	union {
		struct {
			int        nargs;                /*   824     4 */

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

			/* --- cacheline 13 boundary (832 bytes) --- */
			long int   args[6];              /*   832    48 */
		} socketcall;                            /*   824    56 */
		struct {
			kuid_t     uid;                  /*   824     4 */
			kgid_t     gid;                  /*   828     4 */
			umode_t    mode;                 /*   832     2 */

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

			u32        osid;                 /*   836     4 */
			int        has_perm;             /*   840     4 */
			uid_t      perm_uid;             /*   844     4 */
			gid_t      perm_gid;             /*   848     4 */
			umode_t    perm_mode;            /*   852     2 */

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

			long unsigned int qbytes;        /*   856     8 */
		} ipc;                                   /*   824    40 */
		struct {
			mqd_t      mqdes;                /*   824     4 */

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

			struct mq_attr mqstat;           /*   832    64 */
		} mq_getsetattr;                         /*   824    72 */
		struct {
			mqd_t      mqdes;                /*   824     4 */
			int        sigev_signo;          /*   828     4 */
		} mq_notify;                             /*   824     8 */
		struct {
			mqd_t      mqdes;                /*   824     4 */

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

			size_t     msg_len;              /*   832     8 */
			unsigned int msg_prio;           /*   840     4 */

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

			struct timespec64 abs_timeout;   /*   848    16 */
		} mq_sendrecv;                           /*   824    40 */
		struct {
			int        oflag;                /*   824     4 */
			umode_t    mode;                 /*   828     2 */

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

			struct mq_attr attr;             /*   832    64 */
		} mq_open;                               /*   824    72 */
		struct {
			pid_t      pid;                  /*   824     4 */
			struct audit_cap_data cap;       /*   828    32 */
		} capset;                                /*   824    36 */
		struct {
			int        fd;                   /*   824     4 */
			int        flags;                /*   828     4 */
		} mmap;                                  /*   824     8 */
		struct {
			int        argc;                 /*   824     4 */
		} execve;                                /*   824     4 */
		struct {
			char *     name;                 /*   824     8 */
		} module;                                /*   824     8 */
	};                                               /*   824    72 */
	/* --- cacheline 14 boundary (896 bytes) --- */
	int                        fds[2];               /*   896     8 */
	struct audit_proctitle     proctitle;            /*   904    16 */

	/* size: 920, cachelines: 15, members: 46 */
	/* sum members: 912, holes: 2, sum holes: 8 */
	/* last cacheline: 24 bytes */
};

With this fix:

struct audit_context {
<SNIP>
	union {
		struct {
			int        nargs;                /*   824     4 */

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

			/* --- cacheline 13 boundary (832 bytes) --- */
			long int   args[6];              /*   832    48 */
		} socketcall;                            /*   824    56 */
		struct {
			kuid_t     uid;                  /*   824     4 */
			kgid_t     gid;                  /*   828     4 */
			/* --- cacheline 13 boundary (832 bytes) --- */
			umode_t    mode;                 /*   832     2 */

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

			u32        osid;                 /*   836     4 */
			int        has_perm;             /*   840     4 */
			uid_t      perm_uid;             /*   844     4 */
			gid_t      perm_gid;             /*   848     4 */
			umode_t    perm_mode;            /*   852     2 */

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

			long unsigned int qbytes;        /*   856     8 */
		} ipc;                                   /*   824    40 */
		struct {
			mqd_t      mqdes;                /*   824     4 */

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

			/* --- cacheline 13 boundary (832 bytes) --- */
			struct mq_attr mqstat;           /*   832    64 */
		} mq_getsetattr;                         /*   824    72 */
		struct {
			mqd_t      mqdes;                /*   824     4 */
			int        sigev_signo;          /*   828     4 */
		} mq_notify;                             /*   824     8 */
		struct {
			mqd_t      mqdes;                /*   824     4 */

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

			/* --- cacheline 13 boundary (832 bytes) --- */
			size_t     msg_len;              /*   832     8 */
			unsigned int msg_prio;           /*   840     4 */

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

			struct timespec64 abs_timeout;   /*   848    16 */
		} mq_sendrecv;                           /*   824    40 */
		struct {
			int        oflag;                /*   824     4 */
			umode_t    mode;                 /*   828     2 */

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

			/* --- cacheline 13 boundary (832 bytes) --- */
			struct mq_attr attr;             /*   832    64 */
		} mq_open;                               /*   824    72 */
		struct {
			pid_t      pid;                  /*   824     4 */
			struct audit_cap_data cap;       /*   828    32 */
		} capset;                                /*   824    36 */
		struct {
			int        fd;                   /*   824     4 */
			int        flags;                /*   828     4 */
		} mmap;                                  /*   824     8 */
		struct {
			int        argc;                 /*   824     4 */
		} execve;                                /*   824     4 */
		struct {
			char *     name;                 /*   824     8 */
		} module;                                /*   824     8 */
	};                                               /*   824    72 */
	/* --- cacheline 14 boundary (896 bytes) --- */
	int                        fds[2];               /*   896     8 */
	struct audit_proctitle     proctitle;            /*   904    16 */

	/* size: 920, cachelines: 15, members: 46 */
	/* sum members: 912, holes: 2, sum holes: 8 */
	/* last cacheline: 24 bytes */
};

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-07-28 14:25:30 -03:00
Martin KaFai Lau 68645f7fac btf: Add BTF support
This patch introduces BPF Type Format (BTF).

BTF (BPF Type Format) is the meta data format which describes
the data types of BPF program/map.  Hence, it basically focus
on the C programming language which the modern BPF is primary
using.  The first use case is to provide a generic pretty print
capability for a BPF map.

Signed-off-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-07-25 14:42:06 -03:00
Arnaldo Carvalho de Melo 81466af0d4 pahole: Show the file where a struct was used
To help with using just that object file, avoiding processing big files
such as vmlinux, e.g.:

  $ pahole -I vmlinux
<SNIP>
  /* Used at: /home/acme/git/perf/init/main.c */
  /* <1f4a5> /home/acme/git/perf/arch/x86/include/asm/orc_types.h:85 */
  struct orc_entry {
          s16                        sp_offset;            /*     0     2 */
          s16                        bp_offset;            /*     2     2 */
          unsigned int               sp_reg:4;             /*     4:28  4 */
          unsigned int               bp_reg:4;             /*     4:24  4 */
          unsigned int               type:2;               /*     4:22  4 */

          /* size: 6, cachelines: 1, members: 5 */
          /* padding: 65534 */
          /* bit_padding: 22 bits */
          /* last cacheline: 6 bytes */

          /* BRAIN FART ALERT! 6 != 8 + 0(holes), diff = -2 */
  };
<SNIP>

So I noticed that BFA, need to work on it, to make the testing process
faster, better not process vmlinux.o, instead, do:

  $ pahole -C orc_entry ${kernel_build_dir}/init/main.o

Much faster, as main.o is much smaller than the vmlinux file.

Now to fix the processing of 'struct orc_entry'.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2017-12-15 15:30:38 -03:00
Arnaldo Carvalho de Melo 2dd87be78b dwarves_fprintf: Show offsets at union members
In complex structs with multiple complex unions figuring out the offset
for a given union member is difficult, as one needs to figure out the
union, go to the end of it to see the offset.

So just turn struct_member__fprintf() into class_member__fprintf() and
pass a 'union_member' boolean to share all the aspects of struct and
union members, just not advancing the offset when processing union
members.

This way, for instance, the Linux kernel's 'struct page' goes from:

struct page {
	long unsigned int          flags;                /*     0     8 */
	union {
		struct address_space * mapping;          /*     8     8 */
		void *             s_mem;                /*     8     8 */
		atomic_t           compound_mapcount;    /*     8     4 */
	};                                               /*     8     8 */
	union {
		long unsigned int  index;                /*    16     8 */
		void *             freelist;             /*    16     8 */
	};                                               /*    16     8 */
	union {
		long unsigned int  counters;             /*    24     8 */
		struct {
			union {
				atomic_t _mapcount;      /*    24     4 */
				unsigned int active;     /*    24     4 */
				struct {
					unsigned int inuse:16; /*    24:16  4 */
					unsigned int objects:15; /*    24: 1  4 */
					unsigned int frozen:1; /*    24: 0  4 */
				};                       /*    24     4 */
				int units;               /*    24     4 */
			};                               /*    24     4 */
			atomic_t   _refcount;            /*    28     4 */
		};                                       /*    24     8 */
	};                                               /*    24     8 */
	union {
		struct list_head   lru;                  /*    32    16 */
		struct dev_pagemap * pgmap;              /*    32     8 */
		struct {
			struct page * next;              /*    32     8 */
			int        pages;                /*    40     4 */
			int        pobjects;             /*    44     4 */
		};                                       /*    32    16 */
		struct callback_head callback_head;      /*    32    16 */
		struct {
			long unsigned int compound_head; /*    32     8 */
			unsigned int compound_dtor;      /*    40     4 */
			unsigned int compound_order;     /*    44     4 */
		};                                       /*    32    16 */
		struct {
			long unsigned int __pad;         /*    32     8 */
			pgtable_t  pmd_huge_pte;         /*    40     8 */
		};                                       /*    32    16 */
	};                                               /*    32    16 */
	union {
		long unsigned int  private;              /*    48     8 */
		spinlock_t         ptl;                  /*    48     4 */
		struct kmem_cache * slab_cache;          /*    48     8 */
	};                                               /*    48     8 */
	struct mem_cgroup *        mem_cgroup;           /*    56     8 */

	/* size: 64, cachelines: 1, members: 7 */
};

To:

struct page {
	long unsigned int          flags;                /*     0     8 */
	union {
		struct address_space * mapping;          /*     8     8 */
		void *             s_mem;                /*     8     8 */
		atomic_t           compound_mapcount;    /*     8     4 */
	};                                               /*     8     8 */
	union {
		long unsigned int  index;                /*    16     8 */
		void *             freelist;             /*    16     8 */
	};                                               /*    16     8 */
	union {
		long unsigned int  counters;             /*    24     8 */
		struct {
			union {
				atomic_t _mapcount;      /*    24     4 */
				unsigned int active;     /*    24     4 */
				struct {
					unsigned int inuse:16; /*    24:16  4 */
					unsigned int objects:15; /*    24: 1  4 */
					unsigned int frozen:1; /*    24: 0  4 */
				};                       /*    24     4 */
				int units;               /*    24     4 */
			};                               /*    24     4 */
			atomic_t   _refcount;            /*    28     4 */
		};                                       /*    24     8 */
	};                                               /*    24     8 */
	union {
		struct list_head   lru;                  /*    32    16 */
		struct dev_pagemap * pgmap;              /*    32     8 */
		struct {
			struct page * next;              /*    32     8 */
			int        pages;                /*    40     4 */
			int        pobjects;             /*    44     4 */
		};                                       /*    32    16 */
		struct callback_head callback_head;      /*    32    16 */
		struct {
			long unsigned int compound_head; /*    32     8 */
			unsigned int compound_dtor;      /*    40     4 */
			unsigned int compound_order;     /*    44     4 */
		};                                       /*    32    16 */
		struct {
			long unsigned int __pad;         /*    32     8 */
			pgtable_t  pmd_huge_pte;         /*    40     8 */
		};                                       /*    32    16 */
	};                                               /*    32    16 */
	union {
		long unsigned int  private;              /*    48     8 */
		spinlock_t         ptl;                  /*    48     4 */
		struct kmem_cache * slab_cache;          /*    48     8 */
	};                                               /*    48     8 */
	struct mem_cgroup *        mem_cgroup;           /*    56     8 */

	/* size: 64, cachelines: 1, members: 7 */
};

Suggested-by: Matthew Wilcox <willy@infradead.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2017-12-15 13:33:10 -03:00