On 4/11/24 13:40, Indu Bhagat wrote:
> On 4/11/24 11:53, David Faust wrote:
>> This patch fixes an issue with mangled BTF that could occur when
>> a struct type contains a bitfield member which cannot be represented
>> in BTF.  It is undefined what should happen in such cases, but we can
>> at least do something reasonable.
>>
>> Commit
>>
>>    936dd627cd9 "btf: do not skip members of data type with type id
>>    BTF_VOID_TYPEID"
>>
>> made a similar change for un-representable non-bitfield members, but
>> had an unintended side-effect of mangling BTF for un-representable
>> bitfields: the struct (or union) would account for the offending
>> bitfield in its member count but the bitfield member itself was
>> not emitted, making the member count incorrect.
>>
>> This change ensures that non-representable bitfield members of struct
>> and union types are always emitted with BTF_VOID_TYPEID.  This avoids
>> corrupting the BTF information for the entire struct or union type.
>>
>> Tested on x86_64-linux-gnu and x86_64-linux-gnu host for
>> bpf-unknown-none target.
>>
> 
> Hi David,
> 
> Thanks for fixing this.  One comment below.
> 
>> gcc/
>>      * btfout.cc (btf_asm_sou_member): Always emit non-representable
>>      bitfield members as having 'void' type.  Refactor slightly.
>>
>> gcc/testsuite/
>>      * gcc.dg/debug/btf/btf-bitfields-4.c: Add two new checks.
>> ---
>>   gcc/btfout.cc                                 | 48 +++++++++----------
>>   .../gcc.dg/debug/btf/btf-bitfields-4.c        |  2 +
>>   2 files changed, 25 insertions(+), 25 deletions(-)
>>
>> diff --git a/gcc/btfout.cc b/gcc/btfout.cc
>> index ab491f0297f..e1ada41b1f4 100644
>> --- a/gcc/btfout.cc
>> +++ b/gcc/btfout.cc
>> @@ -922,41 +922,39 @@ static void
>>   btf_asm_sou_member (ctf_container_ref ctfc, ctf_dmdef_t * dmd, unsigned 
>> int idx)
>>   {
>>     ctf_dtdef_ref ref_type = ctfc->ctfc_types_list[dmd->dmd_type];
>> +  ctf_id_t base_type = get_btf_id (dmd->dmd_type);
>> +  uint64_t sou_offset = dmd->dmd_offset;
>> +
>> +  dw2_asm_output_data (4, dmd->dmd_name_offset,
>> +                   "MEMBER '%s' idx=%u",
>> +                   dmd->dmd_name, idx);
>>   
>>     /* Re-encode bitfields to BTF representation.  */
>>     if (CTF_V2_INFO_KIND (ref_type->dtd_data.ctti_info) == CTF_K_SLICE)
>>       {
>> -      ctf_id_t base_type = ref_type->dtd_u.dtu_slice.cts_type;
>>         unsigned short word_offset = ref_type->dtd_u.dtu_slice.cts_offset;
>>         unsigned short bits = ref_type->dtd_u.dtu_slice.cts_bits;
>> -      uint64_t sou_offset = dmd->dmd_offset;
>> -
>> -      /* Pack the bit offset and bitfield size together.  */
>> -      sou_offset += word_offset;
>>   
>> -      /* If this bitfield cannot be represented, do not output anything.
>> -     The parent struct/union 'vlen' field has already been updated.  */
>>         if ((bits > 0xff) || (sou_offset > 0xffffff))
> 
> Why dont we reuse the btf_dmd_representable_bitfield_p () function here?
> 
> This one here checks for sou_off > 0xffffff, while that in 
> btf_dmd_representable_bitfield_p checks for sou_offset + word_offset > 
> 0xffffff.  The latter is more precise.

Oops. Good catch. We should be doing the same check here, but I moved
the sou_offset += word_offset into the else below, so the word_offset
isn't included.

I avoided using btf_dmd_representable_bitfield_p only because it does
some redundant work. Clearly that was a bad idea :D

Will use btf_dmd_representable_bitfield_p in v2 so we can keep these
checks contained.

> 
> 
>> -    return;
>> -
>> -      sou_offset &= 0x00ffffff;
>> -      sou_offset |= ((bits & 0xff) << 24);
>> +    {
>> +      /* Bitfield cannot be represented in BTF.  Emit the member as having
>> +         'void' type.  */
>> +      base_type = BTF_VOID_TYPEID;
>> +    }
>> +      else
>> +    {
>> +      /* Pack the bit offset and bitfield size together.  */
>> +      sou_offset += word_offset;
>> +      sou_offset &= 0x00ffffff;
>> +      sou_offset |= ((bits & 0xff) << 24);
>>   
>> -      dw2_asm_output_data (4, dmd->dmd_name_offset,
>> -                       "MEMBER '%s' idx=%u",
>> -                       dmd->dmd_name, idx);
>> -      /* Refer to the base type of the slice.  */
>> -      btf_asm_type_ref ("btm_type", ctfc, get_btf_id (base_type));
>> -      dw2_asm_output_data (4, sou_offset, "btm_offset");
>> -    }
>> -  else
>> -    {
>> -      dw2_asm_output_data (4, dmd->dmd_name_offset,
>> -                       "MEMBER '%s' idx=%u",
>> -                       dmd->dmd_name, idx);
>> -      btf_asm_type_ref ("btm_type", ctfc, get_btf_id (dmd->dmd_type));
>> -      dw2_asm_output_data (4, dmd->dmd_offset, "btm_offset");
>> +      /* Refer to the base type of the slice.  */
>> +      base_type = get_btf_id (ref_type->dtd_u.dtu_slice.cts_type);
>> +    }
>>       }
>> +
>> +  btf_asm_type_ref ("btm_type", ctfc, base_type);
>> +  dw2_asm_output_data (4, sou_offset, "btm_offset");
>>   }
>>   
>>   /* Asm'out an enum constant following a BTF_KIND_ENUM{,64}.  */
>> diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-bitfields-4.c 
>> b/gcc/testsuite/gcc.dg/debug/btf/btf-bitfields-4.c
>> index d4a6ef6a1eb..20cdfaa057a 100644
>> --- a/gcc/testsuite/gcc.dg/debug/btf/btf-bitfields-4.c
>> +++ b/gcc/testsuite/gcc.dg/debug/btf/btf-bitfields-4.c
>> @@ -14,6 +14,8 @@
>>   
>>   /* Struct with 4 members and no bitfield (kind_flag not set).  */
>>   /* { dg-final { scan-assembler-times "\[\t \]0x4000004\[\t 
>> \]+\[^\n\]*btt_info" 1 } } */
>> +/* { dg-final { scan-assembler-times " MEMBER" 4 } } */
>> +/* { dg-final { scan-assembler-times " MEMBER 'unsup' 
>> idx=2\[\\r\\n\]+\[^\\r\\n\]*0\[\t \]+\[^\n\]*btm_type: void" 1 } } */
>>   
>>   struct bigly
>>   {
> 

Reply via email to