On 8/2/25 08:10, Indu Bhagat wrote:
> On 7/21/25 4:00 PM, David Faust wrote:
>> Support the btf_decl_tag and btf_type_tag attributes in BTF by creating
>> and emitting BTF_KIND_DECL_TAG and BTF_KIND_TYPE_TAG records,
>> respectively, for them.
>>
>> Some care is required when -gprune-btf is in effect to avoid emitting
>> decl or type tags for declarations or types which have been pruned and
>> will not be emitted in BTF.
>>
>> gcc/
>>      * btfout.cc (get_btf_kind): Handle DECL_TAG and TYPE_TAG kinds.
>>      (btf_calc_num_vbytes): Likewise.
>>      (btf_asm_type): Likewise.
>>      (output_asm_btf_vlen_bytes): Likewise.
>>      (output_btf_tags): New.
>>      (btf_output): Call it here.
>>      (btf_add_used_type): Replace with simple wrapper around...
>>      (btf_add_used_type_1): ...the implementation.  Handle
>>      BTF_KIND_DECL_TAG and BTF_KIND_TYPE_TAG.
>>      (btf_add_vars): Update btf_add_used_type call.
>>      (btf_assign_tag_ids): New.
>>      (btf_mark_type_used): Update btf_add_used_type call.
>>      (btf_collect_pruned_types): Likewise.  Handle type and decl tags.
>>      (btf_finish): Call btf_assign_tag_ids.
>>
>> gcc/testsuite/
>>      * gcc.dg/debug/btf/btf-decl-tag-1.c: New test.
>>      * gcc.dg/debug/btf/btf-decl-tag-2.c: New test.
>>      * gcc.dg/debug/btf/btf-decl-tag-3.c: New test.
>>      * gcc.dg/debug/btf/btf-decl-tag-4.c: New test.
>>      * gcc.dg/debug/btf/btf-type-tag-1.c: New test.
>>      * gcc.dg/debug/btf/btf-type-tag-2.c: New test.
>>      * gcc.dg/debug/btf/btf-type-tag-3.c: New test.
>>      * gcc.dg/debug/btf/btf-type-tag-4.c: New test.
>>      * gcc.dg/debug/btf/btf-type-tag-c2x-1.c: New test.
>>
>> include/
>>      * btf.h (BTF_KIND_DECL_TAG, BTF_KIND_TYPE_TAG) New defines.
>>      (struct btf_decl_tag): New.
> 
> Hi David,
> 
> LGTM, one nit below.
> 
> Thanks
> Indu
> 
>> ---
>>   gcc/btfout.cc                                 | 171 +++++++++++++++---
>>   .../gcc.dg/debug/btf/btf-decl-tag-1.c         |  14 ++
>>   .../gcc.dg/debug/btf/btf-decl-tag-2.c         |  22 +++
>>   .../gcc.dg/debug/btf/btf-decl-tag-3.c         |  22 +++
>>   .../gcc.dg/debug/btf/btf-decl-tag-4.c         |  34 ++++
>>   .../gcc.dg/debug/btf/btf-type-tag-1.c         |  26 +++
>>   .../gcc.dg/debug/btf/btf-type-tag-2.c         |  13 ++
>>   .../gcc.dg/debug/btf/btf-type-tag-3.c         |  28 +++
>>   .../gcc.dg/debug/btf/btf-type-tag-4.c         |  24 +++
>>   .../gcc.dg/debug/btf/btf-type-tag-c2x-1.c     |  22 +++
>>   include/btf.h                                 |  14 ++
>>   11 files changed, 366 insertions(+), 24 deletions(-)
>>   create mode 100644 gcc/testsuite/gcc.dg/debug/btf/btf-decl-tag-1.c
>>   create mode 100644 gcc/testsuite/gcc.dg/debug/btf/btf-decl-tag-2.c
>>   create mode 100644 gcc/testsuite/gcc.dg/debug/btf/btf-decl-tag-3.c
>>   create mode 100644 gcc/testsuite/gcc.dg/debug/btf/btf-decl-tag-4.c
>>   create mode 100644 gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-1.c
>>   create mode 100644 gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-2.c
>>   create mode 100644 gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-3.c
>>   create mode 100644 gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-4.c
>>   create mode 100644 gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-c2x-1.c
>>
>> diff --git a/gcc/btfout.cc b/gcc/btfout.cc
>> index ff7ea42a961..c00e0c98015 100644
>> --- a/gcc/btfout.cc
>> +++ b/gcc/btfout.cc
>> @@ -141,6 +141,8 @@ get_btf_kind (uint32_t ctf_kind)
>>       case CTF_K_VOLATILE: return BTF_KIND_VOLATILE;
>>       case CTF_K_CONST:    return BTF_KIND_CONST;
>>       case CTF_K_RESTRICT: return BTF_KIND_RESTRICT;
>> +    case CTF_K_DECL_TAG: return BTF_KIND_DECL_TAG;
>> +    case CTF_K_TYPE_TAG: return BTF_KIND_TYPE_TAG;
>>       default:;
>>       }
>>     return BTF_KIND_UNKN;
>> @@ -217,6 +219,7 @@ btf_calc_num_vbytes (ctf_dtdef_ref dtd)
>>       case BTF_KIND_CONST:
>>       case BTF_KIND_RESTRICT:
>>       case BTF_KIND_FUNC:
>> +    case BTF_KIND_TYPE_TAG:
>>       /* These kinds have no vlen data.  */
>>         break;
>>   
>> @@ -256,6 +259,10 @@ btf_calc_num_vbytes (ctf_dtdef_ref dtd)
>>         vlen_bytes += vlen * sizeof (struct btf_var_secinfo);
>>         break;
>>   
>> +    case BTF_KIND_DECL_TAG:
>> +      vlen_bytes += sizeof (struct btf_decl_tag);
>> +      break;
>> +
>>       default:
>>         break;
>>       }
>> @@ -452,6 +459,20 @@ btf_asm_type (ctf_dtdef_ref dtd)
>>       and should write 0.  */
>>         dw2_asm_output_data (4, 0, "(unused)");
>>         return;
>> +    case BTF_KIND_DECL_TAG:
>> +      {
>> +    if (dtd->ref_type)
>> +      break;
>> +    else if (dtd->dtd_u.dtu_tag.ref_var)
>> +      {
>> +        /* ref_type is NULL for decl tag attached to a variable.  */
>> +        ctf_dvdef_ref dvd = dtd->dtd_u.dtu_tag.ref_var;
>> +        dw2_asm_output_data (4, dvd->dvd_id,
>> +                             "btt_type: (BTF_KIND_VAR '%s')",
>> +                             dvd->dvd_name);
>> +        return;
>> +      }
>> +      }
>>       default:
>>         break;
>>       }
>> @@ -801,6 +822,12 @@ output_asm_btf_vlen_bytes (ctf_container_ref ctfc, 
>> ctf_dtdef_ref dtd)
>>       at this point.  */
>>         gcc_unreachable ();
>>   
>> +    case BTF_KIND_DECL_TAG:
>> +      dw2_asm_output_data (4, dtd->dtd_u.dtu_tag.component_idx,
>> +                       "component_idx=%d",
>> +                       dtd->dtd_u.dtu_tag.component_idx);
>> +      break;
>> +
>>       default:
>>         /* All other BTF type kinds have no variable length data.  */
>>         break;
>> @@ -851,6 +878,20 @@ output_btf_func_types (void)
>>       btf_asm_func_type (ref);
>>   }
>>   
>> +static void
>> +output_btf_tags (ctf_container_ref ctfc)
>> +{
>> +  /* If pruning, tags which are not pruned have already been added to
>> +     the used list and output by output_btf_types.  */
>> +  if (debug_prune_btf)
>> +    return;
>> +
>> +  ctf_dtdef_ref dtd;
>> +  unsigned i;
>> +  FOR_EACH_VEC_ELT (*ctfc->ctfc_tags, i, dtd)
>> +    output_asm_btf_type (ctfc, dtd);
>> +}
>> +
>>   /* Output all BTF_KIND_DATASEC records.  */
>>   
>>   static void
>> @@ -869,6 +910,7 @@ btf_output (ctf_container_ref ctfc)
>>     output_btf_types (ctfc);
>>     output_btf_vars (ctfc);
>>     output_btf_func_types ();
>> +  output_btf_tags (ctfc);
>>     output_btf_datasec_types ();
>>     output_btf_strs (ctfc);
>>   }
>> @@ -985,7 +1027,8 @@ static vec<struct btf_fixup> fixups;
>>      is created and emitted.  This vector stores them.  */
>>   static GTY (()) vec<ctf_dtdef_ref, va_gc> *forwards;
>>   
>> -/* Recursively add type DTD and any types it references to the used set.
>> +/* Implementation of btf_add_used_type.
>> +   Recursively add type DTD and any types it references to the used set.
>>      Return a type that should be used for references to DTD - usually DTD 
>> itself,
>>      but may be NULL if DTD corresponds to a type which will not be emitted.
>>      CHECK_PTR is true if one of the predecessors in recursive calls is a 
>> struct
>> @@ -996,8 +1039,8 @@ static GTY (()) vec<ctf_dtdef_ref, va_gc> *forwards;
>>      CREATE_FIXUPS is false.  */
>>   
>>   static ctf_dtdef_ref
>> -btf_add_used_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd,
>> -               bool check_ptr, bool seen_ptr, bool create_fixups)
>> +btf_add_used_type_1 (ctf_container_ref ctfc, ctf_dtdef_ref dtd,
>> +                 bool check_ptr, bool seen_ptr, bool create_fixups)
>>   {
>>     if (dtd == NULL)
>>       return NULL;
>> @@ -1029,8 +1072,9 @@ btf_add_used_type (ctf_container_ref ctfc, 
>> ctf_dtdef_ref dtd,
>>                fixups.unordered_remove (i);
>>   
>>            /* Add the concrete base type.  */
>> -          dtd->ref_type = btf_add_used_type (ctfc, dtd->ref_type, check_ptr,
>> -                                             seen_ptr, create_fixups);
>> +          dtd->ref_type = btf_add_used_type_1 (ctfc, dtd->ref_type,
>> +                                               check_ptr, seen_ptr,
>> +                                               create_fixups);
>>            return dtd;
>>          }
>>      default:
>> @@ -1044,8 +1088,8 @@ btf_add_used_type (ctf_container_ref ctfc, 
>> ctf_dtdef_ref dtd,
>>       the reference to the bitfield.  The slice type won't be emitted,
>>       but we need the information in it when writing out the bitfield
>>       encoding.  */
>> -      btf_add_used_type (ctfc, dtd->dtd_u.dtu_slice.cts_type,
>> -                     check_ptr, seen_ptr, create_fixups);
>> +      btf_add_used_type_1 (ctfc, dtd->dtd_u.dtu_slice.cts_type,
>> +                       check_ptr, seen_ptr, create_fixups);
>>         return dtd;
>>       }
>>   
>> @@ -1069,7 +1113,11 @@ btf_add_used_type (ctf_container_ref ctfc, 
>> ctf_dtdef_ref dtd,
>>       case BTF_KIND_INT:
>>       case BTF_KIND_FLOAT:
>>       case BTF_KIND_FWD:
>> -      /* Leaf kinds which do not refer to any other types.  */
>> +    case BTF_KIND_DECL_TAG:
>> +      /* Leaf kinds which do not refer to any other types.
>> +     BTF_KIND_DECL_TAG is a special case: we treat it as though it does not
>> +     refer to any other types, since we only want the DECL_TAG to be added
>> +     if the type to which it refers has already been added.  */
>>         break;
>>   
>>       case BTF_KIND_FUNC:
>> @@ -1082,6 +1130,7 @@ btf_add_used_type (ctf_container_ref ctfc, 
>> ctf_dtdef_ref dtd,
>>       case BTF_KIND_CONST:
>>       case BTF_KIND_VOLATILE:
>>       case BTF_KIND_RESTRICT:
>> +    case BTF_KIND_TYPE_TAG:
>>         {
>>      /* These type kinds refer to exactly one other type.  */
>>      if (check_ptr && !seen_ptr)
>> @@ -1106,18 +1155,18 @@ btf_add_used_type (ctf_container_ref ctfc, 
>> ctf_dtdef_ref dtd,
>>        }
>>   
>>      /* Add the type to which this type refers.  */
>> -    dtd->ref_type = btf_add_used_type (ctfc, dtd->ref_type, check_ptr,
>> -                                       seen_ptr, create_fixups);
>> +    dtd->ref_type = btf_add_used_type_1 (ctfc, dtd->ref_type, check_ptr,
>> +                                         seen_ptr, create_fixups);
>>      break;
>>         }
>>       case BTF_KIND_ARRAY:
>>         {
>>      /* Add element and index types.  */
>>      ctf_arinfo_t *arr = &(dtd->dtd_u.dtu_arr);
>> -    arr->ctr_contents = btf_add_used_type (ctfc, arr->ctr_contents, false,
>> -                                           false, create_fixups);
>> -    arr->ctr_index = btf_add_used_type (ctfc, arr->ctr_index, false, false,
>> -                                        create_fixups);
>> +    arr->ctr_contents = btf_add_used_type_1 (ctfc, arr->ctr_contents,
>> +                                             false, false, create_fixups);
>> +    arr->ctr_index = btf_add_used_type_1 (ctfc, arr->ctr_index, false,
>> +                                          false, create_fixups);
>>      break;
>>         }
>>       case BTF_KIND_STRUCT:
>> @@ -1133,8 +1182,8 @@ btf_add_used_type (ctf_container_ref ctfc, 
>> ctf_dtdef_ref dtd,
>>          /* Add member type for struct/union members.  For enums, only the
>>             enumerator names are needed.  */
>>          if (kind == BTF_KIND_STRUCT || kind == BTF_KIND_UNION)
>> -          dmd->dmd_type = btf_add_used_type (ctfc, dmd->dmd_type, true,
>> -                                             false, create_fixups);
>> +          dmd->dmd_type = btf_add_used_type_1 (ctfc, dmd->dmd_type, true,
>> +                                               false, create_fixups);
>>          ctf_add_string (ctfc, dmd->dmd_name, &(dmd->dmd_name_offset),
>>                          CTF_STRTAB);
>>        }
>> @@ -1143,16 +1192,17 @@ btf_add_used_type (ctf_container_ref ctfc, 
>> ctf_dtdef_ref dtd,
>>       case BTF_KIND_FUNC_PROTO:
>>         {
>>      /* Add return type.  */
>> -    dtd->ref_type = btf_add_used_type (ctfc, dtd->ref_type, false, false,
>> -                                       create_fixups);
>> +    dtd->ref_type = btf_add_used_type_1 (ctfc, dtd->ref_type, false, false,
>> +                                         create_fixups);
>>   
>>      /* Add arg types.  */
>>      ctf_func_arg_t * farg;
>>      for (farg = dtd->dtd_u.dtu_argv;
>>           farg != NULL; farg = (ctf_func_arg_t *) ctf_farg_list_next (farg))
>>        {
>> -        farg->farg_type = btf_add_used_type (ctfc, farg->farg_type, false,
>> -                                             false, create_fixups);
>> +        farg->farg_type = btf_add_used_type_1 (ctfc, farg->farg_type,
>> +                                               false, false,
>> +                                               create_fixups);
>>          /* Note: argument names are stored in the auxilliary string table,
>>             since CTF does not include arg names.  That table has not been
>>             cleared, so no need to re-add argument names here.  */
>> @@ -1166,6 +1216,16 @@ btf_add_used_type (ctf_container_ref ctfc, 
>> ctf_dtdef_ref dtd,
>>     return dtd;
>>   }
>>   
>> +/* Recursively add type DTD and any types it references to the used set.
>> +   Return a type that should be used for references to DTD - usually DTD 
>> itself,
>> +   but may be NULL if DTD corresponds to a type which will not be emitted.  
>> */
>> +
>> +static ctf_dtdef_ref
>> +btf_add_used_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
>> +{
>> +  return btf_add_used_type_1 (ctfc, dtd, false, false, true);
>> +}
>> +
>>   /* Initial entry point of BTF generation, called at early_finish () after
>>      CTF information has possibly been output.  Translate all CTF information
>>      to BTF, and do any processing that must be done early, such as creating
>> @@ -1402,7 +1462,7 @@ btf_add_vars (ctf_container_ref ctfc)
>>            ctf_dmdef_t *dmd;
>>            for (dmd = dtd->dtd_u.dtu_members;
>>                 dmd != NULL; dmd = (ctf_dmdef_t *) ctf_dmd_list_next (dmd))
>> -            btf_add_used_type (ctfc, dmd->dmd_type, false, false, true);
>> +            btf_add_used_type (ctfc, dmd->dmd_type);
>>          }
>>      }
>>       }
>> @@ -1488,6 +1548,45 @@ btf_assign_var_ids (ctf_container_ref ctfc)
>>       }
>>   }
>>   
>> +/* Assign BTF IDs for type and decl tags and account for their size.  */
>> +
>> +static void
>> +btf_assign_tag_ids (ctf_container_ref ctfc)
>> +{
>> +  /* Both decl and type tags may be pruned if the types/decls to which they
>> +     refer are pruned.  This is handled in btf_collect_pruned_types, and
>> +     through that process they have also been assigned ids already.  */
>> +  if (debug_prune_btf)
>> +    return;
>> +
>> +  size_t num_tags = vec_safe_length (ctfc->ctfc_tags);
>> +  if (num_tags == 0)
>> +    return;
>> +
>> +  unsigned int i;
>> +  ctf_dtdef_ref dtd;
>> +  FOR_EACH_VEC_ELT (*ctfc->ctfc_tags, i, dtd)
>> +    {
>> +      /* Assign BTF id.  */
>> +      ctf_id_t id = ctfc->ctfc_nextid++;
>> +      gcc_assert (id <= BTF_MAX_TYPE);
>> +      dtd->dtd_type = id;
>> +
>> +      /* Tags on functions will have a ref_type pointing to the
>> +     FUNC_PROTO, we want them to point the FUNC record instead.  */
>> +      ctf_dtdef_ref *pdtd = NULL;
>> +      if (dtd->ref_type && (pdtd = func_map->get (dtd->ref_type)) != NULL)
>> +    dtd->ref_type = *pdtd;
>> +
> 
> Nit really.  But I think it has briefly confused me before as well to 
> see this ...
> 
>> +      /* Strings for tags are stored in the auxilliary strtab, which is
> 
> Typo: auxiliary

Fixed, thanks

> 
>> +     concatenated after the regular strtab.  ctti_name only accounts
>> +     for offset in the auxiliary strtab until this point.  */
>> +      dtd->dtd_data.ctti_name += ctfc_get_strtab_len (ctfc, CTF_STRTAB);
>> +      ctfc->ctfc_num_types++;
>> +      ctfc->ctfc_num_vlen_bytes += btf_calc_num_vbytes (dtd);
>> +    }
>> +}
>> +
>>   /* Assign BTF IDs for datasec records and account for their size.  */
>>   
>>   static void
>> @@ -1522,7 +1621,7 @@ btf_mark_type_used (tree t)
>>     if (!dtd)
>>       return;
>>   
>> -  btf_add_used_type (ctfc, dtd, false, false, true);
>> +  btf_add_used_type (ctfc, dtd);
>>   }
>>   
>>   /* Callback used for assembling the only-used-types list.  Note that this 
>> is
>> @@ -1549,7 +1648,7 @@ btf_collect_pruned_types (ctf_container_ref ctfc)
>>     size_t i;
>>     FOR_EACH_VEC_ELT (*funcs, i, dtd)
>>       {
>> -      btf_add_used_type (ctfc, dtd->ref_type, false, false, true);
>> +      btf_add_used_type (ctfc, dtd->ref_type);
>>         ctf_add_string (ctfc, dtd->dtd_name, &(dtd->dtd_data.ctti_name),
>>                    CTF_STRTAB);
>>       }
>> @@ -1558,10 +1657,33 @@ btf_collect_pruned_types (ctf_container_ref ctfc)
>>     for (i = 0; i < ctfc->ctfc_vars_list_count; i++)
>>       {
>>         ctf_dvdef_ref dvd = ctfc->ctfc_vars_list[i];
>> -      btf_add_used_type (ctfc, dvd->dvd_type, false, false, true);
>> +      btf_add_used_type (ctfc, dvd->dvd_type);
>>         ctf_add_string (ctfc, dvd->dvd_name, &(dvd->dvd_name_offset), 
>> CTF_STRTAB);
>>       }
>>   
>> +  /* Used type tags will be added by recursive btf_add_used_type calls 
>> above.
>> +     For decl tags, scan the list and only add those decl tags whose 
>> referent
>> +     types are marked as used.  We may have pruned a struct type with 
>> members
>> +     annotated by a decl tag.  */
>> +  FOR_EACH_VEC_ELT (*ctfc->ctfc_tags, i, dtd)
>> +    {
>> +      /* Only add decl tags whose referent types have not been pruned.
>> +     Variables are never pruned, so decl tags on variables are always
>> +     used.  */
>> +      if (btf_dtd_kind (dtd) == BTF_KIND_DECL_TAG
>> +      && ((dtd->ref_type && btf_used_types->contains (dtd->ref_type))
>> +          || (dtd->dtd_u.dtu_tag.ref_var)))
>> +    btf_add_used_type (ctfc, dtd);
>> +
>> +      /* Tags on functions or function args will have a ref_type pointing 
>> to the
>> +     FUNC_PROTO, we want them to point the FUNC record instead.  */
>> +      ctf_dtdef_ref *pdtd = NULL;
>> +      if (dtd->ref_type
>> +      && btf_used_types->contains (dtd->ref_type)
>> +      && (pdtd = func_map->get (dtd->ref_type)) != NULL)
>> +    dtd->ref_type = *pdtd;
> 
> ... and also this.
> 
>> +    }
>> +
>>     /* Process fixups.  If the base type was never added, create a forward 
>> for it
>>        and adjust the reference to point to that.  If it was added, then 
>> nothing
>>        needs to change.  */
>> @@ -1634,6 +1756,7 @@ btf_finish (void)
>>   
>>     btf_assign_var_ids (tu_ctfc);
>>     btf_assign_func_ids (tu_ctfc);
>> +  btf_assign_tag_ids (tu_ctfc);
>>     btf_assign_datasec_ids (tu_ctfc);
>>   
> 
> only to soon realize that btf_assign_tag_ids early exits when 
> debug_prune_btf.
> 
> So, I would find it more readable if we did:
> 
>    btf_assign_var_ids (tu_ctfc);
>    btf_assign_func_ids (tu_ctfc);
>    btf_assign_datasec_ids (tu_ctfc);
> 
>    /* Both decl and type tags may be pruned if the types/decls to which they
>       refer are pruned.  This is handled in btf_collect_pruned_types, and
>       through that process they have also been assigned ids already.  */
>    if (!debug_prune_btf)
>      btf_assign_tag_ids (tu_ctfc);
> 
> Nit really :)

OK, sure.  Makes sense to move the check on pruning out here from the
early return.

I'd like to preserve the "datasec records are last in the ID space"
(this is not a hard requirement of BTF but is logical IMO) so I'll
keep the overall ordering of id assignments as before.

Thanks!

> 
>>     /* Finally, write out the complete .BTF section.  */
>> diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-decl-tag-1.c 
>> b/gcc/testsuite/gcc.dg/debug/btf/btf-decl-tag-1.c
>> new file mode 100644
>> index 00000000000..c933d84b497
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/debug/btf/btf-decl-tag-1.c
>> @@ -0,0 +1,14 @@
>> +/* Test simple BTF decl tag generation for variables.  */
>> +/* { dg-do compile } */
>> +/* { dg-options "-O0 -gbtf -dA" } */
>> +
>> +#define __tag1 __attribute__((btf_decl_tag ("decl1")))
>> +#define __tag2 __attribute__((btf_decl_tag ("decl2")))
>> +#define __tag3 __attribute__((btf_decl_tag ("decl3")))
>> +
>> +int x __tag1 __tag2;
>> +int y __tag1;
>> +
>> +/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 
>> 'decl1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_VAR 
>> 'x'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=-1" 1} } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 
>> 'decl2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_VAR 
>> 'x'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=-1" 1} } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 
>> 'decl1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_VAR 
>> 'y'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=-1" 1} } */
>> diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-decl-tag-2.c 
>> b/gcc/testsuite/gcc.dg/debug/btf/btf-decl-tag-2.c
>> new file mode 100644
>> index 00000000000..c4f09ca839c
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/debug/btf/btf-decl-tag-2.c
>> @@ -0,0 +1,22 @@
>> +/* Test BTF decl tag generation for structs.  */
>> +/* { dg-do compile } */
>> +/* { dg-options "-O0 -gbtf -dA" } */
>> +
>> +#define __tag1 __attribute__((btf_decl_tag ("decl1")))
>> +#define __tag2 __attribute__((btf_decl_tag ("decl2")))
>> +#define __tag3 __attribute__((btf_decl_tag ("decl3")))
>> +
>> +struct Foo {
>> +  int a;
>> +  int b __tag3 __tag2;
>> +  char *z __tag1;
>> +};
>> +
>> +struct Foo f __tag1 __tag2;
>> +
>> +/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 
>> 'decl2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_STRUCT 
>> 'Foo'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=1" 1} } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 
>> 'decl3'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_STRUCT 
>> 'Foo'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=1" 1} } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 
>> 'decl1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_STRUCT 
>> 'Foo'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=2" 1} } */
>> +
>> +/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 
>> 'decl1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_VAR 
>> 'f'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=-1" 1} } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 
>> 'decl2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_VAR 
>> 'f'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=-1" 1} } */
>> diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-decl-tag-3.c 
>> b/gcc/testsuite/gcc.dg/debug/btf/btf-decl-tag-3.c
>> new file mode 100644
>> index 00000000000..7eb8a93ec12
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/debug/btf/btf-decl-tag-3.c
>> @@ -0,0 +1,22 @@
>> +/* Test BTF decl tag generation for functions and function args.  */
>> +/* { dg-do compile } */
>> +/* { dg-options "-O0 -gbtf -dA" } */
>> +
>> +#define __tag1 __attribute__((btf_decl_tag ("decl1")))
>> +#define __tag2 __attribute__((btf_decl_tag ("decl2")))
>> +#define __tag3 __attribute__((btf_decl_tag ("decl3")))
>> +
>> +int __tag1 __tag2 func (int arg_a __tag3 __tag1, int arg_b __tag2)
>> +{
>> +  return arg_a * arg_b;
>> +}
>> +
>> +int foo (int x) {
>> +  return func (x, x + 1);
>> +}
>> +
>> +/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 
>> 'decl1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_FUNC 
>> 'func'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=-1" 1} } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 
>> 'decl2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_FUNC 
>> 'func'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=-1" 1} } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 
>> 'decl1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_FUNC 
>> 'func'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=0" 1} } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 
>> 'decl3'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_FUNC 
>> 'func'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=0" 1} } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 
>> 'decl2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_FUNC 
>> 'func'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=1" 1} } */
>> diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-decl-tag-4.c 
>> b/gcc/testsuite/gcc.dg/debug/btf/btf-decl-tag-4.c
>> new file mode 100644
>> index 00000000000..a9022375529
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/debug/btf/btf-decl-tag-4.c
>> @@ -0,0 +1,34 @@
>> +/* Test BTF decl tag generation with BTF pruning.  */
>> +/* { dg-do compile } */
>> +/* { dg-options "-O0 -gbtf -gprune-btf -dA" } */
>> +
>> +#define __decl1 __attribute__((btf_decl_tag ("decl1")))
>> +#define __decl2 __attribute__((btf_decl_tag ("decl2")))
>> +#define __decl3 __attribute__((btf_decl_tag ("decl3")))
>> +
>> +struct S {
>> +  /* This tag on S.v shall not be emitted, because struct S is pruned and
>> +     replaced with a FWD, which does not hold any member info.  */
>> +  int v __decl3;
>> +  int w;
>> +};
>> +
>> +struct T {
>> +  int a;
>> +  struct S *s __decl1;
>> +  int c __decl2;
>> +};
>> +
>> +struct T t __decl1;
>> +
>> +int __decl1 func (struct T *t __decl2)
>> +{
>> +  return t->a + t->c;
>> +}
>> +
>> +/* { dg-final { scan-assembler-not " BTF_KIND_DECL_TAG 'decl3'" } } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 
>> 'decl1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_STRUCT 
>> 'T'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=1" 1} } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 
>> 'decl2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_STRUCT 
>> 'T'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=2" 1} } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 
>> 'decl1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_VAR 
>> 't'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=-1" 1} } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 
>> 'decl1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_FUNC 
>> 'func'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=-1" 1} } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 
>> 'decl2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_FUNC 
>> 'func'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=0" 1} } */
>> diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-1.c 
>> b/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-1.c
>> new file mode 100644
>> index 00000000000..63a6f324ab1
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-1.c
>> @@ -0,0 +1,26 @@
>> +/* Test simple generation of BTF type tags.  */
>> +/* { dg-do compile } */
>> +/* { dg-options "-O0 -gbtf -dA" } */
>> +
>> +#define __tag1 __attribute__((btf_type_tag("1")))
>> +#define __tag2 __attribute__((btf_type_tag("2")))
>> +
>> +/* var("kp") -> ptr -> type_tag("1") -> int  */
>> +int * __tag1 kp;
>> +
>> +struct Foo {
>> +  char a;
>> +  int b;
>> +};
>> +
>> +/* var("f") -> ptr -> type_tag("2") -> type_tag("1") -> struct("Foo")  */
>> +struct Foo * __tag1 __tag2 f;
>> +
>> +/* { dg-final { scan-assembler-times " BTF_KIND_VAR 
>> 'kp'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_PTR" 1 } } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 
>> '1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_INT" 1 } } */
>> +
>> +/* { dg-final { scan-assembler-times " BTF_KIND_VAR 
>> 'f'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_PTR" 1 } } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 
>> '2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG '1'\\)" 1 } } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 
>> '1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_STRUCT" 1 } } */
>> +
>> +/* { dg-final { scan-assembler-times " BTF_KIND_PTR 
>> ''(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG" 2 } } */
>> diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-2.c 
>> b/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-2.c
>> new file mode 100644
>> index 00000000000..5adf3d041c7
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-2.c
>> @@ -0,0 +1,13 @@
>> +/* Test generation of BTF type tags with cv-quals.  */
>> +/* { dg-do compile } */
>> +/* { dg-options "-O0 -gbtf -dA" } */
>> +
>> +#define __tag __attribute__((btf_type_tag("1")))
>> +
>> +/* var("pci") -> const -> ptr -> type_tag("1") -> int  */
>> +int __tag *const pci;
>> +
>> +/* { dg-final { scan-assembler-times " BTF_KIND_VAR 
>> 'pci'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_CONST" 1 } } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_CONST 
>> ''(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_PTR" 1 } } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_PTR 
>> ''(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG" 1 } } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 
>> '1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_INT" 1 } } */
>> diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-3.c 
>> b/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-3.c
>> new file mode 100644
>> index 00000000000..0bf38532456
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-3.c
>> @@ -0,0 +1,28 @@
>> +/* Test generation of BTF type tags with typedefs.  */
>> +/* { dg-do compile } */
>> +/* { dg-options "-O0 -gbtf -dA" } */
>> +
>> +#define __tag1 __attribute__((btf_type_tag("1")))
>> +#define __tag2 __attribute__((btf_type_tag("2")))
>> +
>> +typedef int *const cp;
>> +typedef int __tag1 *tp;
>> +
>> +/* var("x") -> ptr -> type_tag("2") -> typedef("cp") -> const -> ptr -> int 
>>  */
>> +cp __tag2 * x;
>> +
>> +/* var("y") -> const -> typedef("tp") -> ptr -> type_tag("1") -> int  */
>> +const tp y;
>> +
>> +/* { dg-final { scan-assembler-times " BTF_KIND_VAR 
>> 'x'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_PTR" 1 } } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_PTR 
>> ''(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG '2'\\)" 1 } } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 
>> '2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPEDEF 'cp'\\)" 1 } } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_TYPEDEF 
>> 'cp'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_CONST" 1 } } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_CONST 
>> ''(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_PTR" 1 } } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_PTR 
>> ''(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_INT" 1 } } */
>> +
>> +/* { dg-final { scan-assembler-times " BTF_KIND_VAR 
>> 'y'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_CONST" 1 } } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_CONST 
>> ''(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPEDEF 'tp'\\)" 1 } } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_TYPEDEF 
>> 'tp'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_PTR" 1 } } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_PTR 
>> ''(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG '1'\\)" 1 } } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 
>> '1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_INT" 1 } } */
>> diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-4.c 
>> b/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-4.c
>> new file mode 100644
>> index 00000000000..0ec7e571db2
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-4.c
>> @@ -0,0 +1,24 @@
>> +/* Test generation of BTF type tag when applied to function prototypes.  */
>> +/* { dg-do compile } */
>> +/* { dg-options "-O0 -gbtf -dA" } */
>> +
>> +#define __tag1 __attribute__((btf_type_tag("1")))
>> +#define __tag2 __attribute__((btf_type_tag("2")))
>> +
>> +int * __tag1
>> +dothing (void __tag2 *ptr, int __tag2 __tag1 *xi)
>> +{
>> +  if (xi)
>> +    {
>> +      int *tmp = (int *) ptr;
>> +      return tmp + (*xi);
>> +    }
>> +
>> +  return (int *) ptr;
>> +}
>> +
>> +/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 
>> '2'(\[\\r\\n\]+\[^\\r\\n\]*){2} btt_type: void" 1 } } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 
>> '2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_INT" 1 } } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 
>> '1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG '2'" 1 } } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_PTR 
>> ''(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG '1'" 2 } } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_PTR 
>> ''(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG '2'" 1 } } */
>> diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-c2x-1.c 
>> b/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-c2x-1.c
>> new file mode 100644
>> index 00000000000..2b2571570b1
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-c2x-1.c
>> @@ -0,0 +1,22 @@
>> +/* Test BTF type tag generation using C2x standard attribute syntax.
>> +   C2x attribute syntax does not allow attributes to "slide around".  */
>> +/* { dg-do compile } */
>> +/* { dg-options "-O0 -gbtf -dA" } */
>> +
>> +#define __tag1 [[gnu::btf_type_tag ("1")]]
>> +#define __tag2 [[gnu::btf_type_tag ("2")]]
>> +#define __tag3 [[gnu::btf_type_tag ("3")]]
>> +
>> +/* Note that the BTF format still only allows to represent type tags on
>> +   pointer types, so we do not get any type_tag("1") from the below, as
>> +   it applies to the 'volatile int' type and cannot be represented.  */
>> +
>> +/* var(z) -> const -> ptr -> type_tag(2) -> type_tag(3) -> ptr -> 
>> type_tag(2) -> volatile -> int  */
>> +volatile int __tag1 * __tag2 * __tag3 __tag2 const z;
>> +
>> +/* { dg-final { scan-assembler-times " BTF_KIND_VAR 
>> 'z'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_CONST" 1 } } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_CONST 
>> ''(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_PTR" 1 } } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_PTR 
>> ''(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG '2'\\)" 2 } } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 
>> '2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG '3'\\)" 1 } } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 
>> '3'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_PTR" 1 } } */
>> +/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 
>> '2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_VOLATILE" 1 } } */
>> diff --git a/include/btf.h b/include/btf.h
>> index 994d02dcfb3..d20ede23fb3 100644
>> --- a/include/btf.h
>> +++ b/include/btf.h
>> @@ -114,6 +114,8 @@ struct btf_type
>>   #define BTF_KIND_VAR               14      /* Variable.  */
>>   #define BTF_KIND_DATASEC   15      /* Section such as .bss or .data.  */
>>   #define BTF_KIND_FLOAT             16      /* Floating point.  */
>> +#define BTF_KIND_DECL_TAG   17      /* Declaration tag.  */
>> +#define BTF_KIND_TYPE_TAG   18      /* Type tag.  */
>>   #define BTF_KIND_ENUM64    19      /* Enumeration up to 64 bits.  */
>>   #define BTF_KIND_MAX               BTF_KIND_ENUM64
>>   #define NR_BTF_KINDS               (BTF_KIND_MAX + 1)
>> @@ -227,6 +229,18 @@ struct btf_enum64
>>     uint32_t val_hi32;       /* high 32-bit value for a 64-bit value 
>> Enumerator */
>>   };
>>   
>> +/* BTF_KIND_DECL_TAG is followed by a single struct btf_decl_tag, which
>> +   describes the item to which the tag applies:
>> +   - If component_idx == (uint32_t) -1, then the tag applies to item 
>> referred
>> +     to by the type_id.
>> +   - Otherwise, the tag applies to the struct or union member, or function
>> +     argument of the type referred to by type_id with the 0-based index
>> +     given by component_idx.  */
>> +struct btf_decl_tag
>> +{
>> +  uint32_t component_idx;
>> +};
>> +
>>   #ifdef     __cplusplus
>>   }
>>   #endif
> 

Reply via email to