diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 28695b9b6967..53faac82c404 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -450,6 +450,15 @@ def XRayInstrument : InheritableAttr { let Documentation = [XRayDocs]; } +def XRayLogArgs : InheritableAttr { + let Spellings = [GNU<"xray_log_args">, CXX11<"clang", "xray_log_args">]; + let Subjects = SubjectList< + [CXXMethod, ObjCMethod, Function], WarnDiag, "ExpectedFunctionOrMethod" + >; + let Args = [UnsignedArgument<"ArgumentCount">]; + let Documentation = [XRayDocs]; +} + def TLSModel : InheritableAttr { let Spellings = [GCC<"tls_model">]; let Subjects = SubjectList<[TLSVar], ErrorDiag, "ExpectedTLSVar">; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index e0c1de12829a..e8a1f71b4220 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -2862,13 +2862,15 @@ See the RenderScript_ documentation for more information. def XRayDocs : Documentation { let Category = DocCatFunction; - let Heading = "xray_always_instrument (clang::xray_always_instrument), xray_never_instrument (clang::xray_never_instrument)"; + let Heading = "xray_always_instrument (clang::xray_always_instrument), xray_never_instrument (clang::xray_never_instrument), xray_log_args (clang::xray_log_args)"; let Content = [{ ``__attribute__((xray_always_instrument))`` or ``[[clang::xray_always_instrument]]`` is used to mark member functions (in C++), methods (in Objective C), and free functions (in C, C++, and Objective C) to be instrumented with XRay. This will cause the function to always have space at the beginning and exit points to allow for runtime patching. Conversely, ``__attribute__((xray_never_instrument))`` or ``[[clang::xray_never_instrument]]`` will inhibit the insertion of these instrumentation points. If a function has neither of these attributes, they become subject to the XRay heuristics used to determine whether a function should be instrumented or otherwise. + +``__attribute__((xray_log_args(N)))`` or ``[[clang::xray_log_args(N)]]`` is used to preserve N function arguments for the logging function. Currently, only N==1 is supported. }]; } diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 1ebfd798c551..bad963b6fa30 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -779,6 +779,10 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, Fn->addFnAttr("function-instrument", "xray-always"); if (XRayAttr->neverXRayInstrument()) Fn->addFnAttr("function-instrument", "xray-never"); + if (const auto *LogArgs = D->getAttr()) { + Fn->addFnAttr("xray-log-args", + llvm::utostr(LogArgs->getArgumentCount())); + } } else { Fn->addFnAttr( "xray-instruction-threshold", diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 9b15a06de9f9..3979383966c8 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -4424,6 +4424,19 @@ static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D, Attr.getAttributeSpellingListIndex())); } +static void handleXRayLogArgsAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + uint64_t ArgCount; + if (!checkFunctionOrMethodParameterIndex(S, D, Attr, 1, Attr.getArgAsExpr(0), + ArgCount)) + return; + + // ArgCount isn't a parameter index [0;n), it's a count [1;n] - hence + 1. + D->addAttr(::new (S.Context) + XRayLogArgsAttr(Attr.getRange(), S.Context, ++ArgCount, + Attr.getAttributeSpellingListIndex())); +} + //===----------------------------------------------------------------------===// // Checker-specific attribute handlers. //===----------------------------------------------------------------------===// @@ -6285,6 +6298,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_XRayInstrument: handleSimpleAttribute(S, D, Attr); break; + case AttributeList::AT_XRayLogArgs: + handleXRayLogArgsAttr(S, D, Attr); + break; } } diff --git a/clang/test/CodeGen/xray-log-args.cpp b/clang/test/CodeGen/xray-log-args.cpp new file mode 100644 index 000000000000..d4f4a1ba851b --- /dev/null +++ b/clang/test/CodeGen/xray-log-args.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 %s -fxray-instrument -std=c++11 -x c++ -emit-llvm -o - -triple x86_64-unknown-linux-gnu | FileCheck %s + +// Make sure that the LLVM attribute for XRay-annotated functions do show up. +[[clang::xray_always_instrument,clang::xray_log_args(1)]] void foo(int a) { +// CHECK: define void @_Z3fooi(i32 %a) #0 +}; + +[[clang::xray_log_args(1)]] void bar(int a) { +// CHECK: define void @_Z3bari(i32 %a) #1 +}; + +// CHECK: #0 = {{.*}}"function-instrument"="xray-always"{{.*}}"xray-log-args"="1" +// CHECK-NOT: #1 = {{.*}}"xray-log-args"="1" diff --git a/clang/test/Sema/xray-log-args-oob.c b/clang/test/Sema/xray-log-args-oob.c new file mode 100644 index 000000000000..a6be0f81cb47 --- /dev/null +++ b/clang/test/Sema/xray-log-args-oob.c @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 %s -verify -fsyntax-only -std=c11 +void foo(int) __attribute__((xray_log_args(1))); +struct __attribute__((xray_log_args(1))) a { int x; }; // expected-warning {{'xray_log_args' attribute only applies to functions and methods}} + +void fop() __attribute__((xray_log_args(1))); // expected-error {{'xray_log_args' attribute parameter 1 is out of bounds}} + +void foq() __attribute__((xray_log_args(-1))); // expected-error {{'xray_log_args' attribute parameter 1 is out of bounds}} + +void fos() __attribute__((xray_log_args(0))); // expected-error {{'xray_log_args' attribute parameter 1 is out of bounds}} diff --git a/clang/test/Sema/xray-log-args-oob.cpp b/clang/test/Sema/xray-log-args-oob.cpp new file mode 100644 index 000000000000..414bce0c334a --- /dev/null +++ b/clang/test/Sema/xray-log-args-oob.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 %s -verify -fsyntax-only -std=c++11 -x c++ +void foo [[clang::xray_log_args(1)]] (int); +struct [[clang::xray_log_args(1)]] a { int x; }; // expected-warning {{'xray_log_args' attribute only applies to functions and methods}} + +void fop [[clang::xray_log_args(1)]] (); // expected-error {{'xray_log_args' attribute parameter 1 is out of bounds}} + +void foq [[clang::xray_log_args(-1)]] (); // expected-error {{'xray_log_args' attribute parameter 1 is out of bounds}} + +void fos [[clang::xray_log_args(0)]] (); // expected-error {{'xray_log_args' attribute parameter 1 is out of bounds}}