Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Pedro Alves <palves@redhat.com>
To: Sergio Durigan Junior <sergiodj@redhat.com>
Cc: Simon Marchi <simon.marchi@polymtl.ca>,
	Simon Marchi <simon.marchi@ericsson.com>,
	GDB Patches <gdb-patches@sourceware.org>,
	Tom Tromey <tom@tromey.com>, Eli Zaretskii <eliz@gnu.org>
Subject: Re: [PATCH v3 2/2] Implement pahole-like 'ptype /o' option
Date: Tue, 12 Dec 2017 20:12:00 -0000	[thread overview]
Message-ID: <d4a15247-ba80-6b31-b6f6-f9e2368357d1@redhat.com> (raw)
In-Reply-To: <87lgi7x00t.fsf@redhat.com>

On 12/12/2017 06:40 PM, Sergio Durigan Junior wrote:
> On Tuesday, December 12 2017, Pedro Alves wrote:
> 
>> On 12/12/2017 06:19 AM, Sergio Durigan Junior wrote:
>>
>>> Apparently the patch can't handle bitfields very well.  I've found a few
>>> cases where the bitfield handling gets confused, printing wrong
>>> offsets/sizes/holes.  Bitfields can be extremely complex to deal with
>>> when it comes to offsets...
>>>
>>> I spent hours trying to improve the patch, managed to make some
>>> progress, but there are still corner cases to fix.  For example, the
>>> patch doesn't deal well with this case:
>>>
>>> struct aa {                                    
>>> /*    0      |     1 */    char aa;            
>>> /*    1: 1   |     1 */    unsigned char a : 7;                                                
>>> /*    1:15   |     4 */    int b : 10;         
>>> } /* total size:    4 bytes */                 
>>>
>>> In this case, the bitfield "b" would be combined with the previous
>>> bitfield "a", like pahole reports:
>>>
>>> struct aa {                                    
>>>         char                       aa;                   /*     0     1 */                     
>>>         unsigned char              a:7;                  /*     1: 1  1 */                     
>>>
>>>         /* Bitfield combined with previous fields */                                           
>>>
>>>         int                        b:10;                 /*     0: 7  4 */                     
>>> }
>>>
>>> Confusing...  I'm not sure why pahole reports b's offset to be 0.
>>
>> 0 seems right to me.  The bitfield's type is int, with size 4,
>> and it lives at byte offset 0:
>>
>>  <2><53>: Abbrev Number: 5 (DW_TAG_member)
>>     <54>   DW_AT_name        : (indirect string, offset: 0x4ae): b
>>     <58>   DW_AT_decl_file   : 1
>>     <59>   DW_AT_decl_line   : 7
>>     <5a>   DW_AT_type        : <0x71>
>>     <5e>   DW_AT_byte_size   : 4
>>     <5f>   DW_AT_bit_size    : 10
>>     <60>   DW_AT_bit_offset  : 7
>>     <61>   DW_AT_data_member_location: 0     <<<
>>
>> Replacing the 0 with 1, like:
>>
>>     int                        b:10;                 /*     1: 7  4 */
>>
>> would look incorrect to me, because that'd make '(char*)&aa + 1 + 4'
>> (address of containing object + byte offset + byte size) overshoot the
>> size of the containing object.
> 
> OK.  The GDB patch is printing "1:15" because the offset is calculated
> as:
> 
>   (bitpos + offset_bitpos) / TARGET_CHAR_BIT
> 
> In this particular case, offset_bitpos is zero because we're not inside
> an inner struct, so we don't care about it.  bitpos is TYPE_FIELD_BITPOS
> (type, field_idx), which is 15 in this case, because sizeof (aa.aa) +
> bitsof (aa.a) = 15.  

Well, actually it's 15 because that's the bit number of the LSB of that
field, and x86 is a !gdbarch_bits_big_endian machine.  Because we have:

 <2><53>: Abbrev Number: 4 (DW_TAG_member)
    <54>   DW_AT_name        : b
    <56>   DW_AT_decl_file   : 1
    <57>   DW_AT_decl_line   : 7
    <58>   DW_AT_type        : <0x6f>
    <5c>   DW_AT_byte_size   : 4
    <5d>   DW_AT_bit_size    : 10
    <5e>   DW_AT_bit_offset  : 7
    <5f>   DW_AT_data_member_location: 0

and with that, we reach here:

static void
dwarf2_add_field (struct field_info *fip, struct die_info *die,
		  struct dwarf2_cu *cu)
{
...
      attr = dwarf2_attr (die, DW_AT_bit_offset, cu);
      if (attr)
	{
	  if (gdbarch_bits_big_endian (gdbarch))
	    {
...
	    }
	  else
	    {
...
	      attr = dwarf2_attr (die, DW_AT_byte_size, cu);
	      if (attr)
		{
		  /* The size of the anonymous object containing
		     the bit field is explicit, so use the
		     indicated size (in bytes).  */
		  anonymous_size = DW_UNSND (attr);
		}
	      else
		{
...
		}
	      SET_FIELD_BITPOS (*fp,
				(FIELD_BITPOS (*fp)
				 + anonymous_size * bits_per_byte
				 - bit_offset - FIELD_BITSIZE (*fp)));
	    }
	}

which gives us:

  bitpos = DW_AT_byte_size * 8 - DW_AT_bit_offset - DW_AT_bit_size
         = 4 * 8 - 7 - 10
         = 15

and since x86 is a !gdbarch_bits_big_endian machine, 15 goes here:

 byte:  0     1      2      3
 bits:  7-0   15-8   23-16   31-24
              ^

which is what we see if we write a "1" to aa.b:

 (gdb) p aa.b = 1
 $1 = 1
 (gdb) x /4xb &aa
 0x60103c <aa>:  0x00    0x80    0x00    0x00
                         ^^^^

> When we divide it by TARGET_CHAR_BIT, we get 1.  It
> seems using TYPE_FIELD_BITPOS is not reliable when dealing with
> bitfields.

I noticed:

 (gdb) p /x & aa.aa
 $1 = 0x601040
 (gdb) p /x & aa.a
 $2 = 0x601041
 (gdb) p /x & aa.b
 $3 = 0x601040
 (gdb) 

Ignoring the fact that taking the address of bitfields is
not valid C/C++ [ :-) ], it seems like the addresses above
match what we'd expect the byte offset to be.  At least for this
example.

So maybe what you need is to factor out or duplicate the logic
used by the related value printing code.  Here in
value_primitive_field:

  if (TYPE_FIELD_BITSIZE (arg_type, fieldno))
    {
      /* Handle packed fields.

...
      LONGEST bitpos = TYPE_FIELD_BITPOS (arg_type, fieldno);
      LONGEST container_bitsize = TYPE_LENGTH (type) * 8;

      v = allocate_value_lazy (type);
      v->bitsize = TYPE_FIELD_BITSIZE (arg_type, fieldno);
      if ((bitpos % container_bitsize) + v->bitsize <= container_bitsize
	  && TYPE_LENGTH (type) <= (int) sizeof (LONGEST))
	v->bitpos = bitpos % container_bitsize;
      else
	v->bitpos = bitpos % 8;
      v->offset = (value_embedded_offset (arg1)
		   + offset
		   + (bitpos - v->bitpos) / 8);
    }

Above "v->offset" may be the byte offset that you're after.

> 
> So there is something I'm not accounting here.
> 

>> What is that number after ":"  in bitfields supposed to mean in
>> pahole's output (and I assume that that's what you're trying
>> to emulate)?  We're missing documentation for that.
> 
> Yeah.  I tried to find documentation on the output, but couldn't.
> Yesterday I was reading pahole's code.  From what I understand, it is
> the number of bits left in the object.
> 
>> It seems like it's supposed to mean the number of bits left in the
>> containing anonymous object (i.e., in the 4 bytes of the declared
>> int)?  Then "0:7" seems right, given:
>>
>> sizeof (int) * 8 - bitsof(aa.a) - bitsof(aa.a) - bits(aa.b)
>>    => sizeof (int) * 8 - 7 - 10 
>>    => 7
> 
> I guess you meant:
> 
>   sizeof (int) * 8 - bitsof (aa.a) - bitsof(aa.b)

No, because that's be

     => 32 - 7 - 10
     => 15

I meant:

 sizeof (int) * 8 - bitsof(aa.aa) - bitsof(aa.a) - bits(aa.b)
    => sizeof (int) * 8 - 8 - 7 - 10 
    => 7

which gives us the 7 unused bits that pahole reports.

> 
> Right?
> 
> But yeah, it makes sense when you consider that the first bitfield got
> "promoted" from "unsigned char" to "int".  I haven't figured out a way
> to keep track of these type changes in order to calculate the right
> offsets, remaining space and holes.

Do we really need to track type changes, or do we simply need to
detect that the byte offset moved in the negative direction?
I.e., here:

struct S {                                    
        char                       aa;                   /*     0     1 */                     
        unsigned char              a:7;                  /*     1: 1  1 */                     

        /* Bitfield combined with previous fields */                                           

        int                        b:10;                 /*     0: 7  4 */                     
};

The byte offset went "0 -> 1 -> 0", and the "1 -> 0" would mean that the
bitfield was "combined"?

Thanks,
Pedro Alves


  reply	other threads:[~2017-12-12 20:12 UTC|newest]

Thread overview: 75+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-11-21 16:07 [PATCH] " Sergio Durigan Junior
2017-11-21 16:16 ` Sergio Durigan Junior
2017-11-21 16:50 ` Eli Zaretskii
2017-11-21 17:00   ` Sergio Durigan Junior
2017-11-21 19:14     ` Eli Zaretskii
2017-11-26 19:27 ` Tom Tromey
2017-11-27 19:54   ` Sergio Durigan Junior
2017-11-27 22:20     ` Tom Tromey
2017-11-28  0:39       ` Sergio Durigan Junior
2017-11-28 21:21 ` [PATCH v2] " Sergio Durigan Junior
2017-11-29  3:28   ` Eli Zaretskii
2017-12-04 15:03   ` Sergio Durigan Junior
2017-12-04 15:41     ` Eli Zaretskii
2017-12-04 16:47       ` Sergio Durigan Junior
2017-12-08 21:32     ` Sergio Durigan Junior
2017-12-11 15:43   ` Simon Marchi
2017-12-11 18:59     ` Sergio Durigan Junior
2017-12-11 20:45       ` Simon Marchi
2017-12-11 21:07         ` Sergio Durigan Junior
2017-12-11 22:42           ` Pedro Alves
2017-12-11 22:50             ` Sergio Durigan Junior
2017-12-11 23:46               ` Pedro Alves
2017-12-12  0:25                 ` Sergio Durigan Junior
2017-12-12  0:52                   ` Pedro Alves
2017-12-12  1:25                     ` Simon Marchi
2017-12-12 15:50                       ` John Baldwin
2017-12-12 17:04                         ` Sergio Durigan Junior
2017-12-11 19:58 ` [PATCH v3 0/2] Implement pahole-like 'ptype /o' option (and do some code reorg) Sergio Durigan Junior
2017-12-11 19:58   ` [PATCH v3 2/2] Implement pahole-like 'ptype /o' option Sergio Durigan Junior
2017-12-11 21:50     ` Simon Marchi
2017-12-11 23:24       ` Sergio Durigan Junior
2017-12-12  1:32         ` Simon Marchi
2017-12-12  6:19           ` Sergio Durigan Junior
2017-12-12 18:14             ` Pedro Alves
2017-12-12 18:40               ` Sergio Durigan Junior
2017-12-12 20:12                 ` Pedro Alves [this message]
2017-12-11 19:58   ` [PATCH v3 1/2] Reorganize code to handle TYPE_CODE_{STRUCT,UNION} on 'c_type_print_base' Sergio Durigan Junior
2017-12-11 20:55     ` Simon Marchi
2017-12-11 23:05       ` Sergio Durigan Junior
2017-12-11 23:43 ` [PATCH v4 0/2] Implement pahole-like 'ptype /o' option (and do some code reorg) Sergio Durigan Junior
2017-12-11 23:44   ` [PATCH v4 2/2] Implement pahole-like 'ptype /o' option Sergio Durigan Junior
2017-12-12  0:27     ` Sergio Durigan Junior
2017-12-12  0:29       ` Sergio Durigan Junior
2017-12-12  1:59     ` Simon Marchi
2017-12-12  3:39     ` Eli Zaretskii
2017-12-11 23:44   ` [PATCH v4 1/2] Reorganize code to handle TYPE_CODE_{STRUCT,UNION} on 'c_type_print_base' Sergio Durigan Junior
2017-12-13  3:17 ` [PATCH v5 0/2] Implement pahole-like 'ptype /o' option (and do some code reorg) Sergio Durigan Junior
2017-12-13  3:17   ` [PATCH v5 1/2] Reorganize code to handle TYPE_CODE_{STRUCT,UNION} on 'c_type_print_base' Sergio Durigan Junior
2017-12-13  3:17   ` [PATCH v5 2/2] Implement pahole-like 'ptype /o' option Sergio Durigan Junior
2017-12-13  4:50     ` Simon Marchi
2017-12-13 16:42       ` Sergio Durigan Junior
2017-12-13 16:17     ` Eli Zaretskii
2017-12-13 17:14       ` Sergio Durigan Junior
2017-12-13 16:19     ` Pedro Alves
2017-12-13 17:13       ` Sergio Durigan Junior
2017-12-13 20:36         ` Sergio Durigan Junior
2017-12-13 21:22           ` Pedro Alves
2017-12-13 21:30             ` Pedro Alves
2017-12-13 21:34             ` Sergio Durigan Junior
2017-12-13 16:20     ` Pedro Alves
2017-12-13 17:41       ` Sergio Durigan Junior
2017-12-14  2:48 ` [PATCH v6 0/2] Implement pahole-like 'ptype /o' option (and do some code reorg) Sergio Durigan Junior
2017-12-14  2:48   ` [PATCH v6 1/2] Reorganize code to handle TYPE_CODE_{STRUCT,UNION} on 'c_type_print_base' Sergio Durigan Junior
2017-12-14  2:48   ` [PATCH v6 2/2] Implement pahole-like 'ptype /o' option Sergio Durigan Junior
2017-12-14 14:19     ` Pedro Alves
2017-12-14 20:31       ` Sergio Durigan Junior
2017-12-14 14:50     ` Pedro Alves
2017-12-14 20:29       ` Sergio Durigan Junior
2017-12-14 16:30     ` Eli Zaretskii
2017-12-15  1:12 ` [PATCH v7 0/2] Implement pahole-like 'ptype /o' option (and do some code reorg) Sergio Durigan Junior
2017-12-15  1:12   ` [PATCH v7 1/2] Reorganize code to handle TYPE_CODE_{STRUCT,UNION} on 'c_type_print_base' Sergio Durigan Junior
2017-12-15  1:13   ` [PATCH v7 2/2] Implement pahole-like 'ptype /o' option Sergio Durigan Junior
2017-12-15 17:24     ` Pedro Alves
2017-12-15 20:04       ` Sergio Durigan Junior
2017-12-15 20:11   ` [PATCH v7 0/2] Implement pahole-like 'ptype /o' option (and do some code reorg) Sergio Durigan Junior

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=d4a15247-ba80-6b31-b6f6-f9e2368357d1@redhat.com \
    --to=palves@redhat.com \
    --cc=eliz@gnu.org \
    --cc=gdb-patches@sourceware.org \
    --cc=sergiodj@redhat.com \
    --cc=simon.marchi@ericsson.com \
    --cc=simon.marchi@polymtl.ca \
    --cc=tom@tromey.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox