Add two new c-family attributes, "btf_type_tag" and "btf_decl_tag" along with attribute handlers for them. These attributes may be used to annotate types or declarations respectively with arbitrary strings, which will be recorded in DWARF and/or BTF information. Both attributes accept exactly one string argument. Wide strings are not supported.
gcc/c-family/ * c-attribs.cc (c_common_attribute_table): Add btf_decl_tag and btf_type_tag attributes. (handle_btf_decl_tag_attribute): New handler for btf_decl_tag. (hanlde_btf_type_tag_attribute): New handler for btf_type_tag. (btf_tag_args_ok): Helper for new attribute handlers. gcc/testsuite/ * gcc.dg/attr-btf-decl-tag-1.c: New test. * gcc.dg/attr-btf-decl-tag-2.c: New test. * gcc.dg/attr-btf-type-tag-1.c: New test. * gcc.dg/attr-btf-type-tag-2.c: New test. --- gcc/c-family/c-attribs.cc | 120 ++++++++++++++++++++- gcc/testsuite/gcc.dg/attr-btf-decl-tag-1.c | 14 +++ gcc/testsuite/gcc.dg/attr-btf-decl-tag-2.c | 15 +++ gcc/testsuite/gcc.dg/attr-btf-type-tag-1.c | 12 +++ gcc/testsuite/gcc.dg/attr-btf-type-tag-2.c | 9 ++ 5 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.dg/attr-btf-decl-tag-1.c create mode 100644 gcc/testsuite/gcc.dg/attr-btf-decl-tag-2.c create mode 100644 gcc/testsuite/gcc.dg/attr-btf-type-tag-1.c create mode 100644 gcc/testsuite/gcc.dg/attr-btf-type-tag-2.c diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc index 5a0e3d328ba..07b8da9ae0f 100644 --- a/gcc/c-family/c-attribs.cc +++ b/gcc/c-family/c-attribs.cc @@ -189,6 +189,9 @@ static tree handle_fd_arg_attribute (tree *, tree, tree, int, bool *); static tree handle_flag_enum_attribute (tree *, tree, tree, int, bool *); static tree handle_null_terminated_string_arg_attribute (tree *, tree, tree, int, bool *); +static tree handle_btf_decl_tag_attribute (tree *, tree, tree, int, bool *); +static tree handle_btf_type_tag_attribute (tree *, tree, tree, int, bool *); + /* Helper to define attribute exclusions. */ #define ATTR_EXCL(name, function, type, variable) \ { name, function, type, variable } @@ -640,7 +643,11 @@ const struct attribute_spec c_common_gnu_attributes[] = { "flag_enum", 0, 0, false, true, false, false, handle_flag_enum_attribute, NULL }, { "null_terminated_string_arg", 1, 1, false, true, true, false, - handle_null_terminated_string_arg_attribute, NULL} + handle_null_terminated_string_arg_attribute, NULL}, + { "btf_type_tag", 1, 1, false, true, false, false, + handle_btf_type_tag_attribute, NULL}, + { "btf_decl_tag", 1, 1, true, false, false, false, + handle_btf_decl_tag_attribute, NULL} }; const struct scoped_attribute_specs c_common_gnu_attribute_table = @@ -5101,6 +5108,117 @@ handle_null_terminated_string_arg_attribute (tree *node, tree name, tree args, return NULL_TREE; } +/* Common argument checking for btf_type_tag and btf_decl_tag. + Return true if the ARGS are valid, otherwise emit an error and + return false. */ + +static bool +btf_tag_args_ok (tree name, tree args) +{ + if (!args) /* Correct number of args (1) is checked for us. */ + return false; + else if (TREE_CODE (TREE_VALUE (args)) != STRING_CST) + { + error ("%qE attribute requires a string argument", name); + return false; + } + + /* Only narrow character strings are accepted. */ + tree argtype = TREE_TYPE (TREE_TYPE (TREE_VALUE (args))); + if (!(argtype == char_type_node + || argtype == char8_type_node + || argtype == signed_char_type_node + || argtype == unsigned_char_type_node)) + { + error ("unsupported wide string type argument in %qE attribute", name); + return false; + } + + return true; +} + +/* Handle the "btf_decl_tag" attribute. */ + +static tree +handle_btf_decl_tag_attribute (tree * ARG_UNUSED (node), tree name, tree args, + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + if (!btf_tag_args_ok (name, args)) + *no_add_attrs = true; + + return NULL_TREE; +} + +/* Handle the "btf_type_tag" attribute. */ + +static tree +handle_btf_type_tag_attribute (tree *node, tree name, tree args, + int flags, bool *no_add_attrs) +{ + if (!btf_tag_args_ok (name, args)) + { + *no_add_attrs = true; + return NULL_TREE; + } + + if (TREE_CODE (*node) == FUNCTION_TYPE || TREE_CODE (*node) == METHOD_TYPE) + { + /* Treat btf_type_tag applied to a function type as applying to the + return type instead. Otherwise with GNU syntax there is no way to + apply type_tag to the return type; the parser always associates it + to the function_type node. btf_decl_tag can (should) be used to + annotate the function itself. */ + tree ret_type = TREE_TYPE (*node); + tree new_attrs = tree_cons (name, args, TYPE_ATTRIBUTES (ret_type)); + tree new_type = build_type_attribute_qual_variant (ret_type, + new_attrs, + TYPE_QUALS (ret_type)); + *node = lang_hooks.types.reconstruct_complex_type (*node, new_type); + + *no_add_attrs = true; + return NULL_TREE; + } + + /* Ensure a variant type is always created to hold the type_tag, + unless ATTR_FLAG_IN_PLACE is set. Same logic as in + common_handle_aligned_attribute. */ + tree decl = NULL_TREE; + tree *type = NULL; + bool is_type = false; + + if (DECL_P (*node)) + { + decl = *node; + type = &TREE_TYPE (decl); + is_type = TREE_CODE (*node) == TYPE_DECL; + } + else if (TYPE_P (*node)) + type = node, is_type = true; + + if (is_type) + { + if ((flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) + /* OK, modify the type in place. */; + + /* If we have a TYPE_DECL, then copy the type, so that we + don't accidentally modify a builtin type. See pushdecl. */ + else if (decl && TREE_TYPE (decl) != error_mark_node + && DECL_ORIGINAL_TYPE (decl) == NULL_TREE) + { + tree tt = TREE_TYPE (decl); + *type = build_variant_type_copy (*type); + DECL_ORIGINAL_TYPE (decl) = tt; + TYPE_NAME (*type) = decl; + TREE_USED (*type) = TREE_USED (decl); + TREE_TYPE (decl) = *type; + } + else + *type = build_variant_type_copy (*type); + } + + return NULL_TREE; +} + /* Handle the "nonstring" variable attribute. */ static tree diff --git a/gcc/testsuite/gcc.dg/attr-btf-decl-tag-1.c b/gcc/testsuite/gcc.dg/attr-btf-decl-tag-1.c new file mode 100644 index 00000000000..d26d992c44d --- /dev/null +++ b/gcc/testsuite/gcc.dg/attr-btf-decl-tag-1.c @@ -0,0 +1,14 @@ +/* Test btf_decl_tag attribute argument checking. */ +/* { dg-do compile } */ + +void *vptr __attribute__((btf_decl_tag("vptr"), btf_decl_tag ("perthread"))); + +struct Foo +{ + int x __attribute__((btf_decl_tag (0x55))); /* { dg-error "requires a string" } */ + char *c __attribute__((btf_decl_tag (L"Lstr"))); /* { dg-error "unsupported wide string" } */ +}; + +extern int foo (int x, int y __attribute__((btf_decl_tag))); /* { dg-error "wrong number of arguments" } */ + +char *str __attribute__((btf_decl_tag("A", "B"))); /* { dg-error "wrong number of arguments" } */ diff --git a/gcc/testsuite/gcc.dg/attr-btf-decl-tag-2.c b/gcc/testsuite/gcc.dg/attr-btf-decl-tag-2.c new file mode 100644 index 00000000000..956e20eb2ef --- /dev/null +++ b/gcc/testsuite/gcc.dg/attr-btf-decl-tag-2.c @@ -0,0 +1,15 @@ +/* Test btf_decl_tag attribute argument checking for wide string types. */ +/* { dg-do compile } */ +/* { dg-options "--std=c11" } */ + +int **my_ptr __attribute__((btf_decl_tag("my_ptr"))); + +void *x __attribute__((btf_decl_tag (U"Ustr"))); /* { dg-error "unsupported wide string" } */ + +const int y __attribute__((btf_decl_tag (u"ustr"))); /* { dg-error "unsupported wide string" } */ + +union U +{ + int x; + char c __attribute__((btf_decl_tag (u8"u8str"))); /* OK. */ +}; diff --git a/gcc/testsuite/gcc.dg/attr-btf-type-tag-1.c b/gcc/testsuite/gcc.dg/attr-btf-type-tag-1.c new file mode 100644 index 00000000000..2ed54ae5be3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/attr-btf-type-tag-1.c @@ -0,0 +1,12 @@ +/* Test btf_type_tag attribute argument checking. */ +/* { dg-do compile } */ + +void * __attribute__((btf_type_tag ("A"), btf_type_tag ("vptr"))) a; + +int __attribute__((btf_type_tag (5))) b; /* { dg-error "requires a string" } */ + +char * __attribute__((btf_type_tag (L"Lstr"))) c; /* { dg-error "unsupported wide string" } */ + +int * __attribute__((btf_type_tag)) d; /* { dg-error "wrong number of arguments" } */ + +char * __attribute__((btf_type_tag ("A", "B"))) e; /* { dg-error "wrong number of arguments" } */ diff --git a/gcc/testsuite/gcc.dg/attr-btf-type-tag-2.c b/gcc/testsuite/gcc.dg/attr-btf-type-tag-2.c new file mode 100644 index 00000000000..edc22b11ef8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/attr-btf-type-tag-2.c @@ -0,0 +1,9 @@ +/* Test btf_type_tag attribute argument checking for wide string types. */ +/* { dg-do compile } */ +/* { dg-options "--std=c11" } */ + +int __attribute__((btf_type_tag (U"Ustr"))) x; /* { dg-error "unsupported wide string" } */ + +int __attribute__((btf_type_tag (u"ustr"))) y; /* { dg-error "unsupported wide string" } */ + +int __attribute__((btf_type_tag (u8"u8str"))) z; /* OK. */ -- 2.47.2