From eb0fa8bfa356d49198f98b878b004bce59232bb0 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Thu, 4 Nov 2021 13:23:19 -0700 Subject: [PATCH] [Clang][Attr] Support btf_type_tag attribute This patch introduced btf_type_tag attribute. The attribute is a type attribute and intends to address the below linux use cases. typedef int __user *__intp; int foo(int __user *arg, ...) static int do_execve(struct filename *filename, const char __user *const __user *__argv, const char __user *const __user *__envp) Here __user in the kernel defined as __attribute__((noderef, address_space(__user))) for sparse ([1]) type checking mode. For normal clang compilation, we intend to replace it with __attribute__((btf_type_tag("user"))) and record such informaiton in dwarf and BTF so such information later can be used in kernel for bpf verification or for other tracing functionalities. [1] https://www.kernel.org/doc/html/v4.11/dev-tools/sparse.html Differential Revision: https://reviews.llvm.org/D111199 --- clang/include/clang/Basic/Attr.td | 7 +++++++ clang/include/clang/Basic/AttrDocs.td | 17 +++++++++++++++++ clang/lib/AST/TypePrinter.cpp | 3 +++ clang/lib/Sema/SemaType.cpp | 36 +++++++++++++++++++++++++++++++++++ clang/test/Sema/attr-btf_type_tag.c | 25 ++++++++++++++++++++++++ 5 files changed, 88 insertions(+) create mode 100644 clang/test/Sema/attr-btf_type_tag.c diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 31ca7d2..a5443c9 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1845,6 +1845,13 @@ def BTFDeclTag : InheritableAttr { let LangOpts = [COnly]; } +def BTFTypeTag : TypeAttr { + let Spellings = [Clang<"btf_type_tag">]; + let Args = [StringArgument<"BTFTypeTag">]; + let Documentation = [BTFTypeTagDocs]; + let LangOpts = [COnly]; +} + def WebAssemblyExportName : InheritableAttr, TargetSpecificAttr { let Spellings = [Clang<"export_name">]; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 09477d6..e7afb36 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -2023,6 +2023,23 @@ section too. }]; } +def BTFTypeTagDocs : Documentation { + let Category = DocCatType; + let Content = [{ +Clang supports the ``__attribute__((btf_type_tag("ARGUMENT")))`` attribute for +all targets. It only has effect when ``-g`` is specified on the command line and +is currently silently ignored when not applied to a pointer type (note: this +scenario may be diagnosed in the future). + +The ``ARGUMENT`` string will be preserved in IR and emitted to DWARF for the +types used in variable declarations, function declarations, or typedef +declarations. + +For BPF targets, the ``ARGUMENT`` string will also be emitted to .BTF ELF +section. + }]; +} + def MipsInterruptDocs : Documentation { let Category = DocCatFunction; let Heading = "interrupt (MIPS)"; diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index 40127f1..eca9af3 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1746,6 +1746,9 @@ void TypePrinter::printAttributedAfter(const AttributedType *T, case attr::ArmMveStrictPolymorphism: OS << "__clang_arm_mve_strict_polymorphism"; break; + case attr::BTFTypeTag: + OS << "btf_type_tag"; + break; } OS << "))"; } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 5918876..3512165 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -5900,6 +5900,9 @@ namespace { void VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { Visit(TL.getUnqualifiedLoc()); } + // Allow to fill pointee's type locations, e.g., + // int __attr * __attr * __attr *p; + void VisitPointerTypeLoc(PointerTypeLoc TL) { Visit(TL.getNextTypeLoc()); } void VisitTypedefTypeLoc(TypedefTypeLoc TL) { TL.setNameLoc(DS.getTypeSpecTypeLoc()); } @@ -6500,6 +6503,34 @@ QualType Sema::BuildAddressSpaceAttr(QualType &T, Expr *AddrSpace, return BuildAddressSpaceAttr(T, ASIdx, AddrSpace, AttrLoc); } +static void HandleBTFTypeTagAttribute(QualType &Type, const ParsedAttr &Attr, + TypeProcessingState &State) { + Sema &S = State.getSema(); + + // Check the number of attribute arguments. + if (Attr.getNumArgs() != 1) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) + << Attr << 1; + Attr.setInvalid(); + return; + } + + // Ensure the argument is a string. + auto *StrLiteral = dyn_cast(Attr.getArgAsExpr(0)); + if (!StrLiteral) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) + << Attr << AANT_ArgumentString; + Attr.setInvalid(); + return; + } + + ASTContext &Ctx = S.Context; + StringRef BTFTypeTag = StrLiteral->getString(); + Type = State.getAttributedType( + ::new (Ctx) BTFTypeTagAttr(Ctx, Attr, BTFTypeTag), Type, Type); + return; +} + /// HandleAddressSpaceTypeAttribute - Process an address_space attribute on the /// specified type. The attribute contains 1 argument, the id of the address /// space for the type. @@ -8129,6 +8160,11 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, case ParsedAttr::IgnoredAttribute: break; + case ParsedAttr::AT_BTFTypeTag: + HandleBTFTypeTagAttribute(type, attr, state); + attr.setUsedAsTypeAttr(); + break; + case ParsedAttr::AT_MayAlias: // FIXME: This attribute needs to actually be handled, but if we ignore // it it breaks large amounts of Linux software. diff --git a/clang/test/Sema/attr-btf_type_tag.c b/clang/test/Sema/attr-btf_type_tag.c new file mode 100644 index 0000000..b40d0e4 --- /dev/null +++ b/clang/test/Sema/attr-btf_type_tag.c @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -x c -triple x86_64-pc-linux-gnu -dwarf-version=4 -fsyntax-only -verify %s + +#define __tag1 __attribute__((btf_type_tag("tag1"))) +#define __tag2 __attribute__((btf_type_tag("tag2"))) +#define __tag3 __attribute__((btf_type_tag("tag3"))) +#define __tag4 __attribute__((btf_type_tag("tag4"))) +#define __tag5 __attribute__((btf_type_tag("tag5"))) +#define __tag6 __attribute__((btf_type_tag("tag6"))) + +int __attribute__((btf_type_tag("tag1", "tag2"))) *invalid1; // expected-error {{'btf_type_tag' attribute takes one argument}} +int __attribute__((btf_type_tag(2))) *invalid2; // expected-error {{'btf_type_tag' attribute requires a string}} + +int * __tag1 __tag2 * __tag3 __tag4 * __tag5 __tag6 *g; + +typedef void __fn_t(int); +typedef __fn_t __tag1 __tag2 * __tag3 __tag4 *__fn2_t; +struct t { + int __tag1 * __tag2 * __tag3 *a; + int __tag1 __tag2 __tag3 *b; + __fn2_t c; + long d; +}; +int __tag4 * __tag5 * __tag6 *foo1(struct t __tag1 * __tag2 * __tag3 *a1) { + return (int __tag4 * __tag5 * __tag6 *)a1[0][0]->d; +} -- 2.7.4