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
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<TargetWebAssembly> {
let Spellings = [Clang<"export_name">];
}];
}
+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)";
case attr::ArmMveStrictPolymorphism:
OS << "__clang_arm_mve_strict_polymorphism";
break;
+ case attr::BTFTypeTag:
+ OS << "btf_type_tag";
+ break;
}
OS << "))";
}
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());
}
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<StringLiteral>(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.
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.
--- /dev/null
+// 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;
+}