Commit Graph

1201 Commits

Author SHA1 Message Date
Andrii Nakryiko b56fed297e dwarves_fprintf: Count bitfield member sizes separately
Counting field sizes only in bits causes confusion and lots of differing
output, when compared to previous logic. This commit changes logic so
that it counts bit size of bitfield fields separately from byte size of
non-bitfield fields. In the end, if there were bit holes, this bit size
is emitted explicitly. This makes output for struct/unions not using
bitfields identical, while also preserving correctness (and data
completeness) for cases with bitfields and bit holes.

Example (-before/+after):
 struct cfg80211_pmsr_request_peer {
        u8                         addr[6];              /*     0     6 */

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

        struct cfg80211_chan_def   chandef;              /*     8    24 */

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

        u8                         report_ap_tsf:1;      /*    32: 0  1 */

        /* XXX 7 bits hole, try to pack */
        /* XXX 3 bytes hole, try to pack */

        struct cfg80211_pmsr_ftm_request_peer ftm;       /*    36    12 */

        /* XXX last struct has 1 byte of padding */

        /* size: 48, cachelines: 1, members: 4 */
-       /* sum members: 43, holes: 2, sum holes: 5 */
-       /* bit holes: 1, sum bit holes: 7 bits */
+       /* sum members: 42, holes: 2, sum holes: 5 */
+       /* sum bitfield members: 1 bits, bit holes: 1, sum bit holes: 7 bits */
        /* paddings: 2, sum paddings: 5 */
        /* last cacheline: 48 bytes */
 };

For cases where there is only byte or bit hole, we still emit total byte and
bit sizes of all members as to not mislead user:
 struct sched_dl_entity {
... <snip ...
        unsigned int               dl_non_contending:1;  /*    84: 3  4 */
        unsigned int               dl_overrun:1;         /*    84: 4  4 */

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

        struct hrtimer             dl_timer;             /*    88    64 */

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

        /* --- cacheline 2 boundary (128 bytes) was 24 bytes ago --- */
        struct hrtimer             inactive_timer;       /*   152    64 */

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

        /* size: 216, cachelines: 4, members: 16 */
-       /* bit holes: 1, sum bit holes: 27 bits */
+       /* sum members: 212 */
+       /* sum bitfield members: 5 bits, bit holes: 1, sum bit holes: 27 bits */
        /* paddings: 2, sum paddings: 10 */
        /* last cacheline: 24 bytes */
 };

For structs with tightly packed bitfield, we emit total number of bits and also
convert them to bytes. E.g., for struct sock output :
struct sock {
... <snip ...
        /* size: 720, cachelines: 12, members: 84 */
-       /* sum members: 712, holes: 4, sum holes: 8 */
+       /* sum members: 707, holes: 4, sum holes: 8 */
+       /* sum bitfield members: 40 bits (5 bytes) */
        /* paddings: 1, sum paddings: 4 */
        /* last cacheline: 16 bytes */
 };

Suggested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
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-03-29 15:55:37 -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 5104d1bef3 loaders: Record CU's endianness in dwarf/btf/ctf loaders
This patch records for each CU whether it's in little-endian or
big-endian data format. This flag will be used in subsequent commits to
adjust bit offsets where necessary, to make them uniform across
endianness. This patch doesn't have any effect on pahole's output.

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 03d9b6ebca dwarf_loader: Fix bitfield fixup logic for DWARF
This patch uses similar approach to btf_loader's one and
adjusts/calculates bitfield parameters in such a way, that their byte
offset is always naturally aligned according to underlying base type
alignment requirement. This is consistent with btf_loader behavior and
helps to get closer to zero discrepancies between DWARF/BTF.

We also make sure that bitfield_offset never stays negative, which can
surprise some other parts of pahole logic.

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: dwarves@vger.kernel.org
Cc: Mark Wielaard <mark@klomp.org>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-03-29 15:55:37 -03:00
Andrii Nakryiko 4abc595539 btf_loader: Adjust negative bitfield offsets early on
Bitfield offsets can be negative, if field "borrows" few bits from
following aligned field. This causes a bunch of surprises down the line
in pahole's logic (e.g., for hole calculation logic), so instead of
waiting till printf routines adjust this for display, adjust them early
and keep less surprising semantics.

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>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-03-29 15:55:37 -03:00
Andrii Nakryiko 41cf0e3cba dwarf_loader: Don't recode enums and use real enum size in calculations
This patch disables bitfield recoding logic in DWARF loader.
This logic is already disabled during DWARF->BTF conversion and without
it pahole reliably produces correct BTF bitfield offsets.

If this functionality is enabled, we are losing correct enum size
information. So let's disable and probably eventually remove it altogether.

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-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
Andrii Nakryiko 7005757fd5 libbpf: Sync in latest libbpf sources
Get latest changes and fixes for libbpf. Most importantly it pulls in
enum fwd resolution in btf_dedup().

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-03-29 15:53:13 -03:00
Arnaldo Carvalho de Melo 69970fc77e pahole: Filter out unions when looking for packable structs
After we made -C apply for unions we had to stop calling
class__find_holes() on them, but forgot to also filter them out when
using --packable, which lead us to, in print_packable_info to access
class->priv for unions, as they were not filtered out, which made
it think that class->priv had the reordered cloned class, b00m.

Fix it by filtering out unions when doing --packable.

Fixes: 3ffe5ba93b ("pahole: Do not apply 'struct class' filters to 'struct type'")
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-03-28 16:53:26 -03:00
Arnaldo Carvalho de Melo fa963e1a86 dwarves_fprintf: Print the bit_offset for inline enum bitfield class members
Before:

  $ pahole examples/myrb_dcdb.o
  struct myrb_dcdb {
	  unsigned int               target:4;             /*     0:28  4 */
	  unsigned int               channel:4;            /*     0:24  4 */

	  /* Bitfield combined with next fields */

	  enum {
		  MYRB_DCDB_XFER_NONE = 0,
		  MYRB_DCDB_XFER_DEVICE_TO_SYSTEM = 1,
		  MYRB_DCDB_XFER_SYSTEM_TO_DEVICE = 2,
		  MYRB_DCDB_XFER_ILLEGAL = 3,
	  } data_xfer:2;                                     /*     1     1 */
  <SNIP>

After:

  $ pahole examples/myrb_dcdb.o
  struct myrb_dcdb {
	unsigned int               target:4;             /*     0:28  4 */
	unsigned int               channel:4;            /*     0:24  4 */

	/* Bitfield combined with next fields */

	enum {
		MYRB_DCDB_XFER_NONE = 0,
		MYRB_DCDB_XFER_DEVICE_TO_SYSTEM = 1,
		MYRB_DCDB_XFER_SYSTEM_TO_DEVICE = 2,
		MYRB_DCDB_XFER_ILLEGAL = 3,
	} data_xfer:2;                                   /*     1: 6  1 */

  <SNIP>

Look at data_xfer:2, it now shows the bit_offset (6) in addition to the
byte offset (1) and the bit_size (2).

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-03-12 16:46:15 -03:00
Arnaldo Carvalho de Melo bb8350acf5 dwarves: Switch type_id_t from uint16_t to uint32_t
With BTF dedup we end up with a CU with all the types, and with
something like an allmodconfig vmlinux image it ends up with more than
65535 types, so use uint32_t for the type IDs to accomodate that.

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:57 -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 f601f67258 libctf: The type_ids returned are uint32_t fixup where it was uint16_t
To help in the tree wide conversion to uint32_t to represent type IDs.

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
Arnaldo Carvalho de Melo 079e6890b7 dwarf_loader: Mark tag__recode_dwarf_bitfield() static
Not used outside the DWARF loader.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-03-07 11:35:17 -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
Andrii Nakryiko 3bd8da5202 libbpf: update reference to bring in btf_dedup fixes
Latest version of libbpf has btf_dedup() fixes preventing it from stucking
in a loop on allyesconfig kernels.

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: andrii.nakryiko@gmail.com
Cc: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
[ Fixed up to get the right upstream commit, the originally submitted wasn't at the github repo ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-03-06 10:37:03 -03:00
Andrii Nakryiko a9afcc65fc btf_encoder: Don't special case packed enums
BTF data can represent packed enums correctly without any special
handling from pahole side. Previously pahole's own `enum vscope` would
be omitted causing problems.

Original commit tried to generate correct struct bitfield member type if
the member is an enum. This was dated before kind_flag implementation.
Later, kind_flag support was added and now pahole always generates BTF
with kind_flag = 1 for structures with bitfield, where bitfield size is
encoded in btf_member, so this workaround is not needed any more.
Removing this "hack" makes handling it easier to handle packed enums
correctly.

Repro:

  $ cat test/packed_enum.c
  enum packed_enum {
          VALUE1,
          VALUE2,
          VALUE3
  } __attribute__((packed));

  struct s {
          int x;
          enum packed_enum e;
          int y;
  };

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

  $ gcc -g -c test/packed_enum.c -o test/packed_enum.o

  $ ~/local/pahole/build/pahole -JV test/packed_enum.o
  File test/packed_enum.o:
  [1] INT (anon) size=1 bit_offset=0 nr_bits=8 encoding=SIGNED
  [2] STRUCT s kind_flag=0 size=12 vlen=3
          x type_id=3 bits_offset=0
          e type_id=1 bits_offset=32
          y type_id=3 bits_offset=64
  [3] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED

  $ ~/local/pahole/build/pahole -F dwarf test/packed_enum.o
  struct s {
          int                        x;                    /*     0     4 */
          enum packed_enum           e;                    /*     4     1 */

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

          int                        y;                    /*     8     4 */

          /* size: 12, cachelines: 1, members: 3 */
          /* sum members: 9, holes: 1, sum holes: 3 */
          /* last cacheline: 12 bytes */
  };

  $ ~/local/pahole/build/pahole -F btf test/packed_enum.o
  struct s {
          int                        x;                    /*     0     4 */
          nameless base type!        e;                    /*     4     1 */

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

          int                        y;                    /*     8     4 */

          /* size: 12, cachelines: 1, members: 3 */
          /* sum members: 9, holes: 1, sum holes: 3 */
          /* last cacheline: 12 bytes */
  };

Notice how pahole's log doesn't have a mention of encoding 'packed_enum'
(anonymous integer is generated instead), which causes 'nameless base
type!' output above.

Fix this change:

  $ ~/local/pahole/build/pahole -JV test/packed_enum.o
  File test/packed_enum.o:
  [1] ENUM packed_enum size=1 vlen=3
          VALUE1 val=0
          VALUE2 val=1
          VALUE3 val=2
  [2] STRUCT s kind_flag=0 size=12 vlen=3
          x type_id=3 bits_offset=0
          e type_id=1 bits_offset=32
          y type_id=3 bits_offset=64
  [3] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED

  $ ~/local/pahole/build/pahole -F btf test/packed_enum.o
  struct s {
          int                        x;                    /*     0     4 */
          enum packed_enum           e;                    /*     4     1 */

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

          int                        y;                    /*     8     4 */

          /* size: 12, cachelines: 1, members: 3 */
          /* sum members: 9, holes: 1, sum holes: 3 */
          /* last cacheline: 12 bytes */
  };

  $ PAHOLE=~/local/pahole/build/pahole ./btfdiff test/packed_enum.o

Also verified on pahole, kernel and glibc:

  $ PAHOLE=~/local/pahole/build/pahole ./btfdiff ~/local/btf/pahole.debug
  $ PAHOLE=~/local/pahole/build/pahole ./btfdiff ~/local/btf/libc-2.28.so.debug
  $ PAHOLE=~/local/pahole/build/pahole ./btfdiff ~/local/btf/vmlinux4

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: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
Fixes: b18354f64c ("btf: Generate correct struct bitfield member types")
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-02-26 11:32:32 -03:00
Andrii Nakryiko 8f4f280163 btf_loader: Simplify fixup code by relying on BTF data more
btf_loader relies on guessing base integral type size for enums and
integers, which is unreliable. There doesn't seem to be a need for that,
as all this information could be extracted from BTF information.

  Before:
  $ PAHOLE=~/local/pahole/build/pahole ./btfdiff ~/local/btf/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.aV4wSL   2019-02-25 13:31:54.787923673 -0800
  +++ /tmp/btfdiff.btf.22NQmJ     2019-02-25 13:31:54.802923668 -0800
  @@ -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 */
  @@ -472,6 +478,7 @@ struct La_x86_64_retval {
          __int128                   lrv_bnd1;             /*   224    16 */

          /* size: 240, cachelines: 4, members: 10 */
  +       /* sum members: 224, holes: 2, sum holes: 16 */
          /* last cacheline: 48 bytes */
   };
   struct r_debug {
  @@ -2044,7 +2051,7 @@ union ieee754_float {
          } ieee_nan;                                    /*     0     4 */
   };
   union ieee854_long_double {
  -       long double                d;                  /*     0    16 */
  +       long double                d;                  /*     0     8 */
          struct {
                  unsigned int       mantissa1:32;       /*     0: 0  4 */
                  unsigned int       mantissa0:32;       /*     4: 0  4 */
  @@ -2141,7 +2148,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 */
  @@ -2219,7 +2226,7 @@ union printf_arg {
          long unsigned int          pa_u_long_int;      /*     0     8 */
          long long unsigned int     pa_u_long_long_int; /*     0     8 */
          double                     pa_double;          /*     0     8 */
  -       long double                pa_long_double;     /*     0    16 */
  +       long double                pa_long_double;     /*     0     8 */
          const char  *              pa_string;          /*     0     8 */
          const wchar_t  *           pa_wstring;         /*     0     8 */
          void *                     pa_pointer;         /*     0     8 */

  $ PAHOLE=~/local/pahole/build/pahole ./btfdiff ~/local/btf/libc-2.28.so.debug
  <empty output>

  Still good for kernel image:
  $ PAHOLE=~/local/pahole/build/pahole ./btfdiff ~/local/btf/vmlinux4
  <empty output>

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-26 10:41:44 -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
Arnaldo Carvalho de Melo d52c9f9b94 dwarf_loader: Fixup bitfield entry with same number of bits as its base_type
For instance:

  $ cat examples/andrii/hsw_tsx_tuning.c
  // https://lore.kernel.org/bpf/CAEf4BzYoJgxYWX9iS7pda62cnGr5VOC70NGgqPurMNWP_w1daA@mail.gmail.com/

  typedef unsigned long long u64;
  typedef unsigned int u32;

  union hsw_tsx_tuning {
          struct {
                  u32 cycles_last_block     : 32,
                      hle_abort             : 1,
                      rtm_abort             : 1,
                      instruction_abort     : 1,
                      non_instruction_abort : 1,
                      retry                 : 1,
                      data_conflict         : 1,
                      capacity_writes       : 1,
                      capacity_reads        : 1;
          };
          u64        value;
  };

  int main() {
          union hsw_tsx_tuning t;
          return 0;
  }
  $

When recoding the DWARF bitfield sizes we look for a base type that has
32 bits and that has the same name, in this case:

  $ pahole --expand_types examples/andrii/hsw_tsx_tuning-gcc  | grep cycles_last_block
		/* typedef u32 */ unsigned int       cycles_last_block:32;               /*     0: 0  4 */
  $

We look for a 'unsigned int' with 32 bits, the same way as we do for all
the other bitfield entries. That worked well when the bit_size wasn't
the same as existing base type like 'unsigned int', which ended up
making that field get recoded to point to 'unsigned int', effectively
removing the original name, 'u32' in the case above, with the base type
it ultimately points to, 'unsigned int'.

Fix it making it use the same logic as for bit sizes that are different
from the base_type it points to, i.e. go ahead and create a new typedef
pointing to to a new base_type that has the right bit_size.

So, to sum up, before this fix:

$ btfdiff hsw_tsx_tuning-gcc
--- /tmp/btfdiff.dwarf.ErXffk   2019-02-25 10:26:56.863625697 -0300
+++ /tmp/btfdiff.btf.Y5EDdM     2019-02-25 10:26:56.864625706 -0300
@@ -1,6 +1,6 @@
 union hsw_tsx_tuning {
        struct {
-               unsigned int       cycles_last_block:32; /*     0: 0  4 */
+               u32                cycles_last_block:32; /*     0: 0  4 */
                u32                hle_abort:1;        /*     4:31  4 */
                u32                rtm_abort:1;        /*     4:30  4 */
                u32                instruction_abort:1; /*     4:29  4 */
$

Now btfdiff shows there are no differences, DWARF and BTF output produce
the same output, that matches the original struct.

The same tests were performed with vmlinux files produced by me and
Andrii.

Reported-by: Andrii Nakryiko <andriin@fb.com>
Reviewed-by: Andrii Nakryiko <andriin@fb.com>
Tested-by: Andrii Nakryiko <andriin@fb.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-25 16:49:10 -03:00
Andrii Nakryiko 6586e423d4 btf_loader: Fix bitfield fixup code
Existing code assumes alignment of any integer type, which breaks for
packed structs.

This patch fixes all the current discrepanies between dwarf and btf
loader, when compared using btfdiff.

It preserves bit_offset of non-bitfield members, while for bitfield ones
it re-calculates initial byte/bit offset using natural alignment of the
underlying integer type, which seems to be always the case for
bitfields.

I've tested this on toy examples for both x86-64 and arm targets, there
were no differences reported by btfdiff.

Testing on vmlinux on x86-64 shows only these discrepancies, which are
unrelated to bit offsets:

  $ ./btfdiff /tmp/vmlinux4
  --- /tmp/btfdiff.dwarf.GIVfpr   2019-02-20 12:18:29.138788970 -0800
  +++ /tmp/btfdiff.btf.c3x2KY     2019-02-20 12:18:29.351786365 -0800
  @@ -16884,7 +16884,7 @@ struct pebs_record_nhm {
   };
   union hsw_tsx_tuning {
          struct {
  -               unsigned int       cycles_last_block:32; /*     0: 0  4 */
  +               u32                cycles_last_block:32; /*     0: 0  4 */
                  u32                hle_abort:1;        /*     4:31  4 */
                  u32                rtm_abort:1;        /*     4:30  4 */
                  u32                instruction_abort:1; /*     4:29  4 */
  @@ -26154,7 +26154,7 @@ struct acpi_device_power {
          /* last cacheline: 40 bytes */
   };
   struct acpi_device_perf_flags {
  -       unsigned char              reserved:8;           /*     0: 0  1 */
  +       u8                         reserved:8;           /*     0: 0  1 */

          /* size: 1, cachelines: 1, members: 1 */
          /* last cacheline: 1 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:10:34 -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
Andrii Nakryiko 6bcf0bd703 btfdiff: Support specifying custom pahole location
During development it's convenient to be able to specify custom location
of pahole binary, built locally.

E.g.:

  $ PAHOLE=~/local/pahole/build/pahole ./btfdiff /tmp/vmlinux4

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:06:27 -03:00
Arnaldo Carvalho de Melo 88028b5d0c btfdiff: Use --show_private_classes with DWARF
In DWARF we have the information if a struct/class is defined only
inside another struct/class or in a function, and then we consider those
to be 'private classes', requiring the use of --show_private_classes to
see those when asking for all structs.

That is not the case with BTF, that doesn't have that info and thus
shows all structs, private or not.

So, to compare the outputs in btfdiff we need to ask for
--show_private_classes when printing from DWARF.

With the Linux kernel vmlinux file the only private structure noticed
when not using this option, i.e. the only private class, as 'struct
sun_disklabel', defined in the block/partitions/sun.c file, inside the
'sun_partition' function.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-02-19 11:04:44 -03:00
Andrii Nakryiko e6c59bd11d libbpf: Build as PIC and statically link into libdwarves
As libbpf is not yet widely available, it's safer to statically link it
into libdwarves for now. Easiest way to define that in cmake is through
OBJECT library with PIC.

Committer testing:

  $ file build/pahole
  build/pahole: 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]=666c97e5763ac0f4c5eff229be1532f1e60195e6, with debug_info, not stripped
  $ ldd build/pahole
	linux-vdso.so.1 (0x00007ffe5fdf8000)
	libdwarves_reorganize.so.1 => /home/acme/git/pahole/build/libdwarves_reorganize.so.1 (0x00007f1c84fa4000)
	libdwarves.so.1 => /home/acme/git/pahole/build/libdwarves.so.1 (0x00007f1c84f5e000)
	libdw.so.1 => /lib64/libdw.so.1 (0x00007f1c84eee000)
	libelf.so.1 => /lib64/libelf.so.1 (0x00007f1c84ed4000)
	libz.so.1 => /lib64/libz.so.1 (0x00007f1c84eba000)
	libc.so.6 => /lib64/libc.so.6 (0x00007f1c84cf4000)
	libdl.so.2 => /lib64/libdl.so.2 (0x00007f1c84cec000)
	liblzma.so.5 => /lib64/liblzma.so.5 (0x00007f1c84cc3000)
	libbz2.so.1 => /lib64/libbz2.so.1 (0x00007f1c84cb0000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f1c84fad000)
	libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f1c84c8e000)
  $

  $ nm build/libdwarves.so.1.0.0  | grep b[pt]f__
  0000000000028aae T btf__dedup
  0000000000027d44 T btf__fd
  0000000000027a37 T btf__find_by_name
  0000000000027ad9 T btf__free
  0000000000027da8 T btf__get_from_id
  0000000000027f6c T btf__get_map_kv_tids
  0000000000027739 T btf__get_nr_types
  0000000000027d55 T btf__get_raw_data
  0000000000027c2e T btf__load
  0000000000027d77 T btf__name_by_offset
  0000000000027b36 T btf__new
  00000000000277eb T btf__resolve_size
  0000000000027960 T btf__resolve_type
  000000000002774a T btf__type_by_id
  $

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Suggested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Wang Nan <wangnan0@huawei.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
Cc: kernel-team@fb.com
[ split from a larger patch ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-02-19 10:21:29 -03:00
Andrii Nakryiko cf4f3e282d cmake: Bump miminum required version to use OBJECT feature
We need to link with libbpf, that is not yet generally available, so we
need to link it into libdwarves for now, to do that we need to use the
OBJECT library with PIC, and that requires we use at least cmake version
2.8.8, so bump the minimum required cmake version.

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Wang Nan <wangnan0@huawei.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
Cc: kernel-team@fb.com
[ split from a larger patch ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-02-19 10:20:42 -03:00
Arnaldo Carvalho de Melo 5148be53dc btfdiff: Rename tmp files to contain the format used
So that one can comment the 'rm' line at the end to look at the files
further.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-02-18 11:05:29 -03:00
Andrii Nakryiko dd3a7d3ab3 btf_encoder: run BTF deduplication before writing out to ELF
After btf_encoder completes DWARF to BTF 0-to-1 conversion, utilize
libbpf to construct struct btf and run btf__dedup() algorithm on it.
This significantly reduces number of BTF types and strings section size
without losing any information.

Committer testing:

Before:

  $ cp ../build/v5.0-rc3+/vmlinux .
  $ ls -la vmlinux
  -rwxrwxr-x. 1 acme acme 654357792 Feb 18 10:51 vmlinux
  $ pahole -J vmlinux
  $ ls -la vmlinux
  -rwxrwxr-x. 1 acme acme 824950072 Feb 18 10:52 vmlinux
  $ echo $((824950072 - 654357792))
  170592280
  $
  $ readelf -SW vmlinux  | head -4
  There are 79 section headers, starting at offset 0x312ba978:

  Section Headers:
    [Nr] Name   Type      Address          Off      Size    ES Flg Lk Inf Al
  <SNIP>
    [78] .BTF   PROGBITS  0000000000000000 27053da9 a266bcd 00      0   0  1
    $
  >>> 0xa266bcd
  170290125

After:

  $ cp ../build/v5.0-rc3+/vmlinux .
  $ ls -la vmlinux
-rwxrwxr-x. 1 acme acme 654357792 Feb 18 11:01 vmlinux
  $ pahole -J vmlinux
  $ ls -la vmlinux
-rwxrwxr-x. 1 acme acme 656641544 Feb 18 11:01 vmlinux
  $ echo $((656641544 - 654357792))
2283752
  $ readelf -SW vmlinux  | grep BTF
  [78] .BTF              PROGBITS        0000000000000000 27053da9 1e3c9e 00      0   0  1
>>> 0x1e3c9e
1981598
>>>

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
Cc: kernel-team@fb.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-02-18 11:00:03 -03:00
Andrii Nakryiko 54106025cd libbtf: Fixup temp filename to .btf, not .btfe
Bug introduced when renaming pahole's 'struct btf' to 'struct btf_elf'.

Fixes: fe4e1f799c ("btf_elf: Rename btf_elf__free() to btf_elf__delete()")
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-02-18 10:58:12 -03:00
Andrii Nakryiko e6dfd10bcb libbpf: Build as shared lib
Change CMakeLists.txt to build libbpf as shared library to satisfy libdwarves
shared library compilation.

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
Cc: kernel-team@fb.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-02-18 09:57:51 -03:00
Andrii Nakryiko c234b6ca6e libbpf: Pull latest libbpf
Bring in latest changes from libbpf which allow to use btf__dedup() for
big binaries (e.g., linux kernel image).

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
Cc: kernel-team@fb.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-02-18 09:49:38 -03:00
Arnaldo Carvalho de Melo fe4e1f799c btf_elf: Rename btf_elf__free() to btf_elf__delete()
That is the idiom for free its members and then free itself, 'free' is
just to free its members.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-02-14 17:06:40 -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
Andrii Nakryiko ca86e9416b pahole: use btf.h directly from libbpf
Now that libbpf is a submodule, we don't need to copy/paste btf.h header
with BTF type definitions.

This is a first step in migrating parts of libbtf, btf_encoder and
btf_loader to use libbpf and starting to use btf__dedup().

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:57:06 -03:00
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