Re: Differences in pahole output from BTF versus from DWARF

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Em Mon, Jan 14, 2019 at 10:06:11PM +0000, Yonghong Song escreveu:
> On 1/14/19 10:13 AM, Arnaldo Carvalho de Melo wrote:
> > Em Mon, Jan 14, 2019 at 04:55:42PM +0000, Yonghong Song escreveu:
> >> On 1/14/19 6:27 AM, Arnaldo Carvalho de Melo wrote:
> > Which ends up producing this output, that still has stuff to do wrt the
> > hole/padding calculations, but has the offset adjusted to that '30'
> > value instead of showing -1:
> > 
> > [acme@quaco pahole]$ pahole examples/yonghong/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:30  4 */
> 
> The y2 should be "4:30"?

So, I kept that patch and added another hunk, the first one here:

diff --git a/dwarves_fprintf.c b/dwarves_fprintf.c
index bd46f97916fc..39f96318625e 100644
--- a/dwarves_fprintf.c
+++ b/dwarves_fprintf.c
@@ -753,6 +753,9 @@ static size_t class_member__fprintf(struct class_member *member, bool union_memb
 			sconf.base_offset = offset;
 	}
 
+	if (member->bitfield_offset < 0)
+		offset += member->byte_size;
+
 	if (!conf->suppress_comments)
 		printed_cacheline = class__fprintf_cacheline_boundary(conf, offset, fp);
 
@@ -807,9 +810,14 @@ static size_t class_member__fprintf(struct class_member *member, bool union_memb
 					   offset);
 
 			if (member->bitfield_size != 0) {
+				unsigned int bitfield_offset = member->bitfield_offset;
+
+				if (member->bitfield_offset < 0)
+					bitfield_offset = member->byte_size * 8 + member->bitfield_offset;
+
 				printed += fprintf(fp, sconf.hex_fmt ?
 							":%#2x" : ":%2u",
-						   member->bitfield_offset);
+						   bitfield_offset);
 				size_spacing -= 3;
 			}

With it we get what you suggested:

[acme@quaco pahole]$ pahole examples/yonghong/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 */
};
[acme@quaco pahole]$ 

And, if I use a cross compiler to build a big endian .o:

[acme@quaco ~]$ dsh ubuntu:18.04-x-powerpc
perfbuilder@47aa4489b67f:/git/pahole$ powerpc-linux-gnu-gcc -O2 -g -c examples/yonghong/packed_bitfield.c -o /git/tmp/packed_bitfield.powerpc.o
perfbuilder@47aa4489b67f:/git/pahole$ exit

The one for x86_64:

[acme@quaco pahole]$ file examples/yonghong/packed_bitfield.o
examples/yonghong/packed_bitfield.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), with debug_info, not stripped

For powerpc:

[acme@quaco pahole]$ 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
[acme@quaco pahole]$ 

[acme@quaco pahole]$ 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 */
};
[acme@quaco pahole]$

And with sparc64:

[acme@quaco ~]$ dsh ubuntu:18.04-x-sparc64
perfbuilder@1ded5e9c526a:/git/pahole$ sparc64-linux-gnu-gcc -O2 -g -c examples/yonghong/packed_bitfield.c -o /git/tmp/packed_bitfield.sparc64.o
perfbuilder@1ded5e9c526a:/git/pahole$ exit

[acme@quaco pahole]$ 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
[acme@quaco pahole]$ 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 */
};
[acme@quaco pahole]$ 

Seems to work?

Now need to tackle the holes calculations.
 
> This is how I interpret the above:
> 
>  > 	char                       x1:1;                 /*     0: 7  1 */
> 
>     ==> this will convert to big endian offset 0, size 1
>     ==> offset = sizeof(char) - 7 - 1
> 
>  > 	char                       x2:3;                 /*     0: 4  1 */
>     ===> this will convert to big endian offset 1, size 3
>     ===> offset = sizeof(char) - 4 - 3
> 
>  > 	char                       x3:3;                 /*     0: 1  1 */
>     ===> this will convert to big endian offset 4, size 3
>     ===> offset = sizeof(char) - 1 - 3
> 
>  > 	int                        y1:7;                 /*     0:18  4 */
>     ===> this will convert to big endian offset 7, size 7
>     ===> offset = sizeof(int) - 18 - 7 = 7
>  > 	int                        y2:20;                /*     4:30  4 */
>     ===> this will convert to big endian offset 14, size 20
>     ===> offset = 4 * 8 + sizeof(int) - 30 - 20 = 14
> 
> 
> > 
> > 	/* 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 */
> > };
> > [acme@quaco pahole]$
> > 
> > The following drawing _tries_ to paint this picture according to the
> > description you gave for negative bit_offsets, butthen it would be 8
> > bytes, the size of the struct is 5 bytes, sizeof(char) + sizeof(int),
> > and since the sum of the bit sizes is 34 bits, we need 5 bytes.
> > 
> >             x     x
> >           + 3 + + 2 + x1     +---- y2 ---+  +-- y2 --+
> >           |   | |   | |      |           |  |        |
> >           V   V V   V V      V           V  V        V
> >        [0 1 2 3 4 5 6 7 ... 30 31][0 .. 17 18 ..... 24 .. 31]
> 
> With packing, the elements layout may not be similar to the above.
> 
> It probably likes below (I have a C program later):
> 
>    => memory increasing
> bits
>    0  1 2  3 4 5  6 7 8 9 10 11 12 13 14 15 16 17 ... 30 31 32 33 34 ...
>    x1 | x2 | | x3 | |    y1         |  |          y2            |
> 
> In little representation, the following looks like the case:
>   x1: byte0, bit 7
>   x2: byte0, bit 4 - 6
>   x3: byte0, bit 1 - 3
>   y1: byte0, bit 0 and byte1, bit 2 - 7.
>   y2: byte1, bit 0 - 1, and byte 2, 3, and byte4 6 -7.
> 
> So there is no wasted bits. In the above your diagram, there are
> some wasted bits.
> 
> I didn't check exactly how the little endian DW attributes are computed
> inside the compiler for the packed case. But one way to do it is
>     - do a big endian bit offset/size assignment first. This should be
>       straight forward.
>     - convert to the little endian offset based on the corresponding
>       field type and big endian field offset/type.
> 
> -bash-4.4$ cat t2.c
> #include <stdio.h>
> 
> struct packed {
>      char x1: 1;
>      char x2: 3;
>      char x3: 3;
>      int y1: 7;
>      int y2: 20;
> } __attribute__((packed));
> 
> int main() {
>    struct packed p;
>    int i;
> 
>    p.x1 = 1;
>    p.x2 = 0;
>    p.x3 = 2;
>    p.y1 = 7 << 2;
>    p.y2 = (1 << 18) + 3;
> 
>    for (i = 0; i < sizeof(p); i++)
>      printf("i = %x\n", *(((unsigned char *)&p) + i));
> 
>    return 0;
> }
> -bash-4.4$ gcc t2.c
> -bash-4.4$ ./a.out
> i = 21
> i = ce
> i = 0
> i = 0
> i = fd
> -bash-4.4$
> 
> > 
> > Doesn't make sense, we don't have 64 bits, just 40.
> > 
> > Can you hand hold me here? :-)
> >   
> >>> seeing negative DW_AT_bit_offsets we should think it starts in this
> >>> location (0 in this case), but straddles to the next, so I should say
> >>> that it is at bit offset (DW_AT_byte_size * 8 - DW_AT_bit_offset), the
> >>> user, looking at this new pahole output will realize that it has 2 bits
> >>> at the end of the current DW_AT_data_member_location (0) but has 18 bits
> >>> in the next.
> >>>
> >>>
> >>>> (2). the -2 means the the starting bit is at the "4" byte boundary - 2
> >>>> bits. So basically it covers:
> >>>>
> >>>>                  |           |
> >>>>                  V           V
> >>>>       [0 1 .....30 31][0 .. 17 18 ... 31]
> >>>>
> >>>> totally 20 bits.
> >>>>
> >>>> The following patch fixed the issue:
> >>>> -bash-4.4$ git diff
> >>>> diff --git a/dwarves.h b/dwarves.h
> >>>> index e6bffe8..e5f8347 100644
> >>>> --- a/dwarves.h
> >>>> +++ b/dwarves.h
> >>>> @@ -831,7 +831,7 @@ struct class_member {
> >>>>            uint32_t         bit_size;
> >>>>            uint32_t         byte_offset;
> >>>>            size_t           byte_size;
> >>>> -       uint8_t          bitfield_offset;
> >>>> +       int8_t           bitfield_offset;
> >>>>            uint8_t          bitfield_size;
> >>>>            uint8_t          bit_hole;
> >>>>            uint8_t          bitfield_end:1;
> >>>> -bash-4.4$
> >>>>
> >>>> With the above change:
> >>>> -bash-4.4$ ~/work/github/pahole/build/pahole -JV bitfields.o
> >>>> File bitfields.o:
> >>>> [1] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
> >>>> [2] STRUCT packed kind_flag=1 size=5 vlen=5
> >>>>            x1 type_id=3 bitfield_size=1 bits_offset=0
> >>>>            x2 type_id=3 bitfield_size=3 bits_offset=1
> >>>>            x3 type_id=3 bitfield_size=3 bits_offset=4
> >>>>            y1 type_id=1 bitfield_size=7 bits_offset=7
> >>>>            y2 type_id=1 bitfield_size=20 bits_offset=14
> >>>> [3] INT char size=1 bit_offset=0 nr_bits=8 encoding=(none)
> >>>> [4] STRUCT unpacked kind_flag=1 size=8 vlen=5
> >>>>            x1 type_id=3 bitfield_size=1 bits_offset=0
> >>>>            x2 type_id=3 bitfield_size=3 bits_offset=1
> >>>>            x3 type_id=3 bitfield_size=3 bits_offset=4
> >>>>            y1 type_id=1 bitfield_size=7 bits_offset=7
> >>>>            y2 type_id=1 bitfield_size=20 bits_offset=32
> >>>> [5] UNION packed_union kind_flag=0 size=8 vlen=4
> >>>>            x1 type_id=3 bits_offset=0
> >>>>            y2 type_id=1 bits_offset=0
> >>>>            s1 type_id=2 bits_offset=0
> >>>>            s2 type_id=4 bits_offset=0
> >>>> [6] UNION unpacked_union kind_flag=0 size=8 vlen=3
> >>>>            x1 type_id=3 bits_offset=0
> >>>>            y2 type_id=1 bits_offset=0
> >>>>            s type_id=4 bits_offset=0
> >>>> -bash-4.4$
> >>>>
> >>>> Will send out a patch shortly.
> >>>>
> >>>>>
> >>>>> andriin@devvm$ cat bitfields.c
> >>>>> struct unpacked{
> >>>>>        char x1: 1;
> >>>>>        char x2: 3;
> >>>>>        char x3: 3;
> >>>>>        int y1: 7;
> >>>>>        int y2: 20;
> >>>>> };
> >>>>>
> >>>>> struct packed{
> >>>>>        char x1: 1;
> >>>>>        char x2: 3;
> >>>>>        char x3: 3;
> >>>>>        int y1: 7;
> >>>>>        int y2: 20;
> >>>>> } __attribute__((packed));
> >>>>>
> >>>>> union packed_union {
> >>>>>        char x1;
> >>>>>        int y2;
> >>>>>        struct packed s1;
> >>>>>        struct unpacked s2;
> >>>>> };
> >>>>>
> >>>>> union unpacked_union {
> >>>>>        char x1;
> >>>>>        int y2;
> >>>>>        struct unpacked s;
> >>>>> } __attribute__((packed));
> >>>>>
> >>>>> int main() {
> >>>>>        struct packed s1;
> >>>>>        struct unpacked s2;
> >>>>>        union packed_union u1;
> >>>>>        union unpacked_union u2;
> >>>>>        return 0;
> >>>>> }
> >>>>> andriin@devvm$ cc -g bitfields.c -o bitfields
> >>>>> andriin@devvm$ LLVM_OBJCOPY=objcopy ~/local/pahole/build/pahole -JV bitfields
> >>>>> File bitfields:
> >>>>> [1] STRUCT unpacked kind_flag=1 size=8 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=32
> >>>>> [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
> >>>>> [4] 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
> >>>>> [5] UNION packed_union kind_flag=0 size=8 vlen=4
> >>>>>            x1 type_id=2 bits_offset=0
> >>>>>            y2 type_id=3 bits_offset=0
> >>>>>            s1 type_id=4 bits_offset=0
> >>>>>            s2 type_id=1 bits_offset=0
> >>>>> [6] UNION unpacked_union kind_flag=0 size=8 vlen=3
> >>>>>            x1 type_id=2 bits_offset=0
> >>>>>            y2 type_id=3 bits_offset=0
> >>>>>            s type_id=1 bits_offset=0
> >>>>> andriin@devvm$ readelf -wi bitfields
> >>>>> Contents of the .debug_info section:
> >>>>>
> >>>>> ...
> >>>>>
> >>>>>     <1><2d>: Abbrev Number: 2 (DW_TAG_structure_type)
> >>>>>        <2e>   DW_AT_name        : (indirect string, offset: 0x4e): unpacked
> >>>>>        <32>   DW_AT_byte_size   : 8
> >>>>>        <33>   DW_AT_decl_file   : 1
> >>>>>        <34>   DW_AT_decl_line   : 1
> >>>>>        <35>   DW_AT_sibling     : <0x80>
> >>>>>     <2><39>: Abbrev Number: 3 (DW_TAG_member)
> >>>>>        <3a>   DW_AT_name        : x1
> >>>>>        <3d>   DW_AT_decl_file   : 1
> >>>>>        <3e>   DW_AT_decl_line   : 2
> >>>>>        <3f>   DW_AT_type        : <0x80>
> >>>>>        <43>   DW_AT_byte_size   : 1
> >>>>>        <44>   DW_AT_bit_size    : 1
> >>>>>        <45>   DW_AT_bit_offset  : 7
> >>>>>        <46>   DW_AT_data_member_location: 0
> >>>>>     <2><47>: Abbrev Number: 3 (DW_TAG_member)
> >>>>>        <48>   DW_AT_name        : x2
> >>>>>        <4b>   DW_AT_decl_file   : 1
> >>>>>        <4c>   DW_AT_decl_line   : 3
> >>>>>        <4d>   DW_AT_type        : <0x80>
> >>>>>        <51>   DW_AT_byte_size   : 1
> >>>>>        <52>   DW_AT_bit_size    : 3
> >>>>>        <53>   DW_AT_bit_offset  : 4
> >>>>>        <54>   DW_AT_data_member_location: 0
> >>>>>     <2><55>: Abbrev Number: 3 (DW_TAG_member)
> >>>>>        <56>   DW_AT_name        : x3
> >>>>>        <59>   DW_AT_decl_file   : 1
> >>>>>        <5a>   DW_AT_decl_line   : 4
> >>>>>        <5b>   DW_AT_type        : <0x80>
> >>>>>        <5f>   DW_AT_byte_size   : 1
> >>>>>        <60>   DW_AT_bit_size    : 3
> >>>>>        <61>   DW_AT_bit_offset  : 1
> >>>>>        <62>   DW_AT_data_member_location: 0
> >>>>>     <2><63>: Abbrev Number: 3 (DW_TAG_member)
> >>>>>        <64>   DW_AT_name        : y1
> >>>>>        <67>   DW_AT_decl_file   : 1
> >>>>>        <68>   DW_AT_decl_line   : 5
> >>>>>        <69>   DW_AT_type        : <0x87>
> >>>>>        <6d>   DW_AT_byte_size   : 4
> >>>>>        <6e>   DW_AT_bit_size    : 7
> >>>>>        <6f>   DW_AT_bit_offset  : 18
> >>>>>        <70>   DW_AT_data_member_location: 0
> >>>>>     <2><71>: Abbrev Number: 3 (DW_TAG_member)
> >>>>>        <72>   DW_AT_name        : y2
> >>>>>        <75>   DW_AT_decl_file   : 1
> >>>>>        <76>   DW_AT_decl_line   : 6
> >>>>>        <77>   DW_AT_type        : <0x87>
> >>>>>        <7b>   DW_AT_byte_size   : 4
> >>>>>        <7c>   DW_AT_bit_size    : 20
> >>>>>        <7d>   DW_AT_bit_offset  : 12
> >>>>>        <7e>   DW_AT_data_member_location: 4
> >>>>>     <2><7f>: Abbrev Number: 0
> >>>>>     <1><80>: Abbrev Number: 4 (DW_TAG_base_type)
> >>>>>        <81>   DW_AT_byte_size   : 1
> >>>>>        <82>   DW_AT_encoding    : 6        (signed char)
> >>>>>        <83>   DW_AT_name        : (indirect string, offset: 0xb3): char
> >>>>>     <1><87>: Abbrev Number: 5 (DW_TAG_base_type)
> >>>>>        <88>   DW_AT_byte_size   : 4
> >>>>>        <89>   DW_AT_encoding    : 5        (signed)
> >>>>>        <8a>   DW_AT_name        : int
> >>>>>     <1><8e>: Abbrev Number: 2 (DW_TAG_structure_type)
> >>>>>        <8f>   DW_AT_name        : (indirect string, offset: 0x50): packed
> >>>>>        <93>   DW_AT_byte_size   : 5
> >>>>>        <94>   DW_AT_decl_file   : 1
> >>>>>        <95>   DW_AT_decl_line   : 9
> >>>>>        <96>   DW_AT_sibling     : <0xe1>
> >>>>>     <2><9a>: Abbrev Number: 3 (DW_TAG_member)
> >>>>>        <9b>   DW_AT_name        : x1
> >>>>>        <9e>   DW_AT_decl_file   : 1
> >>>>>        <9f>   DW_AT_decl_line   : 10
> >>>>>        <a0>   DW_AT_type        : <0x80>
> >>>>>        <a4>   DW_AT_byte_size   : 1
> >>>>>        <a5>   DW_AT_bit_size    : 1
> >>>>>        <a6>   DW_AT_bit_offset  : 7
> >>>>>        <a7>   DW_AT_data_member_location: 0
> >>>>>     <2><a8>: Abbrev Number: 3 (DW_TAG_member)
> >>>>>        <a9>   DW_AT_name        : x2
> >>>>>        <ac>   DW_AT_decl_file   : 1
> >>>>>        <ad>   DW_AT_decl_line   : 11
> >>>>>        <ae>   DW_AT_type        : <0x80>
> >>>>>        <b2>   DW_AT_byte_size   : 1
> >>>>>        <b3>   DW_AT_bit_size    : 3
> >>>>>        <b4>   DW_AT_bit_offset  : 4
> >>>>>        <b5>   DW_AT_data_member_location: 0
> >>>>>     <2><b6>: Abbrev Number: 3 (DW_TAG_member)
> >>>>>        <b7>   DW_AT_name        : x3
> >>>>>        <ba>   DW_AT_decl_file   : 1
> >>>>>        <bb>   DW_AT_decl_line   : 12
> >>>>>        <bc>   DW_AT_type        : <0x80>
> >>>>>        <c0>   DW_AT_byte_size   : 1
> >>>>>        <c1>   DW_AT_bit_size    : 3
> >>>>>        <c2>   DW_AT_bit_offset  : 1
> >>>>>        <c3>   DW_AT_data_member_location: 0
> >>>>>     <2><c4>: Abbrev Number: 3 (DW_TAG_member)
> >>>>>        <c5>   DW_AT_name        : y1
> >>>>>        <c8>   DW_AT_decl_file   : 1
> >>>>>        <c9>   DW_AT_decl_line   : 13
> >>>>>        <ca>   DW_AT_type        : <0x87>
> >>>>>        <ce>   DW_AT_byte_size   : 4
> >>>>>        <cf>   DW_AT_bit_size    : 7
> >>>>>        <d0>   DW_AT_bit_offset  : 18
> >>>>>        <d1>   DW_AT_data_member_location: 0
> >>>>>     <2><d2>: Abbrev Number: 6 (DW_TAG_member)
> >>>>>        <d3>   DW_AT_name        : y2
> >>>>>        <d6>   DW_AT_decl_file   : 1
> >>>>>        <d7>   DW_AT_decl_line   : 14
> >>>>>        <d8>   DW_AT_type        : <0x87>
> >>>>>        <dc>   DW_AT_byte_size   : 4
> >>>>>        <dd>   DW_AT_bit_size    : 20
> >>>>>        <de>   DW_AT_bit_offset  : -2
> >>>>>        <df>   DW_AT_data_member_location: 0
> >>>>>     <2><e0>: Abbrev Number: 0
> >>>>>
> >>>>> ...
> >>>>>
> >>>
> > 

-- 

- Arnaldo



[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux