Commit Graph

331 Commits

Author SHA1 Message Date
Andrii Nakryiko 8ce85a1ad7 reorganize: Use class__find_holes() to recalculate holes
Instead of relying on error-prone adjustment of bit/byte holes, use
class__find_holes() to re-calculate them after members are moved around.

As part of that change, fix bug with not adjusting bit_offset, when
changing byte_offset.

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-03 18:10:15 -03:00
Andrii Nakryiko 5d1c4029bd dwarves: Fix classification of byte/bit hole for aligned bitfield
This patch fixes a bug in class__find_holes() with determining byte hole
as a bit hole in case where previous member is not bitfield, but current
one is aligned bitfield. See example below, notice hole classification
hw_stopped field..

  $ cat test/bit_test.c
  struct s {
          long unused: 62;
          /* 2 bit hole */
          int hw_stopped;
          /* 4 byte hole */
          long unused2: 55;
          /* 9 bit padding */
  };

  int main() {
          static struct s s;
          return 0;
  }

  $ clang -g test/bit_test.c -o test/bit_test

  $ pahole -JV test/bit_test
  File test/bit_test:
  [1] STRUCT s kind_flag=1 size=24 vlen=3
          unused type_id=2 bitfield_size=62 bits_offset=0
          hw_stopped type_id=3 bitfield_size=0 bits_offset=64
          unused2 type_id=2 bitfield_size=55 bits_offset=128
  [2] INT long int size=8 bit_offset=0 nr_bits=64 encoding=SIGNED
  [3] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED

BEFORE:

  $ pahole -F btf test/bit_test
  struct s {
          long int                   unused:62;            /*     0: 0  8 */

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

          int                        hw_stopped;           /*     8     4 */

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

          long int                   unused2:55;           /*    16: 0  8 */

          /* size: 24, cachelines: 1, members: 3 */
          /* sum members: 4 */
          /* sum bitfield members: 117 bits, bit holes: 2, sum bit holes: 34 bits */
          /* bit_padding: 9 bits */
          /* last cacheline: 24 bytes */
  };

AFTER:

  $ pahole -F btf test/bit_test
  struct s {
          long int                   unused:62;            /*     0: 0  8 */

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

          int                        hw_stopped;           /*     8     4 */

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

          long int                   unused2:55;           /*    16: 0  8 */

          /* size: 24, cachelines: 1, members: 3 */
          /* sum members: 4, holes: 1, sum holes: 4 */
          /* sum bitfield members: 117 bits, bit holes: 1, sum bit holes: 2 bits */
          /* bit_padding: 9 bits */
          /* last cacheline: 24 bytes */
  };

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-03 10:37:03 -03:00
Andrii Nakryiko 78c110a7ea dwarves: Revert semantics of member bit/byte hole
pahole --reorganize heavily depends on member's bit_hole and hole fields
to denote bit/byte holes *after* member. Previous commit "dwarves: use
bit sizes and bit/byte hole info in __class__fprintf" changed its
meaning to bit/byte hole *before* member to accomodate possible bit/byte
holes at the beginning of a struct. This change broke reorganization
algorithm, though, which is quite involved and isn't trivially
modifiable to accomodate new semantics.

This patch reverts the meaning of bit_hole and hole, but also introduces
per class pre_bit_hole/pre_hole to record initial bit/byte hole of a
struct. This allows to fix reorg code more easily and still handle
initial holes cases, if at the expense of being not as elegant.

Committer testing:

  $ time pahole -F btf --packable vmlinux | sort -nr -k4 | head
  bts_ctx     12288 8192 4096
  swsusp_info  4096  432 3664
  vc_data       792  496  296
  pci_dev      2488 2320  168
  rcu_state    3392 3240  152
  ptr_ring      192   40  152
  xdp_sock      960  840  120
  zone         1664 1552  112
  rcu_data      576  472  104
  rcu_node      576  480   96

  real	0m0.038s
  user	0m0.029s
  sys	0m0.017s
  $

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Reported-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-03 10:09:33 -03:00
Andrii Nakryiko c0fdc5e685 dwarf_loader: Use DWARF recommended uniform bit offset scheme
Use uniform bit offset scheme as described in DWARF standard (though
apparently not really followed by major compilers), in which bit offset
is a natural extension of byte offset in both big- and little-endian
architectures.

BEFORE:

1. Bit offsets for little-endian are output as offsets from highest-order bit
of underlying int to highest-order bit of bitfield, so double-backwards for
little-endian arch and counter to how byte offsets are used, which point to
lowest-order bit of underlying type. This makes first bitfield to have bit
offset 27, instead of natural 0.

2. Bit offsets for big-endian are output as expected, by referencing
highest-order bit offset from highest-order bit of underlying int. This is
natural for big-endian platform, e.g., first bitfield has bit offset of 0.

3. Big-endian target also has problem with determining bit holes, because bit
positions have to be calculated differently for little- and big-endian
platforms and previous commit changed pahole logic to follow little-endian
semantics.

4. BTF encoder outputs uniform bit offset for both little- and big-endian
format (following DWARF's recommended bit offset scheme)

5. BTF loader, though, follows DWARF loader's format and outputs little-endian
bit offsets "double-backwards".

  $ gcc -g dwarf_test.c -o dwarf_test
  $ pahole -F dwarf dwarf_test
  struct S {
          int                        j:5;                  /*     0:27  4 */
          int                        k:6;                  /*     0:21  4 */
          int                        m:5;                  /*     0:16  4 */
          int                        n:8;                  /*     0: 8  4 */

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

  $ pahole -JV dwarf_test
  File dwarf_test:
  [1] STRUCT S kind_flag=1 size=4 vlen=4
          j type_id=2 bitfield_size=5 bits_offset=0
          k type_id=2 bitfield_size=6 bits_offset=5
          m type_id=2 bitfield_size=5 bits_offset=11
          n type_id=2 bitfield_size=8 bits_offset=16
  [2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED

  $ pahole -F btf dwarf_test
  struct S {
          int                        j:5;                  /*     0:27  4 */
          int                        k:6;                  /*     0:21  4 */
          int                        m:5;                  /*     0:16  4 */
          int                        n:8;                  /*     0: 8  4 */

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

  $ aarch64-linux-gnu-gcc -mbig-endian -g -c dwarf_test.c -o dwarf_test.be
  $ pahole -F dwarf dwarf_test.be
  struct S {

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

          int                        j:5;                  /*     0: 0  4 */

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

          int                        k:6;                  /*     0: 5  4 */

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

          int                        m:5;                  /*     0:11  4 */

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

          int                        n:8;                  /*     0:16  4 */

          /* size: 4, cachelines: 1, members: 4 */
          /* bit holes: 4, sum bit holes: 760 bits */
          /* bit_padding: 16 bits */
          /* last cacheline: 4 bytes */

          /* BRAIN FART ALERT! 4 bytes != 24 (member bits) + 0 (byte holes) + 760 (bit holes), diff = -768 bits */
  };

  $ pahole -JV dwarf_test.be
  File dwarf_test.be:
  [1] STRUCT S kind_flag=1 size=4 vlen=4
          j type_id=2 bitfield_size=5 bits_offset=0
          k type_id=2 bitfield_size=6 bits_offset=5
          m type_id=2 bitfield_size=5 bits_offset=11
          n type_id=2 bitfield_size=8 bits_offset=16
  [2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED

  $ pahole -F btf dwarf_test.be
  struct S {

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

          int                        j:5;                  /*     0: 0  4 */

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

          int                        k:6;                  /*     0: 5  4 */

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

          int                        m:5;                  /*     0:11  4 */

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

          int                        n:8;                  /*     0:16  4 */

          /* size: 4, cachelines: 1, members: 4 */
          /* bit holes: 4, sum bit holes: 760 bits */
          /* bit_padding: 16 bits */
          /* last cacheline: 4 bytes */

          /* BRAIN FART ALERT! 4 bytes != 24 (member bits) + 0 (byte holes) + 760 (bit holes), diff = -768 bits */
  };

AFTER:

1. Same output for little- and big-endian binaries, both for BTF and DWARF
loader.

2. For little-endian target, bit offsets are natural extensions of byte offset,
counting from lowest-order bit of underlying int to lowest-order bit of a
bitfield.

3. BTF encoder still emits correct and natural bit offsets (for both binaries).

4. No more BRAIN FART ALERTs for big-endian.

  $ pahole -F dwarf dwarf_test
  struct S {
          int                        j:5;                  /*     0: 0  4 */
          int                        k:6;                  /*     0: 5  4 */
          int                        m:5;                  /*     0:11  4 */
          int                        n:8;                  /*     0:16  4 */

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

  $ pahole -JV dwarf_test
  File dwarf_test:
  [1] STRUCT S kind_flag=1 size=4 vlen=4
          j type_id=2 bitfield_size=5 bits_offset=0
          k type_id=2 bitfield_size=6 bits_offset=5
          m type_id=2 bitfield_size=5 bits_offset=11
          n type_id=2 bitfield_size=8 bits_offset=16
  [2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED

  $ pahole -F btf dwarf_test
  struct S {
          int                        j:5;                  /*     0: 0  4 */
          int                        k:6;                  /*     0: 5  4 */
          int                        m:5;                  /*     0:11  4 */
          int                        n:8;                  /*     0:16  4 */

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

  $ pahole -F dwarf dwarf_test.be
  struct S {
          int                        j:5;                  /*     0: 0  4 */
          int                        k:6;                  /*     0: 5  4 */
          int                        m:5;                  /*     0:11  4 */
          int                        n:8;                  /*     0:16  4 */

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

  $ pahole -JV dwarf_test.be
  File dwarf_test.be:
  [1] STRUCT S kind_flag=1 size=4 vlen=4
          j type_id=2 bitfield_size=5 bits_offset=0
          k type_id=2 bitfield_size=6 bits_offset=5
          m type_id=2 bitfield_size=5 bits_offset=11
          n type_id=2 bitfield_size=8 bits_offset=16
  [2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED

  $ pahole -F btf dwarf_test.be
  struct S {
          int                        j:5;                  /*     0: 0  4 */
          int                        k:6;                  /*     0: 5  4 */
          int                        m:5;                  /*     0:11  4 */
          int                        n:8;                  /*     0:16  4 */

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

FOR REFERENCE. Relevant parts of DWARF output from GCC (clang outputs exactly
the same data) for both little- and big-endian binaries:

  $ readelf -wi dwarf_test
  Contents of the .debug_info section:
  <snip>
   <1><2d>: Abbrev Number: 2 (DW_TAG_structure_type)
      <2e>   DW_AT_name        : S
      <30>   DW_AT_byte_size   : 4
      <31>   DW_AT_decl_file   : 1
      <32>   DW_AT_decl_line   : 1
      <33>   DW_AT_decl_column : 8
      <34>   DW_AT_sibling     : <0x71>
   <2><38>: Abbrev Number: 3 (DW_TAG_member)
      <39>   DW_AT_name        : j
      <3b>   DW_AT_decl_file   : 1
      <3c>   DW_AT_decl_line   : 2
      <3d>   DW_AT_decl_column : 6
      <3e>   DW_AT_type        : <0x71>
      <42>   DW_AT_byte_size   : 4
      <43>   DW_AT_bit_size    : 5
      <44>   DW_AT_bit_offset  : 27
      <45>   DW_AT_data_member_location: 0
   <2><46>: Abbrev Number: 3 (DW_TAG_member)
      <47>   DW_AT_name        : k
      <49>   DW_AT_decl_file   : 1
      <4a>   DW_AT_decl_line   : 3
      <4b>   DW_AT_decl_column : 6
      <4c>   DW_AT_type        : <0x71>
      <50>   DW_AT_byte_size   : 4
      <51>   DW_AT_bit_size    : 6
      <52>   DW_AT_bit_offset  : 21
      <53>   DW_AT_data_member_location: 0
   <2><54>: Abbrev Number: 3 (DW_TAG_member)
      <55>   DW_AT_name        : m
      <57>   DW_AT_decl_file   : 1
      <58>   DW_AT_decl_line   : 4
      <59>   DW_AT_decl_column : 6
      <5a>   DW_AT_type        : <0x71>
      <5e>   DW_AT_byte_size   : 4
      <5f>   DW_AT_bit_size    : 5
      <60>   DW_AT_bit_offset  : 16
      <61>   DW_AT_data_member_location: 0
   <2><62>: Abbrev Number: 3 (DW_TAG_member)
      <63>   DW_AT_name        : n
      <65>   DW_AT_decl_file   : 1
      <66>   DW_AT_decl_line   : 5
      <67>   DW_AT_decl_column : 6
      <68>   DW_AT_type        : <0x71>
      <6c>   DW_AT_byte_size   : 4
      <6d>   DW_AT_bit_size    : 8
      <6e>   DW_AT_bit_offset  : 8
      <6f>   DW_AT_data_member_location: 0
   <2><70>: Abbrev Number: 0
   <1><71>: Abbrev Number: 4 (DW_TAG_base_type)
      <72>   DW_AT_byte_size   : 4
      <73>   DW_AT_encoding    : 5        (signed)
      <74>   DW_AT_name        : int
  <snip>

  $ readelf -wi dwarf_test.be
  Contents of the .debug_info section:
  <snip>
   <1><2d>: Abbrev Number: 2 (DW_TAG_structure_type)
      <2e>   DW_AT_name        : S
      <30>   DW_AT_byte_size   : 4
      <31>   DW_AT_decl_file   : 1
      <32>   DW_AT_decl_line   : 1
      <33>   DW_AT_sibling     : <0x6c>
   <2><37>: Abbrev Number: 3 (DW_TAG_member)
      <38>   DW_AT_name        : j
      <3a>   DW_AT_decl_file   : 1
      <3b>   DW_AT_decl_line   : 2
      <3c>   DW_AT_type        : <0x6c>
      <40>   DW_AT_byte_size   : 4
      <41>   DW_AT_bit_size    : 5
      <42>   DW_AT_bit_offset  : 0
      <43>   DW_AT_data_member_location: 0
   <2><44>: Abbrev Number: 3 (DW_TAG_member)
      <45>   DW_AT_name        : k
      <47>   DW_AT_decl_file   : 1
      <48>   DW_AT_decl_line   : 3
      <49>   DW_AT_type        : <0x6c>
      <4d>   DW_AT_byte_size   : 4
      <4e>   DW_AT_bit_size    : 6
      <4f>   DW_AT_bit_offset  : 5
      <50>   DW_AT_data_member_location: 0
   <2><51>: Abbrev Number: 3 (DW_TAG_member)
      <52>   DW_AT_name        : m
      <54>   DW_AT_decl_file   : 1
      <55>   DW_AT_decl_line   : 4
      <56>   DW_AT_type        : <0x6c>
      <5a>   DW_AT_byte_size   : 4
      <5b>   DW_AT_bit_size    : 5
      <5c>   DW_AT_bit_offset  : 11
      <5d>   DW_AT_data_member_location: 0
   <2><5e>: Abbrev Number: 3 (DW_TAG_member)
      <5f>   DW_AT_name        : n
      <61>   DW_AT_decl_file   : 1
      <62>   DW_AT_decl_line   : 5
      <63>   DW_AT_type        : <0x6c>
      <67>   DW_AT_byte_size   : 4
      <68>   DW_AT_bit_size    : 8
      <69>   DW_AT_bit_offset  : 16
      <6a>   DW_AT_data_member_location: 0
  <snip>

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Mark Wielaard <mark@klomp.org>
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-03-29 15:55:37 -03:00
Andrii Nakryiko 975757bc88 dwarves: Use bit sizes and bit/byte hole info in __class__fprintf
This patch changes __class__fprintf to rely on bit_size/bitfield_size,
calculated in corresponding loaders, instead of trying to guess correct
sizes on its own.

Bit and byte hole information is now stored in current field member and
stores information about holes *before* field. Previously hole
information was stored in previous field and was meant to represent
"holes after a field". Such approach makes it hard to report bit holes
at the very beginning of the struct:

struct s {
	int:4; /* this is bit hole, not a field in DWARF/BTF */
	int x:8;
};

With this change and previous bitfield calculation/fixup logic fixes,
there are no more discrepancies between DWARF/BTF for allyesconfig
kernel. There are also no more BRAIN FART ALERTS!

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Mark Wielaard <mark@klomp.org>
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-03-29 15:55:37 -03:00
Andrii Nakryiko 1838d3d762 dwarves: Revamp bit/byte holes detection logic
This patch rewrites hole detection logic. Now many crazy combinations of
bitfields and normal fields are handled correctly.

This was tested on allyesconfig kernel and differences before/after were
always in favor of new algorithm.

With subsequent change in next patch, there are no more BRAIN FART
ALERTs for allyesconfig and DWARF and BTF outputs have no discrepanies.

Example:
$ cat test.c
struct s {
        short : 4;	/* this one is not emitted in DWARF/BTF */
        short a : 4;
        int x;
        int : 10;
        int y : 4;
        short zz;
        short zzz : 4;
        long z;
        short : 4;
};

int main() {
        struct s s;
        return 0;
}
$ gcc -g test.c -o test
$ ~/pahole/build/pahole -J test
$ ~/pahole/build/pahole -F dwarf test
struct s {

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

        short int                  a:4;                  /*     0: 8  2 */

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

        int                        x;                    /*     4     4 */

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

        int                        y:4;                  /*     8:18  4 */

        /* Bitfield combined with next fields */
        /* XXX 2 bits hole, try to pack */

        short int                  zz;                   /*    10     2 */
        short int                  zzz:4;                /*    12:12  2 */

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

        long int                   z;                    /*    16     8 */

        /* size: 32, cachelines: 1, members: 6 */
        /* sum members (bits): 124, holes: 2, sum holes: 4 */
        /* bit holes: 5, sum bit holes: 36 bits */
        /* padding: 8 */
        /* last cacheline: 32 bytes */
};

No discrepanies between BTF/DWARF:
$ ../btfdiff test
$

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Mark Wielaard <mark@klomp.org>
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-03-29 15:55:37 -03:00
Andrii Nakryiko 55c96aaed8 loaders: Strip away volatile/const/restrict when fixing bitfields
btf_loader and ctf_loader didn't remove const/volatile/restrict, so
bitfields using modifiers were not adjusted properly.

This patch abstracts logic of stripping aways typedefs and access
modifiers into tag__strip_typedefs_and_modifiers, which handles any
interleaving of typedefs and modifiers. dwarf_loader was adapter to
reuse this function as well, instead of custom goto loop.

REPRO:

  $ cat vc_map.c
  typedef unsigned int u32;
  typedef volatile u32 vu32;
  typedef vu32 vu32_t;

  typedef struct vc_map {
          volatile unsigned int tx: 1;
          vu32_t rx: 1;
          void *x1, *x2;
  } vc_map;

  int main() {
          struct vc_map s;
          return 0;
  }

BEFORE:

  $ ~/pahole/build/pahole -F btf vc_map
  struct vc_map {
          volatile unsigned int      tx:1;                 /*     0: 0  4 */
          vu32_t                     rx:1;                 /*     0: 0  4 */

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

          void *                     x1;                   /*     8     8 */
          void *                     x2;                   /*    16     8 */

          /* size: 24, cachelines: 1, members: 4 */
          /* sum members: 20, holes: 1, sum holes: 4 */
          /* bit holes: 1, sum bit holes: 30 bits */
          /* last cacheline: 24 bytes */
  };

AFTER:

  $ ~/pahole/build/pahole -F btf vc_map
  struct vc_map {
          volatile unsigned int      tx:1;                 /*     0:31  4 */
          vu32_t                     rx:1;                 /*     0:30  4 */

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

          void *                     x1;                   /*     8     8 */
          void *                     x2;                   /*    16     8 */

          /* size: 24, cachelines: 1, members: 4 */
          /* sum members: 20, holes: 1, sum holes: 4 */
          /* bit holes: 1, sum bit holes: 30 bits */
          /* last cacheline: 24 bytes */
  };

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-03-29 15:55:37 -03:00
Arnaldo Carvalho de Melo 5375d06faf dwarves: Introduce type_id_t for use with the type IDs
This is just a prep patch, marking uint16_t IDs as type_id_t, that
points to uint16_t, so no change in the resulting code.

Cc: Andrii Nakryiko <andriin@fb.com>
Tested-by:Andrii Nakryiko <andrii.nakryiko@gmail.com>
Link: https://lore.kernel.org/bpf/CAEf4Bzb0SpvXdDKMMnUof==kp4Y0AP54bKFjeCzX_AsmDm7k7g@mail.gmail.com/
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-03-11 11:44:53 -03:00
Arnaldo Carvalho de Melo c9b2ef034f dwarf: Add cu__add_tag_with_id() to stop using id == -1 to allocate id
the CTF and BTF loaders come already with the id to use, while the DWARF
loader comes with a Dwarf_Off that needs to be converted into the
ptr_table index.

So keep the cu__add_tag(cu, tag, &id) method to ask ask for the index to
be allocated in the ptr_table and the result to come back via the 'id'
parameter, now a uint32_t and introduce a cu__add_tag_with_id(cu, tag, id)
method to indicate that the 'uint32_t id' is the one to use.

With this we can use a uint32_t for the id both on 32-bit and 64-bit
arches.

Reported-by: Andrii Nakryiko <andriin@fb.com>
Tested-by:Andrii Nakryiko <andrii.nakryiko@gmail.com>
Link: https://lore.kernel.org/bpf/CAEf4Bzb0SpvXdDKMMnUof==kp4Y0AP54bKFjeCzX_AsmDm7k7g@mail.gmail.com/
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-03-11 11:44:45 -03:00
Arnaldo Carvalho de Melo 762e7b58f4 dwarves: Change ptr_table__add() signature to allow for uint32_t returns
We were using 'long', so that we could return -ENOMEM, but since we need
struct ptr_table members are already uint32_t, meaning we can use the
entire range, make the return be just an int and be just for error
reporting and pass a uint32_t pointer to return the index used for the
new entry.

Reported-by: Andrii Nakryiko <andriin@fb.com>
Tested-by:Andrii Nakryiko <andrii.nakryiko@gmail.com>
Link: https://lore.kernel.org/bpf/CAEf4Bzb0SpvXdDKMMnUof==kp4Y0AP54bKFjeCzX_AsmDm7k7g@mail.gmail.com/
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-03-11 11:44:34 -03:00
Andrii Nakryiko 3526ebebd3 pahole: Use 32-bit integers for type ID iterations within CU
Existing code base assumes that single CU doesn't have more than 65535
types per each CU, which might be a reasonable assumption for DWARF
data. With BTF, though, all we get is single, potentially huge, CU which
can easily have more than 65k types. For example, this is the case for
allyesconfig version of Linux kernel, which has >200k types.

Due to this assumption, libdwarves and other parts of pahole are using
16-bit counters to iterate over entities within CU. This can cause
infinite loops when iterating BTF data, if there are more than 65535
types. This patch changes non-public variables to use 32-bit integers,
where appropriate.

This still leads to invalid reported data when using BTF loader (due to using
(X & 0xFFFF) type ID, instead of X, when X > 65535) and loading huge files,
but at least it's not stuck in an infinite loop anymore.

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Reported-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
[ Removed non type ID conversions, for instance for the kind of tag, like in type->namespace.tag.tag, that can remain a uint16_t ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-03-07 11:16:10 -03:00
Arnaldo Carvalho de Melo be5173b4df dwarves: Fixup sizeof(long double) in bits in base_type_name_to_size table
We were erroneously setting it to 64 bits everywhere, i.e. 8 bytes, when
it in fact is 16 bytes, 128 bits, as we can see with:

  $ btfdiff libc-2.28.so.debug
  --- /tmp/btfdiff.dwarf.RuqA9q	2019-02-26 10:25:49.828150761 -0300
  +++ /tmp/btfdiff.btf.t3XqV6	2019-02-26 10:25:49.835150835 -0300
  @@ -461,9 +461,15 @@ struct La_x86_64_retval {
 	  uint64_t                   lrv_rdx;              /*     8     8 */
 	  La_x86_64_xmm              lrv_xmm0;             /*    16    16 */
 	  La_x86_64_xmm              lrv_xmm1;             /*    32    16 */
  -	long double                lrv_st0;              /*    48    16 */
  +	long double                lrv_st0;              /*    48     8 */
  +
  +	/* XXX 8 bytes hole, try to pack */
  +
 	  /* --- cacheline 1 boundary (64 bytes) --- */
  -	long double                lrv_st1;              /*    64    16 */
  +	long double                lrv_st1;              /*    64     8 */
  +
  +	/* XXX 8 bytes hole, try to pack */
  +
 	  La_x86_64_vector           lrv_vector0;          /*    80    64 */
 	  /* --- cacheline 2 boundary (128 bytes) was 16 bytes ago --- */
 	  La_x86_64_vector           lrv_vector1;          /*   144    64 */

And:

  $ cat long_double.c
  #include <stdio.h>

  int main(void)
  {
	  return printf("sizeof(long double)=%zd\n", sizeof(long double));
  }
  $ ./long_double
  sizeof(long double)=16
  $ file long_double
  long_double: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=c876603879d49905fbd7fc5907dc65ad3bca422f, not stripped
  $

So use sizeof to at least match the running machine, this is
insufficient for cross-platform analysis, so a new fix is needed to
cover those cases, this at least improves the current situation a bit.

Reported-by: Andrii Nakryiko <andriin@fb.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Yonghong Song <yhs@fb.com>
link: https://lore.kernel.org/bpf/20190226131156.GA26786@kernel.org/
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-02-26 10:26:14 -03:00
Arnaldo Carvalho de Melo 5081ed5070 dwarves: Add _Float128 base_type
Without it we end up with these messages and a zero sized _Float128
type.

  $ btfdiff libc-2.28.so.debug
  base_type__name_to_size: base_type _Float128
  class__fixup_btf_bitfields: unknown base type name "_Float128"!
  base_type__name_to_size: base_type _Float128
  class__fixup_btf_bitfields: unknown base type name "_Float128"!
  base_type__name_to_size: base_type _Float128
  class__fixup_btf_bitfields: unknown base type name "_Float128"!
  base_type__name_to_size: base_type _Float128
  class__fixup_btf_bitfields: unknown base type name "_Float128"!
  base_type__name_to_size: base_type _Float128
  class__fixup_btf_bitfields: unknown base type name "_Float128"!
  base_type__name_to_size: base_type _Float128
  class__fixup_btf_bitfields: unknown base type name "_Float128"!
  --- /tmp/btfdiff.dwarf.M7kavg	2019-02-26 10:13:06.633184595 -0300
  +++ /tmp/btfdiff.btf.vlWt5u	2019-02-26 10:13:06.640184669 -0300
  @@ -2142,7 +2149,7 @@ struct ucontext_t {
 	  /* last cacheline: 8 bytes */
   };
   union ieee854_float128 {
  -	_Float128                  d;                  /*     0    16 */
  +	_Float128                  d;                  /*     0     0 */
 	  struct {
 		  unsigned int       mantissa3:32;       /*     0: 0  4 */
 		  unsigned int       mantissa2:32;       /*     4: 0  4 */

After this patch these messages are gone and for pahole's needs we have
enough information, no need to wait for BTF to have explicit support for
floating point base types.

Reported-by: Andrii Nakryiko <andriin@fb.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Link: https://lore.kernel.org/bpf/20190226131156.GA26786@kernel.org/
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-02-26 10:15:17 -03:00
Andrii Nakryiko 7daa4300d2 pahole: Complete list of base type names
clang seems to generate base type with name "short", instead of "short
in", but it also isn't inconceivable to imagine other compilers
generating just "long" and/or "long long". This patch adds all those
short forms to a list of base type names.

  $ cat type_test.c
  struct s {
      short x1;
      long x2;
      long long x3;
  };

  int main() {
      struct s s;
      return 0;
  }

  $ clang -g type_test.c -o type_test && ~/local/pahole/build/pahole -JV type_test
  File type_test:
  [1] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
  [2] STRUCT s kind_flag=0 size=24 vlen=3
          x1 type_id=3 bits_offset=0
          x2 type_id=4 bits_offset=64
          x3 type_id=5 bits_offset=128
  [3] INT short size=2 bit_offset=0 nr_bits=16 encoding=SIGNED
  [4] INT long int size=8 bit_offset=0 nr_bits=64 encoding=SIGNED
  [5] INT long long int size=8 bit_offset=0 nr_bits=64 encoding=SIGNED

Before:

  $ ~/local/pahole/build/pahole -F btf type_test
  base_type__name_to_size: base_type short
  class__fixup_btf_bitfields: unknown base type name "short"!
  struct s {
          short                      x1;                   /*     0     0 */

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

          long int                   x2;                   /*     8     8 */
          long long int              x3;                   /*    16     8 */

          /* size: 24, cachelines: 1, members: 3 */
          /* sum members: 16, holes: 1, sum holes: 8 */
          /* last cacheline: 24 bytes */
  };

After:

  $ ~/local/pahole/build/pahole -F btf type_test
  struct s {
          short                      x1;                   /*     0     2 */

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

          long int                   x2;                   /*     8     8 */
          long long int              x3;                   /*    16     8 */

          /* size: 24, cachelines: 1, members: 3 */
          /* sum members: 18, holes: 1, sum holes: 6 */
          /* last cacheline: 24 bytes */
  };

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-02-22 18:08:02 -03:00
Arnaldo Carvalho de Melo 6780c4334d btf: Rename 'struct btf' to 'struct btf_elf'
So that we don't clash with libbpf's 'struct btf', in time more internal
state now in 'struct btf_elf' will refer to the equivalent internal
state in libbpf's 'struct btf', as they have lots in common.

Requested-by: Andrii Nakryiko <andrii.nakryiko@gmail.com>
Acked-by: Andrii Nakryiko <andrii.nakryiko@gmail.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Martin Lau <kafai@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-02-14 17:06:23 -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
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 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
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 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 2a092d6145 dwarves: Fix cus__load_files() success return value
If we processed at least one file we should return 0 to mean success.

Fixes: 02a456f5f5 ("pahole: Search and use running kernel vmlinux when no file is passed")
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2017-12-14 14:14:56 -03:00
Arnaldo Carvalho de Melo 02a456f5f5 pahole: Search and use running kernel vmlinux when no file is passed
Seems like a nice shortcut for kernel hackers, and one that makes sure
the right vmlinux file is used, as it reads the running kernel build id
from /sys/kernel/notes and then searches the well known path for vmlinux
files:

vmlinux
/boot/vmlinux
/boot/vmlinux-4.14.0+
/usr/lib/debug/boot/vmlinux-`uname -r`
/lib/modules/`uname -r`/build/vmlinux
/usr/lib/debug/lib/modules/`uname -r`/vmlinux
/usr/lib/debug/boot/vmlinux-`uname -r`.debug

To find one with a matching build id (.notes ELF section, then
nhdr->n_type == NT_GNU_BUILD_ID), just like the Linux kernel 'perf
tools', where this code comes from, with some minor modifications to
cope with not having symbol_conf, symfs, etc.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2017-11-24 11:24:16 -03:00
Arnaldo Carvalho de Melo 103e89bb25 dwarves_fprintf: Find holes on structs embedded in other structs
Take 'struct task_struct' in the Linux kernel, these fields:

        /* --- cacheline 2 boundary (128 bytes) --- */
        struct sched_entity        se;                   /*   128   448 */

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

        /* --- cacheline 9 boundary (576 bytes) --- */
        struct sched_rt_entity     rt;                   /*   576    48 */

The sched_entity struct has 24 bytes of padding, and that info would
only appear when printing 'struct task_struct' if class__find_holes()
had previously been run on 'struct sched_entity' which wasn't always the
case, make sure that happens.

This results in this extra stat being printed for 'struct task_struct':

	/* paddings: 4, sum paddings: 38 */

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2016-06-30 16:18:11 -03:00
Arnaldo Carvalho de Melo 44130bf70e dwarves: Update e-mail address
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2016-06-28 14:24:41 -03:00
Arnaldo Carvalho de Melo 9df42c6826 dwarves: Initial support for rvalue_reference_type
Need to read more on http://www.artima.com/cppsource/rvalue.html, but
handling it mostly like DW_TAG_typedef so that at least references to it
are resolved, we can get its byte size, etc.

FIXME: look at the vtable parameters, some are resolving to "(null)".

Reported-by: Benjamin Kosnik <bkoz@redhat.com>
Reported-by: Mark Wieelard <mjw@redhat.com>
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=962571
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2016-03-15 16:37:48 -03:00
Arnaldo Carvalho de Melo 10515a7c4d dwarves: Introduce cus__fprintf_load_files_err()
Out of code in pdwtags and pahole, will be used in the other tools.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2016-03-15 14:25:58 -03:00
Arnaldo Carvalho de Melo 9f3f67e786 dwarves: Fix cus__load_files() error return
Silly bug, it was trying to return a negative index stating what file
had problems in the provided array, but if the first had problems it was
return -0, duh, fix it by returning the first as 1, etc.

With this, calling 'pdwtags non-existent-file' would return no errors
via $?.

Next csets will provide proper error messages, using what is in errno
and this index to tell what file has problems.

Reported-by: Eric Blake <eblake@redhat.com>
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=949034
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2016-03-15 12:24:38 -03:00
Arnaldo Carvalho de Melo 8c6378fd88 dwarves: Support static class data members
Fixes the following BFA:

[acme@sandy pahole]$ pahole brainfart.o
class ios_base {
	enum _Ios_Openmodeconst    in;                   /*     0     4 */
	typedef enum _Ios_Fmtflags fmtflags;

	/* size: 1, cachelines: 1, members: 1 */
	/* padding: 65533 */
	/* last cacheline: 1 bytes */

	/* BRAIN FART ALERT! 1 != 4 + 0(holes), diff = -3 */

};

That now produces:

[acme@sandy pahole]$ build/pahole brainfart.o
class ios_base {
	static enum _Ios_Openmodeconst    in = 8;        /*     0     0 */
	typedef enum _Ios_Fmtflags fmtflags;

	/* size: 1, cachelines: 0, members: 0, static members: 1 */
	/* last cacheline: 1 bytes */
};
[acme@sandy pahole]$

Reported-by: Nicolas <nikos42@gmail.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2012-08-20 14:42:17 -03:00
Arnaldo Carvalho de Melo a54515fa6e dwarves: Stop using 'self'
As Thomas Gleixner wisely pointed out, using 'self' is stupid, it
doesn't convey useful information, so use sensible names.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2012-08-17 18:47:15 -03:00
Arnaldo Carvalho de Melo e1e7fc2f53 dwarves: Add missing #include <sys/stat.h>
Needed because it uses S_ISDIR. In the past this header probably was
being indirectly included. Noticed while building on RHEL6 Beta.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2010-06-04 09:26:13 -03:00
Arnaldo Carvalho de Melo 0c50ef3a60 dwarves: class_member__clone need to allocate from the obstack
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-09-20 16:20:06 -03:00
Arnaldo Carvalho de Melo f001b9f688 dwarves: Add a newline to __tag__id_not_found_fprintf output
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-09-14 17:55:20 -03:00
Arnaldo Carvalho de Melo 5be2291b14 dwarves: Teach base_type__name_to_size about "long double"
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-09-14 17:50:14 -03:00
Arnaldo Carvalho de Melo b4977b20e0 dwarves: __tag__has_type_loop has to handle a NULL type (void)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-09-14 17:39:52 -03:00
Arnaldo Carvalho de Melo 9720415091 dwarf: Detect type loops
[acme@doppio pahole]$ pahole -F ctf /media/tb/debuginfo/usr/lib/debug/usr/bin/greycstoration4integration.debug > /tmp/bla
<ERROR(tag__size:837): detected type loop: type=572, tag=const_type>
<ERROR(tag__size:837): detected type loop: type=572, tag=const_type>
[acme@doppio pahole]$

These type loops are problems in the CTF encoding, that should be fixed, but
should not cause the core code to segfault on an infinite recursion.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-09-14 17:07:02 -03:00
Arnaldo Carvalho de Melo 7e5b39f944 dwarves_fprintf: Make tag__id_not_found_(f|sn)printf print __LINE__
Helps debugging.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-09-11 15:10:43 -03:00
Arnaldo Carvalho de Melo fc1269af2f pahole: Introduce --classes_as_structs
That asks dwarf_fprintf to always use "struct" in places where it would
use "class", because CTF doesn't have the "class" concept, so for
'regtest diffctf' sake, we use this.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-08-24 17:22:43 -03:00
Arnaldo Carvalho de Melo 3de722e9ab dwarves: Delete list entries in reverse order
It doesn't matter when using a traditional malloc/free allocator, but
with obstacks we need to do it in reverse order.

For the usual case where we successfully process an object this doesn't
matter, as when we started using obstacks we don't traverse all the tags
calling their destructors anymore, we just free the whole obstack in one
go.

Noticed when processing object files built from non-supported languages
such as FORTRAN and Pascal, where there are some DWARF tags that are not
supported, which makes the object file load to be prematurely aborted
and that calls destructors for things like classes and functions that in
turn free space for their parameter/member lists, which now have to be
done in reverse order.

We could just stop calling the destructors and then destroying the whole
obstack, but I think that partially processed files are a nice feature,
so keep the interface in a way that both obstacks and traditinal malloc
alocators can be used.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-08-19 10:32:49 -03:00
Arnaldo Carvalho de Melo 19bbecf668 dwarves: Pass the cu to destructors to free memory on the obstack
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-08-18 18:21:20 -03:00
Arnaldo Carvalho de Melo dffd3d4ee7 dwarves: Fix cu__find_base_type_by_name when the base_type name is NULL
This shouldn't happen, but if it does, don't return it.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-08-16 12:13:38 -03:00
Arnaldo Carvalho de Melo 932a884ed9 dwarves: Use an obstack for all the tags
We got it down from:

15.733210256  seconds time elapsed   ( +-   0.197% )

as reported in the previous changeset to:

[acme@doppio pahole]$ perf stat -r 5 pahole object_samples/zweinberg\@mozilla.com/libgklayout.so > /dev/null

 Performance counter stats for 'pahole object_samples/zweinberg@mozilla.com/libgklayout.so' (5 runs):

   12293.726462  task-clock-msecs         #      0.969 CPUs    ( +-   0.189% )
           2663  context-switches         #      0.000 M/sec   ( +-  18.994% )
             40  CPU-migrations           #      0.000 M/sec   ( +-  34.146% )
         127003  page-faults              #      0.010 M/sec   ( +-   0.000% )
    24417854522  cycles                   #   1986.204 M/sec   ( +-   0.174% )
    29007002413  instructions             #      1.188 IPC     ( +-   0.009% )
      297872959  cache-references         #     24.230 M/sec   ( +-   0.529% )
       21440854  cache-misses             #      1.744 M/sec   ( +-   0.321% )

   12.680530119  seconds time elapsed   ( +-   1.042% )

[acme@doppio pahole]$

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-07-08 16:37:37 -03:00
Arnaldo Carvalho de Melo 570dd1ea55 dwarves: constify filename parm of cus__load_file
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-08 14:17:23 -03:00
Arnaldo Carvalho de Melo 27f4f0afb1 dwarves: Make cus__load_file really use the format path
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-04 23:15:52 -03:00
Arnaldo Carvalho de Melo 7c6603189e dwarves: Make all the tags that have an IP to be derived from ip_tag
Next we'll add a new kind of tag, DW_TAG_perf_counter, that will come
from perf.data generated by 'perf report'.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-04 17:30:06 -03:00
Arnaldo Carvalho de Melo e429f8efbb dwarves: Add an rbtree for the functions in a cu
That is used by cus__find_function_by_addr & cu__func_function_by_addr.

First user is pfunct --addr, but this is really for pfunct --annotate, that
will process a perf.data file generated by 'perf report', load the debugging
info and regenerate the functions (pfunct -TVi like) that had hits, using
libdisasm to show the assembly code, etc.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-04 14:56:44 -03:00
Arnaldo Carvalho de Melo e2b7d1a5f5 dwarves: types are uint16_t now
Remove one more DWARF specific detail.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-03 14:56:53 -03:00
Arnaldo Carvalho de Melo f84bf73d54 dwarves: Move the fprintf code to a new source file.
$ wc -l dwarves.c dwarves_fprintf.c
 1468 dwarves.c
 1554 dwarves_fprintf.c
 3022 total
$

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-04-19 13:48:51 -03:00
Arnaldo Carvalho de Melo e148f93418 code: Combine the debugging_formats and debug_fmt_ops structs
Paving the way for pluggable debugging formats via dlopen.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-04-04 14:56:39 -03:00