On 2/24/25 11:04, Indu Bhagat wrote:
> On 2/6/25 11:54 AM, David Faust wrote:
>> Translate DW_TAG_GNU_annotation DIEs created for C attributes
>> btf_decl_tag and btf_type_tag into an in-memory representation in the
>> CTF/BTF container. They will be output in BTF as BTF_KIND_DECL_TAG and
>> BTF_KIND_TYPE_TAG records.
>>
>> The new CTF kinds used to represent these annotations, CTF_K_DECL_TAG
>> and CTF_K_TYPE_TAG, are expected to be formalized in the next version of
>> the CTF specification. For now they only exist in memory as a
>> translation step to BTF, and are not emitted when generating CTF
>> information.
>>
>
> The patch overall looks OK to me. Some comments inlined below.
>
>> gcc/
>> * ctfc.cc (ctf_dtu_d_union_selector): Handle CTF_K_DECL_TAG and
>> CTF_K_TYPE_TAG.
>> (ctf_add_type_tag, ctf_add_decl_tag): New.
>> (ctf_add_variable): Return the new ctf_dvdef_ref rather than zero.
>> (new_ctf_container): Initialize new members.
>> (ctfc_delete_container): Deallocate new members.
>> * ctfc.h (ctf_dvdef, ctf_dvdef_t, ctf_dvdef_ref): Move forward
>> declarations earlier in file.
>> (ctf_decl_tag_t): New typedef.
>> (ctf_dtdef): Add ctf_decl_tag_t member to dtd_u union.
>> (ctf_dtu_d_union_enum): Add new CTF_DTU_D_TAG enumerator.
>> (ctf_container): Add ctfc_tags vector and ctfc_type_tags_map hash_map
>> members.
>> (ctf_add_type_tag, ctf_add_decl_tag): New function protos.
>> (ctf_add_variable): Change prototype return type to ctf_dvdef_ref.
>> * dwarf2ctf.cc (gen_ctf_type_tags, gen_ctf_decl_tags)
>> (gen_ctf_decl_tags_for_var): New static functions.
>> (gen_ctf_sou_type): Handle decl tags.
>> (gen_ctf_function_type): Likewise.
>> (gen_ctf_variable): Likewise.
>> (gen_ctf_function): Likewise.
>> (gen_ctf_type): Handle type tags.
>>
>> gcc/testsuite
>> * gcc.dg/debug/ctf/ctf-decl-tag-1.c: New test.
>> * gcc.dg/debug/ctf/ctf-type-tag-1.c: New test.
>>
>> include/
>> * ctf.h (CTF_K_DECL_TAG, CTF_K_TYPE_TAG): New defines.
>> ---
>> gcc/ctfc.cc | 70 +++++++-
>> gcc/ctfc.h | 41 ++++-
>> gcc/dwarf2ctf.cc | 152 +++++++++++++++++-
>> .../gcc.dg/debug/ctf/ctf-decl-tag-1.c | 31 ++++
>> .../gcc.dg/debug/ctf/ctf-type-tag-1.c | 19 +++
>> include/ctf.h | 4 +
>> 6 files changed, 303 insertions(+), 14 deletions(-)
>> create mode 100644 gcc/testsuite/gcc.dg/debug/ctf/ctf-decl-tag-1.c
>> create mode 100644 gcc/testsuite/gcc.dg/debug/ctf/ctf-type-tag-1.c
>>
>> diff --git a/gcc/ctfc.cc b/gcc/ctfc.cc
>> index 51511d69baa..c478fa0a136 100644
>> --- a/gcc/ctfc.cc
>> +++ b/gcc/ctfc.cc
>> @@ -107,6 +107,9 @@ ctf_dtu_d_union_selector (ctf_dtdef_ref ctftype)
>> return CTF_DTU_D_ARGUMENTS;
>> case CTF_K_SLICE:
>> return CTF_DTU_D_SLICE;
>> + case CTF_K_DECL_TAG:
>> + case CTF_K_TYPE_TAG:
>> + return CTF_DTU_D_TAG;
>> default:
>> /* The largest member as default. */
>> return CTF_DTU_D_ARRAY;
>> @@ -445,6 +448,58 @@ ctf_add_reftype (ctf_container_ref ctfc, uint32_t flag,
>> ctf_dtdef_ref ref,
>> return dtd;
>> }
>>
>> +ctf_dtdef_ref
>> +ctf_add_type_tag (ctf_container_ref ctfc, uint32_t flag, const char *value,
>> + ctf_dtdef_ref ref_dtd)
>> +{
>> + ctf_dtdef_ref dtd;
>> + /* Create a DTD for the tag, but do not place it in the regular types
>> list;
>> + CTF format does not (yet) encode tags. */
>> + dtd = ggc_cleared_alloc<ctf_dtdef_t> ();
>> +
>> + dtd->dtd_name = ctf_add_string (ctfc, value, &(dtd->dtd_data.ctti_name),
>> + CTF_AUX_STRTAB);
>> + /* A single DW_TAG_GNU_annotation DIE may be referenced by multiple DIEs,
>> + e.g. when multiple distinct types specify the same type tag. We will
>> + synthesize multiple CTF DTD records in that case, so we cannot tie them
>> + all to the same key (the DW_TAG_GNU_annotation DIE) in ctfc_types. */
>> + dtd->dtd_key = NULL;
>> + dtd->ref_type = ref_dtd;
>> + dtd->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_TYPE_TAG, flag, 0);
>> + dtd->dtd_u.dtu_tag.ref_var = NULL; /* Not used for type tags. */
>> + dtd->dtd_u.dtu_tag.component_idx = 0; /* Not used for type tags. */
>> +
>> + /* Insert tag directly into the tag list. Type ID will be assigned
>> later. */
>> + vec_safe_push (ctfc->ctfc_tags, dtd);
>> + return dtd;
>> +}
>> +
>> +ctf_dtdef_ref
>> +ctf_add_decl_tag (ctf_container_ref ctfc, uint32_t flag, const char *value,
>> + ctf_dtdef_ref ref_dtd, uint32_t comp_idx)
>> +{
>> + ctf_dtdef_ref dtd;
>> + /* Create a DTD for the tag, but do not place it in the regular types
>> list;
>> + ctf format does not (yet) encode tags. */
>> + dtd = ggc_cleared_alloc<ctf_dtdef_t> ();
>> +
>> + dtd->dtd_name = ctf_add_string (ctfc, value, &(dtd->dtd_data.ctti_name),
>> + CTF_AUX_STRTAB);
>> + /* A single DW_TAG_GNU_annotation DIE may be referenced by multiple DIEs,
>> + e.g. when multiple distinct declarations specify the same decl tag.
>> + We will synthesize multiple CTF DTD records in that case, so we cannot
>> tie
>> + them all to the same key (the DW_TAG_GNU_annotation DIE) in
>> ctfc_types. */
>> + dtd->dtd_key = NULL;
>> + dtd->ref_type = ref_dtd;
>> + dtd->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_DECL_TAG, flag, 0);
>> + dtd->dtd_u.dtu_tag.ref_var = NULL;
>> + dtd->dtd_u.dtu_tag.component_idx = comp_idx;
>> +
>> + /* Insert tag directly into the tag list. Type ID will be assigned
>> later. */
>> + vec_safe_push (ctfc->ctfc_tags, dtd);
>> + return dtd;
>> +}
>> +
>> ctf_dtdef_ref
>> ctf_add_forward (ctf_container_ref ctfc, uint32_t flag, const char * name,
>> uint32_t kind, dw_die_ref die)
>> @@ -691,12 +746,12 @@ ctf_add_member_offset (ctf_container_ref ctfc,
>> dw_die_ref sou,
>> return 0;
>> }
>>
>> -int
>> +ctf_dvdef_ref
>> ctf_add_variable (ctf_container_ref ctfc, const char * name, ctf_dtdef_ref
>> ref,
>> dw_die_ref die, unsigned int external_vis,
>> dw_die_ref die_var_decl)
>> {
>> - ctf_dvdef_ref dvd, dvd_ignore;
>> + ctf_dvdef_ref dvd = NULL, dvd_ignore;
>>
>> gcc_assert (name);
>>
>> @@ -732,7 +787,7 @@ ctf_add_variable (ctf_container_ref ctfc, const char *
>> name, ctf_dtdef_ref ref,
>> ctfc->ctfc_strlen += strlen (name) + 1;
>> }
>>
>> - return 0;
>> + return dvd;
>> }
>>
>> int
>> @@ -949,6 +1004,10 @@ new_ctf_container (void)
>> tu_ctfc->ctfc_ignore_vars
>> = hash_table<ctfc_dvd_hasher>::create_ggc (10);
>>
>> + vec_alloc (tu_ctfc->ctfc_tags, 100);
>> + tu_ctfc->ctfc_type_tags_map
>> + = hash_map<ctf_dtdef_ref, ctf_dtdef_ref>::create_ggc (100);
>> +
>> return tu_ctfc;
>> }
>>
>> @@ -1003,6 +1062,11 @@ ctfc_delete_container (ctf_container_ref ctfc)
>> ctfc->ctfc_ignore_vars->empty ();
>> ctfc->ctfc_ignore_vars = NULL;
>>
>> + ctfc->ctfc_tags = NULL;
>> +
>> + ctfc->ctfc_type_tags_map->empty ();
>> + ctfc->ctfc_type_tags_map = NULL;
>> +
>> ctfc_delete_strtab (&ctfc->ctfc_strtable);
>> ctfc_delete_strtab (&ctfc->ctfc_aux_strtable);
>> if (ctfc->ctfc_vars_list)
>> diff --git a/gcc/ctfc.h b/gcc/ctfc.h
>> index 32c73be6a41..756f17f0a9b 100644
>> --- a/gcc/ctfc.h
>> +++ b/gcc/ctfc.h
>> @@ -52,6 +52,10 @@ struct ctf_dtdef;
>> typedef struct ctf_dtdef ctf_dtdef_t;
>> typedef ctf_dtdef_t * ctf_dtdef_ref;
>>
>> +struct ctf_dvdef;
>> +typedef struct ctf_dvdef ctf_dvdef_t;
>> +typedef ctf_dvdef_t * ctf_dvdef_ref;
>> +
>> /* CTF string table element (list node). */
>>
>> typedef struct GTY ((chain_next ("%h.cts_next"))) ctf_string
>> @@ -155,6 +159,14 @@ typedef struct GTY (()) ctf_func_arg
>>
>> #define ctf_farg_list_next(elem) ((ctf_func_arg_t *)((elem)->farg_next))
>>
>> +/* Declaration Tag. */
>> +
>
> Perhaps another one liner will be meaningful here. Something like:
>
> Declaration tags may be used for struct or union members, variable and
> function declarations, and function arguments.
OK
>
>> +typedef struct GTY (()) ctf_decl_tag
>> +{
>> + uint32_t component_idx; /* Index of component to which tag applies. */
>> + ctf_dvdef_ref ref_var; /* Non-null iff this tag applies to a variable.
>> */
>> +} ctf_decl_tag_t;
>> +
>> /* Type definition for CTF generation. */
>>
>> struct GTY ((for_user)) ctf_dtdef
>> @@ -184,6 +196,8 @@ struct GTY ((for_user)) ctf_dtdef
>> ctf_func_arg_t * GTY ((tag ("CTF_DTU_D_ARGUMENTS"))) dtu_argv;
>> /* slice. */
>> ctf_sliceinfo_t GTY ((tag ("CTF_DTU_D_SLICE"))) dtu_slice;
>> + /* decl tag. */
>> + ctf_decl_tag_t GTY ((tag ("CTF_DTU_D_TAG"))) dtu_tag;
>> } dtd_u;
>> };
>>
>> @@ -201,9 +215,6 @@ struct GTY ((for_user)) ctf_dvdef
>> ctf_id_t dvd_id; /* ID of this variable. Only used for BTF. */
>> };
>>
>> -typedef struct ctf_dvdef ctf_dvdef_t;
>> -typedef ctf_dvdef_t * ctf_dvdef_ref;
>> -
>> /* Location information for CTF Types and CTF Variables. */
>>
>> typedef struct GTY (()) ctf_srcloc
>> @@ -222,7 +233,8 @@ enum ctf_dtu_d_union_enum {
>> CTF_DTU_D_ARRAY,
>> CTF_DTU_D_ENCODING,
>> CTF_DTU_D_ARGUMENTS,
>> - CTF_DTU_D_SLICE
>> + CTF_DTU_D_SLICE,
>> + CTF_DTU_D_TAG,
>> };
>>
>> enum ctf_dtu_d_union_enum
>> @@ -287,6 +299,17 @@ typedef struct GTY (()) ctf_container
>> /* CTF variables to be ignored. */
>> hash_table <ctfc_dvd_hasher> * GTY (()) ctfc_ignore_vars;
>>
>> + /* BTF type and decl tags. Not yet represented in CTF. These tags also
>> + uniquely have a one-to-many relation with DIEs, meaning a single DIE
>> + may translate to multiple CTF/BTF records. For both of these reasons,
>> + they cannot be stored in the regular types table. */
>> + vec <ctf_dtdef_ref, va_gc> * GTY (()) ctfc_tags;
>> + /* Type tags logically form part of the type chain similar to cv-quals.
>> + Therefore references to types need to know if the referred-to type has
>> + any type tags, and if so to refer to the outermost type tag. This map
>> + maps a type to the outermost type tag created for it, if any. */
>> + hash_map <ctf_dtdef_ref, ctf_dtdef_ref> * GTY (()) ctfc_type_tags_map;
>> +
>> /* CTF string table. */
>> ctf_strtable_t ctfc_strtable;
>> /* Auxilliary string table. At this time, used for keeping func arg
>> names
>> @@ -440,15 +463,19 @@ extern ctf_dtdef_ref ctf_add_function
>> (ctf_container_ref, uint32_t,
>> dw_die_ref, bool, int);
>> extern ctf_dtdef_ref ctf_add_sou (ctf_container_ref, uint32_t, const char
>> *,
>> uint32_t, size_t, dw_die_ref);
>> -
>> +extern ctf_dtdef_ref ctf_add_type_tag (ctf_container_ref, uint32_t,
>> + const char *, ctf_dtdef_ref);
>> +extern ctf_dtdef_ref ctf_add_decl_tag (ctf_container_ref, uint32_t,
>> + const char *, ctf_dtdef_ref, uint32_t);
>> extern int ctf_add_enumerator (ctf_container_ref, ctf_dtdef_ref, const
>> char *,
>> HOST_WIDE_INT, dw_die_ref);
>> extern int ctf_add_member_offset (ctf_container_ref, dw_die_ref, const
>> char *,
>> ctf_dtdef_ref, uint64_t);
>> extern int ctf_add_function_arg (ctf_container_ref, dw_die_ref,
>> const char *, ctf_dtdef_ref);
>> -extern int ctf_add_variable (ctf_container_ref, const char *, ctf_dtdef_ref,
>> - dw_die_ref, unsigned int, dw_die_ref);
>> +extern ctf_dvdef_ref ctf_add_variable (ctf_container_ref, const char *,
>> + ctf_dtdef_ref, dw_die_ref, unsigned int,
>> + dw_die_ref);
>>
>> extern ctf_dtdef_ref ctf_lookup_tree_type (ctf_container_ref, const tree);
>>
>> diff --git a/gcc/dwarf2ctf.cc b/gcc/dwarf2ctf.cc
>> index 7de3696a4d7..33432a1038c 100644
>> --- a/gcc/dwarf2ctf.cc
>> +++ b/gcc/dwarf2ctf.cc
>> @@ -32,6 +32,15 @@ along with GCC; see the file COPYING3. If not see
>> static ctf_dtdef_ref
>> gen_ctf_type (ctf_container_ref, dw_die_ref);
>>
>> +static ctf_dtdef_ref
>> +gen_ctf_type_tags (ctf_container_ref, dw_die_ref, ctf_dtdef_ref);
>> +
>> +static void
>> +gen_ctf_decl_tags (ctf_container_ref, dw_die_ref, ctf_dtdef_ref, uint32_t);
>> +
>> +static void
>> +gen_ctf_decl_tags_for_var (ctf_container_ref, dw_die_ref, ctf_dvdef_ref);
>> +
>> /* All the DIE structures we handle come from the DWARF information
>> generated by GCC. However, there are three situations where we need
>> to create our own created DIE structures because GCC doesn't
>> @@ -532,6 +541,7 @@ gen_ctf_sou_type (ctf_container_ref ctfc, dw_die_ref
>> sou, uint32_t kind)
>> /* Now process the struct members. */
>> {
>> dw_die_ref c;
>> + uint32_t idx = 0;
>>
>> c = dw_get_die_child (sou);
>> if (c)
>> @@ -616,6 +626,9 @@ gen_ctf_sou_type (ctf_container_ref ctfc, dw_die_ref
>> sou, uint32_t kind)
>> field_name,
>> field_dtd,
>> field_location);
>> +
>> + gen_ctf_decl_tags (ctfc, c, sou_dtd, idx);
>> + idx++;
>> }
>> while (c != dw_get_die_child (sou));
>> }
>> @@ -699,14 +712,18 @@ gen_ctf_function_type (ctf_container_ref ctfc,
>> dw_die_ref function,
>> gcc_assert (i == num_args - 1);
>> /* Add an argument with type 0 and no name. */
>> ctf_add_function_arg (ctfc, function, "", NULL);
>> + /* Handle any declaration tags on the argument. */
>> + gen_ctf_decl_tags (ctfc, c, function_dtd, i);
>> }
>> else if (dw_get_die_tag (c) == DW_TAG_formal_parameter)
>> {
>> - i++;
>> arg_name = get_AT_string (c, DW_AT_name);
>> arg_type = gen_ctf_type (ctfc, ctf_get_AT_type (c));
>> /* Add the argument to the existing CTF function type. */
>> ctf_add_function_arg (ctfc, function, arg_name, arg_type);
>> + /* Handle any declaration tags on the argument. */
>> + gen_ctf_decl_tags (ctfc, c, function_dtd, i);
>> + i++;
>> }
>> else
>> /* This is a local variable. Ignore. */
>> @@ -797,6 +814,7 @@ gen_ctf_variable (ctf_container_ref ctfc, dw_die_ref die)
>> dw_die_ref var_type = ctf_get_AT_type (die);
>> unsigned int external_vis = get_AT_flag (die, DW_AT_external);
>> ctf_dtdef_ref var_dtd;
>> + ctf_dvdef_ref dvd;
>>
>> /* Avoid duplicates. */
>> if (ctf_dvd_lookup (ctfc, die))
>> @@ -817,10 +835,13 @@ gen_ctf_variable (ctf_container_ref ctfc, dw_die_ref
>> die)
>> var_dtd = gen_ctf_type (ctfc, var_type);
>>
>> /* Generate the new CTF variable and update global counter. */
>> - (void) ctf_add_variable (ctfc, var_name, var_dtd, die, external_vis,
>> decl);
>> + dvd = ctf_add_variable (ctfc, var_name, var_dtd, die, external_vis, decl);
>> /* Skip updating the number of global objects at this time. This is
>> updated
>> later after pre-processing as some CTF variable records although
>> generated now, will not be emitted later. [PR105089]. */
>> +
>> + /* Handle declaration tags on the variable. */
>> + gen_ctf_decl_tags_for_var (ctfc, die, dvd);
>> }
>>
>> /* Add a CTF function record for the given input DWARF DIE. */
>> @@ -838,8 +859,119 @@ gen_ctf_function (ctf_container_ref ctfc, dw_die_ref
>> die)
>> counter. Note that DWARF encodes function types in both
>> DW_TAG_subroutine_type and DW_TAG_subprogram in exactly the same
>> way. */
>> - (void) gen_ctf_function_type (ctfc, die, true /* from_global_func */);
>> + function_dtd = gen_ctf_function_type (ctfc, die, true /* from_global_func
>> */);
>> ctfc->ctfc_num_global_funcs += 1;
>> +
>> + /* Handle declaration tags on the function. */
>> + gen_ctf_decl_tags (ctfc, die, function_dtd, -1U);
>> +}
>> +
>> +/* Handle any DW_AT_GNU_annotation on type DIE by constructing a
>> CTF_K_TYPE_TAG
>> + type for the DW_TAG_GNU_annotation DIE to which it points, if this has
>> not
>> + previously been constructed. There may be multiple annotations chained
>> + together by further occurances of DW_AT_GNU_annotation in the annotation
>> + DIEs themselves, in which case a corresponding chain of CTF_K_TYPE_TAG
>> + records is created. The final TYPE_TAG in the chain refers to the dtd
>> for
>> + the annotated type, which should be supplied in REF_DTD.
>> +
>> + Return the ctf_dtdef_t for the outermost TYPE_TAG created, since anything
>> + referring to this type should refer to it via the chain of type tags. */
>> +
>> +static ctf_dtdef_ref
>> +gen_ctf_type_tags (ctf_container_ref ctfc, dw_die_ref die,
>> + ctf_dtdef_ref ref_dtd)
>> +{
>> + if (!btf_debuginfo_p ())
>> + return ref_dtd;
>> + if (!die || !ref_dtd)
>> + return NULL;
>> +
>> + ctf_dtdef_ref *existing = ctfc->ctfc_type_tags_map->get (ref_dtd);
>> + if (existing)
>> + return *existing;
>> +
>> + dw_die_ref annot_die = get_AT_ref (die, DW_AT_GNU_annotation);
>> + ctf_dtdef_ref tag_dtd = ref_dtd;
>> +
>> + /* Recurse first; build the chain from back to front. */
>> + if (annot_die)
>> + tag_dtd = gen_ctf_type_tags (ctfc, annot_die, ref_dtd);
>> +
>> + /* If this is an annotation die, make the tag. */
>> + if (dw_get_die_tag (die) == DW_TAG_GNU_annotation)
>> + {
>> + const char *name = get_AT_string (die, DW_AT_name);
>> + const char *value = get_AT_string (die, DW_AT_const_value);
>> + if (strcmp (name, "btf_type_tag") == 0)
>> + {
>> + tag_dtd = ctf_add_type_tag (ctfc, CTF_ADD_ROOT, value, tag_dtd);
>> + ctfc->ctfc_type_tags_map->put (ref_dtd, tag_dtd);
>> + }
>> + }
>> +
>> + return tag_dtd;
>> +}
>> +
>> +/* Handle any DW_AT_GNU_annotation on decl DIE by constructing a
>> CTF_K_DECL_TAG
>> + type for the DW_TAG_GNU_annotation DIE to which it points, if this has
>> not
>> + been previously constructed. There may be multiple annotations chained
>> + together by further occurances of DW_AT_GNU_annotation in the annoation
>> DIEs
>> + themselves, in which case a corresponding CTF_K_DECL_TAG type is created
>> for
>> + each. Unlike TYPE_TAGs, which form a chain, each DECL_TAG individually
>> + refers directly to the annotated decl, which should be supplied in
>> REF_DTD.
>
> Which is why they cannot be deduplicated across usages.
Right.
>
> I see that you mention this aspect also in ctf_add_decl_tag (), but I
> think its worthwhile to mention it explicitly here again.
Makes sense to me, I'll add a note to the comment.
>
>> + IDX is the zero-based component index indicating to which function
>> parameter
>> + or struct or union member the DECL_TAG refers, or (uint32_t) -1 if it
>> refers
>> + to a function decl or sou itself. */
>> +> +static void
>> +gen_ctf_decl_tags (ctf_container_ref ctfc, dw_die_ref die,
>> + ctf_dtdef_ref ref_dtd, uint32_t idx)
>> +{
>> + if (!btf_debuginfo_p () || !die || !ref_dtd)
>> + return;
>> +
>> + dw_die_ref annot_die = get_AT_ref (die, DW_AT_GNU_annotation);
>> + while (annot_die)
>> + {
>> + const char *name = get_AT_string (annot_die, DW_AT_name);
>> + const char *value = get_AT_string (annot_die, DW_AT_const_value);
>> +
>> + if (strcmp (name, "btf_decl_tag") == 0)
>> + (void) ctf_add_decl_tag (ctfc, CTF_ADD_ROOT, value, ref_dtd, idx);
>> +
>> + annot_die = get_AT_ref (annot_die, DW_AT_GNU_annotation);
>> + }
>> +}
>> +
>> +/* Like gen_ctf_decl_tags above, but specifically for variables.
>> Declaration
>> + tags may appear on variables or other declarations like functions, but
>> due
>> + to the distinction in CTF between variables and types the processing in
>> + each case is slightly different. REF_DVD is the CTF record for the
>> variable
>> + which is annotated. */
>> +
>> +static void
>> +gen_ctf_decl_tags_for_var (ctf_container_ref ctfc, dw_die_ref die,
>> + ctf_dvdef_ref ref_dvd)
>> +{
>> + if (!btf_debuginfo_p () || !die || !ref_dvd)
>> + return;
>> +
>> + ctf_dtdef_ref tag_dtd = NULL;
>> +
>> + dw_die_ref annot_die = get_AT_ref (die, DW_AT_GNU_annotation);
>> + while (annot_die)
>> + {
>> + const char *name = get_AT_string (annot_die, DW_AT_name);
>> + const char *value = get_AT_string (annot_die, DW_AT_const_value);
>> +
>> + if (strcmp (name, "btf_decl_tag") == 0)
>> + {
>> + tag_dtd = ctf_add_decl_tag (ctfc, CTF_ADD_ROOT, value, NULL, -1U);
>> + tag_dtd->dtd_u.dtu_tag.ref_var = ref_dvd;
>> + }
>> +
>> + annot_die = get_AT_ref (annot_die, DW_AT_GNU_annotation);
>> + }
>> }
>>
>> /* Add CTF type record(s) for the given input DWARF DIE and return its
>> type id.
>> @@ -857,7 +989,12 @@ gen_ctf_type (ctf_container_ref ctfc, dw_die_ref die)
>> int unrecog_die = false;
>>
>> if (ctf_type_exists (ctfc, die, &dtd))
>> - return dtd;
>> + {
>> + if (btf_debuginfo_p ())
>> + return gen_ctf_type_tags (ctfc, die, dtd);
>> + else
>> + return dtd;
>> + }
>>
>> switch (dw_get_die_tag (die))
>> {
>> @@ -906,6 +1043,10 @@ gen_ctf_type (ctf_container_ref ctfc, dw_die_ref die)
>>
>> break;
>> }
>> + case DW_TAG_GNU_annotation:
>> + dtd = NULL;
>> + unrecog_die = true;
>> + break;
>
> Hmm... this can be confusing later. The DW_TAG_GNU_annotation is now
> represented in CTF, albeit only in-memory representation.
>
> Should we add a comment that these dies are traversed explicitly in
> dwarf2ctf by following the DW_AT_GNU_annotation ?
OK
>
>> case DW_TAG_reference_type:
>> dtd = NULL;
>> break;
>> @@ -916,6 +1057,9 @@ gen_ctf_type (ctf_container_ref ctfc, dw_die_ref die)
>> break;
>> }
>>
>> + if (dtd)
>> + dtd = gen_ctf_type_tags (ctfc, die, dtd);
>> +
>
> Nit: I see that gen_ctf_type_tags () has an early exit if
> !btf_debuginfo_p(), but just to keep this invocation of
> gen_ctf_type_tags () similar looking as the one above (it does help
> readability IMO), perhaps include a check for btf_debuginfo_p () here too ?
You're right. Thanks for catching the inconsistency, will fix it.
>
>> /* For all types unrepresented in CTF, use an explicit CTF type of kind
>> CTF_K_UNKNOWN. */
>> if ((dtd == NULL) && (!unrecog_die))
>> diff --git a/gcc/testsuite/gcc.dg/debug/ctf/ctf-decl-tag-1.c
>> b/gcc/testsuite/gcc.dg/debug/ctf/ctf-decl-tag-1.c
>> new file mode 100644
>> index 00000000000..564bbc76468
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/debug/ctf/ctf-decl-tag-1.c
>> @@ -0,0 +1,31 @@
>> +/* CTF generation for btf_decl_tag attribute.
>> +
>> + CTF does not encode these attributes and no CTF_K_DECL_TAG record should
>> be
>> + emitted; these records only exist internally to facilitate translation
>> + to BTF. */
>> +
>> +/* { dg-do compile } */
>> +/* { dg-options "-O0 -gctf -dA" } */
>> +
>> +int x __attribute__((btf_decl_tag ("some_tag")));
>> +
>> +struct S {
>> + int a;
>> + int b __attribute__((btf_decl_tag ("_b")));
>> + int c;
>> +};
>> +
>> +struct S some_S;
>> +
>> +void
>> +__attribute__((btf_decl_tag ("__func")))
>> +foo (int *ptr __attribute__((btf_decl_tag ("w"))), int val)
>> +{
>> + *ptr = val;
>> +}
>> +
>> +/* Expect 5 CTF types: int, struct, void, int*, void (int*, int). */
>> +/* { dg-final { scan-assembler-times "ctt_info" 5 } } */
>> +/* Ensure no CTF_K_DECL_TAG record is emitted. */
>> +/* { dg-final { scan-assembler-not "\[\t \]0x3c*\[\t \]+\[^\n\]*ctt_info" }
>> } */
>> +/* { dg-final { scan-assembler-not "\[\t \]0x3e*\[\t \]+\[^\n\]*ctt_info" }
>> } */
>> diff --git a/gcc/testsuite/gcc.dg/debug/ctf/ctf-type-tag-1.c
>> b/gcc/testsuite/gcc.dg/debug/ctf/ctf-type-tag-1.c
>> new file mode 100644
>> index 00000000000..ca37ef44fe2
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/debug/ctf/ctf-type-tag-1.c
>> @@ -0,0 +1,19 @@
>> +/* CTF generation for btf_type_tag attribute.
>> +
>> + CTF does not encode these attributes and no CTF_K_TYPE_TAG record should
>> be
>> + emitted; these records only exist internally to facilitate translation
>> + to BTF. */
>> +
>> +/* { dg-do compile } */
>> +/* { dg-options "-O0 -gctf -dA" } */
>> +
>> +int * __attribute__((btf_type_tag ("some_tag"))) x;
>> +
>> +typedef unsigned int __attribute__((btf_type_tag ("other_tag"))) uint;
>> +const uint u;
>> +
>> +/* Expect 5 CTF types: int, int*, unsigned int, typedef, const. */
>> +/* { dg-final { scan-assembler-times "ctt_info" 5 } } */
>> +/* Ensure no CTF_K_TYPE_TAG record is emitted. */
>> +/* { dg-final { scan-assembler-not "\[\t \]0x40*\[\t \]+\[^\n\]*ctt_info" }
>> } */
>> +/* { dg-final { scan-assembler-not "\[\t \]0x42*\[\t \]+\[^\n\]*ctt_info" }
>> } */
>> diff --git a/include/ctf.h b/include/ctf.h
>> index 72a639ac9b4..f75e337ba0f 100644
>> --- a/include/ctf.h
>> +++ b/include/ctf.h
>> @@ -423,6 +423,10 @@ union
>> #define CTF_K_CONST 12 /* ctt_type is base type. */
>> #define CTF_K_RESTRICT 13 /* ctt_type is base type. */
>> #define CTF_K_SLICE 14 /* Variant data is a ctf_slice_t. */
>> +#define CTF_K_DECL_TAG 15 /* Declaration tag. Internal use only.
>> + Not valid externally until CTF V4. */
>> +#define CTF_K_TYPE_TAG 16 /* Type tag. Internal use only.
>> + Not valid externally until CTF V4. */
>>
>> #define CTF_K_MAX 63 /* Maximum possible (V2) CTF_K_* value. */
>>
>