Message ID | 20240411210147.16974-1-david.faust@oracle.com |
---|---|
State | New |
Headers | show |
Series | [v2] btf: emit non-representable bitfield as void | expand |
On 4/11/24 14:01, David Faust wrote: > [Changes from v1: use btf_dmd_representable_bitfield_p in > btf_asm_sou_member, instead of a slightly incorrect equivalent check.] > > 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. > > 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. LGTM. Thanks > --- > gcc/btfout.cc | 54 +++++++++---------- > .../gcc.dg/debug/btf/btf-bitfields-4.c | 2 + > 2 files changed, 28 insertions(+), 28 deletions(-) > > diff --git a/gcc/btfout.cc b/gcc/btfout.cc > index ab491f0297f..a1510574a93 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)) > - return; > + if (btf_dmd_representable_bitfield_p (ctfc, dmd)) > + { > + unsigned short word_offset = ref_type->dtd_u.dtu_slice.cts_offset; > + unsigned short bits = ref_type->dtd_u.dtu_slice.cts_bits; > > - sou_offset &= 0x00ffffff; > - sou_offset |= ((bits & 0xff) << 24); > + /* 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); > + } > + else > + { > + /* Bitfield cannot be represented in BTF. Emit the member as having > + 'void' type. */ > + base_type = BTF_VOID_TYPEID; > + } > } > + > + 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 > {
diff --git a/gcc/btfout.cc b/gcc/btfout.cc index ab491f0297f..a1510574a93 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)) - return; + if (btf_dmd_representable_bitfield_p (ctfc, dmd)) + { + unsigned short word_offset = ref_type->dtd_u.dtu_slice.cts_offset; + unsigned short bits = ref_type->dtd_u.dtu_slice.cts_bits; - sou_offset &= 0x00ffffff; - sou_offset |= ((bits & 0xff) << 24); + /* 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); + } + else + { + /* Bitfield cannot be represented in BTF. Emit the member as having + 'void' type. */ + base_type = BTF_VOID_TYPEID; + } } + + 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 {