#include "clang/Basic/SanitizerBlacklist.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
+#include "clang/Basic/XRayLists.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
/// entities should not be instrumented.
std::unique_ptr<SanitizerBlacklist> SanitizerBL;
+ /// \breif Function filtering mehcanism to determine whether a given function
+ /// should be imbued with the XRay "always" or "never" attributes.
+ std::unique_ptr<XRayFunctionFilter> XRayFilter;
+
/// \brief The allocator used to create AST objects.
///
/// AST objects are never destructed; rather, all memory associated with the
return *SanitizerBL;
}
+ const XRayFunctionFilter &getXRayFilter() const {
+ return *XRayFilter;
+ }
+
DiagnosticsEngine &getDiagnostics() const;
FullSourceLoc getFullLoc(SourceLocation Loc) const {
"field padding (0: none, 1:least "
"aggressive, 2: more aggressive)")
+LANGOPT(XRayInstrument, 1, 0, "controls whether to do XRay instrumentation")
+
#undef LANGOPT
#undef COMPATIBLE_LANGOPT
#undef BENIGN_LANGOPT
/// (files, functions, variables) should not be instrumented.
std::vector<std::string> SanitizerBlacklistFiles;
+ /// \brief Paths to the XRay "always instrument" files specifying which
+ /// objects (files, functions, variables) should be imbued with the XRay
+ /// "always instrument" attribute.
+ std::vector<std::string> XRayAlwaysInstrumentFiles;
+
+ /// \brief Paths to the XRay "never instrument" files specifying which
+ /// objects (files, functions, variables) should be imbued with the XRay
+ /// "never instrument" attribute.
+ std::vector<std::string> XRayNeverInstrumentFiles;
+
clang::ObjCRuntime ObjCRuntime;
std::string ObjCConstantStringClass;
--- /dev/null
+//===--- XRayLists.h - XRay automatic attribution ---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// User-provided filters for always/never XRay instrumenting certain functions.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_BASIC_XRAYLISTS_H
+#define LLVM_CLANG_BASIC_XRAYLISTS_H
+
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/SpecialCaseList.h"
+#include <memory>
+
+namespace clang {
+
+class XRayFunctionFilter {
+ std::unique_ptr<llvm::SpecialCaseList> AlwaysInstrument;
+ std::unique_ptr<llvm::SpecialCaseList> NeverInstrument;
+ SourceManager &SM;
+
+public:
+ XRayFunctionFilter(ArrayRef<std::string> AlwaysInstrumentPaths,
+ ArrayRef<std::string> NeverInstrumentPaths,
+ SourceManager &SM);
+
+ enum class ImbueAttribute {
+ NONE,
+ ALWAYS,
+ NEVER,
+ };
+
+ ImbueAttribute shouldImbueFunction(StringRef FunctionName) const;
+
+ ImbueAttribute
+ shouldImbueFunctionsInFile(StringRef Filename,
+ StringRef Category = StringRef()) const;
+
+ ImbueAttribute shouldImbueLocation(SourceLocation Loc,
+ StringRef Category = StringRef()) const;
+};
+
+} // namespace clang
+
+#endif
JoinedOrSeparate<["-"], "fxray-instruction-threshold">,
Group<f_Group>, Flags<[CC1Option]>;
+def fxray_always_instrument :
+ JoinedOrSeparate<["-"], "fxray-always-instrument=">,
+ Group<f_Group>, Flags<[CC1Option]>,
+ HelpText<"Filename defining the whitelist for imbuing the 'always instrument' XRay attribute.">;
+def fxray_never_instrument :
+ JoinedOrSeparate<["-"], "fxray-never-instrument=">,
+ Group<f_Group>, Flags<[CC1Option]>,
+ HelpText<"Filename defining the whitelist for imbuing the 'never instrument' XRay attribute.">;
+
def flat__namespace : Flag<["-"], "flat_namespace">;
def flax_vector_conversions : Flag<["-"], "flax-vector-conversions">, Group<f_Group>;
def flimited_precision_EQ : Joined<["-"], "flimited-precision=">, Group<f_Group>;
class RegisterEffectiveTriple;
class SanitizerArgs;
class Tool;
+ class XRayArgs;
/// ToolChain - Access to tools for a single platform.
class ToolChain {
Tool *getOffloadBundler() const;
mutable std::unique_ptr<SanitizerArgs> SanitizerArguments;
+ mutable std::unique_ptr<XRayArgs> XRayArguments;
/// The effective clang triple for the current Job.
mutable llvm::Triple EffectiveTriple;
const SanitizerArgs& getSanitizerArgs() const;
+ const XRayArgs& getXRayArgs() const;
+
// Returns the Arg * that explicitly turned on/off rtti, or nullptr.
const llvm::opt::Arg *getRTTIArg() const { return CachedRTTIArg; }
--- /dev/null
+//===--- XRayArgs.h - Arguments for XRay ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_DRIVER_XRAYARGS_H
+#define LLVM_CLANG_DRIVER_XRAYARGS_H
+
+#include "clang/Driver/Types.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+
+namespace clang {
+namespace driver {
+
+class ToolChain;
+
+class XRayArgs {
+ std::vector<std::string> AlwaysInstrumentFiles;
+ std::vector<std::string> NeverInstrumentFiles;
+ std::vector<std::string> ExtraDeps;
+ bool XRayInstrument = false;
+ int InstructionThreshold = 200;
+
+public:
+ /// Parses the XRay arguments from an argument list.
+ XRayArgs(const ToolChain &TC, const llvm::opt::ArgList &Args);
+ void addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs, types::ID InputType) const;
+};
+
+} // namespace driver
+} // namespace clang
+
+#endif // LLVM_CLANG_DRIVER_XRAYARGS_H
ExternCContext(nullptr), MakeIntegerSeqDecl(nullptr),
TypePackElementDecl(nullptr), SourceMgr(SM), LangOpts(LOpts),
SanitizerBL(new SanitizerBlacklist(LangOpts.SanitizerBlacklistFiles, SM)),
+ XRayFilter(new XRayFunctionFilter(LangOpts.XRayAlwaysInstrumentFiles,
+ LangOpts.XRayNeverInstrumentFiles, SM)),
AddrSpaceMap(nullptr), Target(nullptr), AuxTarget(nullptr),
PrintingPolicy(LOpts), Idents(idents), Selectors(sels),
BuiltinInfo(builtins), DeclarationNames(*this), ExternalSource(nullptr),
VersionTuple.cpp
VirtualFileSystem.cpp
Warnings.cpp
+ XRayLists.cpp
${version_inc}
)
// sanitizer options (this affects __has_feature(address_sanitizer) etc).
Sanitize.clear();
SanitizerBlacklistFiles.clear();
+ XRayAlwaysInstrumentFiles.clear();
+ XRayNeverInstrumentFiles.clear();
CurrentModule.clear();
IsHeaderFile = false;
--- /dev/null
+//===--- XRayFunctionFilter.cpp - XRay automatic-attribution --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// User-provided filters for always/never XRay instrumenting certain functions.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Basic/XRayLists.h"
+
+using namespace clang;
+
+XRayFunctionFilter::XRayFunctionFilter(
+ ArrayRef<std::string> AlwaysInstrumentPaths,
+ ArrayRef<std::string> NeverInstrumentPaths, SourceManager &SM)
+ : AlwaysInstrument(
+ llvm::SpecialCaseList::createOrDie(AlwaysInstrumentPaths)),
+ NeverInstrument(llvm::SpecialCaseList::createOrDie(NeverInstrumentPaths)),
+ SM(SM) {}
+
+XRayFunctionFilter::ImbueAttribute
+XRayFunctionFilter::shouldImbueFunction(StringRef FunctionName) const {
+ // First apply the always instrument list, than if it isn't an "always" see
+ // whether it's treated as a "never" instrument function.
+ if (AlwaysInstrument->inSection("fun", FunctionName))
+ return ImbueAttribute::ALWAYS;
+ if (NeverInstrument->inSection("fun", FunctionName))
+ return ImbueAttribute::NEVER;
+ return ImbueAttribute::NONE;
+}
+
+XRayFunctionFilter::ImbueAttribute
+XRayFunctionFilter::shouldImbueFunctionsInFile(StringRef Filename,
+ StringRef Category) const {
+ if (AlwaysInstrument->inSection("src", Filename, Category))
+ return ImbueAttribute::ALWAYS;
+ if (NeverInstrument->inSection("src", Filename, Category))
+ return ImbueAttribute::NEVER;
+ return ImbueAttribute::NONE;
+}
+
+XRayFunctionFilter::ImbueAttribute
+XRayFunctionFilter::shouldImbueLocation(SourceLocation Loc,
+ StringRef Category) const {
+ if (!Loc.isValid())
+ return ImbueAttribute::NONE;
+ return this->shouldImbueFunctionsInFile(SM.getFilename(SM.getFileLoc(Loc)),
+ Category);
+}
llvm::utostr(LogArgs->getArgumentCount()));
}
} else {
- Fn->addFnAttr(
- "xray-instruction-threshold",
- llvm::itostr(CGM.getCodeGenOpts().XRayInstructionThreshold));
+ if (!CGM.imbueXRayAttrs(Fn, Loc))
+ Fn->addFnAttr(
+ "xray-instruction-threshold",
+ llvm::itostr(CGM.getCodeGenOpts().XRayInstructionThreshold));
}
}
return false;
}
+bool CodeGenModule::imbueXRayAttrs(llvm::Function *Fn, SourceLocation Loc,
+ StringRef Category) const {
+ if (!LangOpts.XRayInstrument)
+ return false;
+ const auto &XRayFilter = getContext().getXRayFilter();
+ using ImbueAttr = XRayFunctionFilter::ImbueAttribute;
+ auto Attr = XRayFunctionFilter::ImbueAttribute::NONE;
+ if (Loc.isValid())
+ Attr = XRayFilter.shouldImbueLocation(Loc, Category);
+ if (Attr == ImbueAttr::NONE)
+ Attr = XRayFilter.shouldImbueFunction(Fn->getName());
+ switch (Attr) {
+ case ImbueAttr::NONE:
+ return false;
+ case ImbueAttr::ALWAYS:
+ Fn->addFnAttr("function-instrument", "xray-always");
+ break;
+ case ImbueAttr::NEVER:
+ Fn->addFnAttr("function-instrument", "xray-never");
+ break;
+ }
+ return true;
+}
+
bool CodeGenModule::MustBeEmitted(const ValueDecl *Global) {
// Never defer when EmitAllDecls is specified.
if (LangOpts.EmitAllDecls)
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/SanitizerBlacklist.h"
+#include "clang/Basic/XRayLists.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
QualType Ty,
StringRef Category = StringRef()) const;
+ /// Imbue XRay attributes to a function, applying the always/never attribute
+ /// lists in the process. Returns true if we did imbue attributes this way,
+ /// false otherwise.
+ bool imbueXRayAttrs(llvm::Function *Fn, SourceLocation Loc,
+ StringRef Category = StringRef()) const;
+
SanitizerMetadata *getSanitizerMetadata() {
return SanitizerMD.get();
}
ToolChains/WebAssembly.cpp
ToolChains/XCore.cpp
Types.cpp
+ XRayArgs.cpp
DEPENDS
ClangDriverOptions
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/SanitizerArgs.h"
+#include "clang/Driver/XRayArgs.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
return *SanitizerArguments.get();
}
+const XRayArgs& ToolChain::getXRayArgs() const {
+ if (!XRayArguments.get())
+ XRayArguments.reset(new XRayArgs(*this, Args));
+ return *XRayArguments.get();
+}
+
namespace {
struct DriverSuffix {
const char *Suffix;
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/SanitizerArgs.h"
+#include "clang/Driver/XRayArgs.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/CodeGen.h"
Args.AddAllArgs(CmdArgs, options::OPT_finstrument_functions);
- if (Args.hasFlag(options::OPT_fxray_instrument,
- options::OPT_fnoxray_instrument, false)) {
- const char *const XRayInstrumentOption = "-fxray-instrument";
- if (Triple.getOS() == llvm::Triple::Linux)
- switch (Triple.getArch()) {
- case llvm::Triple::x86_64:
- case llvm::Triple::arm:
- case llvm::Triple::aarch64:
- case llvm::Triple::ppc64le:
- case llvm::Triple::mips:
- case llvm::Triple::mipsel:
- case llvm::Triple::mips64:
- case llvm::Triple::mips64el:
- // Supported.
- break;
- default:
- D.Diag(diag::err_drv_clang_unsupported)
- << (std::string(XRayInstrumentOption) + " on " + Triple.str());
- }
- else
- D.Diag(diag::err_drv_clang_unsupported)
- << (std::string(XRayInstrumentOption) + " on non-Linux target OS");
- CmdArgs.push_back(XRayInstrumentOption);
- if (const Arg *A =
- Args.getLastArg(options::OPT_fxray_instruction_threshold_,
- options::OPT_fxray_instruction_threshold_EQ)) {
- CmdArgs.push_back("-fxray-instruction-threshold");
- CmdArgs.push_back(A->getValue());
- }
- }
-
addPGOAndCoverageFlags(C, D, Output, Args, CmdArgs);
// Add runtime flag for PS4 when PGO or Coverage are enabled.
const SanitizerArgs &Sanitize = getToolChain().getSanitizerArgs();
Sanitize.addArgs(getToolChain(), Args, CmdArgs, InputType);
+ const XRayArgs &XRay = getToolChain().getXRayArgs();
+ XRay.addArgs(getToolChain(), Args, CmdArgs, InputType);
+
if (getToolChain().SupportsProfiling())
Args.AddLastArg(CmdArgs, options::OPT_pg);
--- /dev/null
+//===--- XRayArgs.cpp - Arguments for XRay --------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Driver/XRayArgs.h"
+#include "ToolChains/CommonArgs.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
+#include "clang/Driver/ToolChain.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/SpecialCaseList.h"
+
+using namespace clang;
+using namespace clang::driver;
+using namespace llvm::opt;
+
+namespace {
+constexpr char XRayInstrumentOption[] = "-fxray-instrument";
+constexpr char XRayInstructionThresholdOption[] =
+ "-fxray-instruction-threshold=";
+constexpr char XRayAlwaysInstrumentOption[] = "-fxray-always-instrument=";
+constexpr char XRayNeverInstrumentOption[] = "-fxray-never-instrument=";
+} // namespace
+
+XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) {
+ const Driver &D = TC.getDriver();
+ const llvm::Triple &Triple = TC.getTriple();
+ if (Args.hasFlag(options::OPT_fxray_instrument,
+ options::OPT_fnoxray_instrument, false)) {
+ if (Triple.getOS() == llvm::Triple::Linux)
+ switch (Triple.getArch()) {
+ case llvm::Triple::x86_64:
+ case llvm::Triple::arm:
+ case llvm::Triple::aarch64:
+ case llvm::Triple::ppc64le:
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ break;
+ default:
+ D.Diag(diag::err_drv_clang_unsupported)
+ << (std::string(XRayInstrumentOption) + " on " + Triple.str());
+ }
+ else
+ D.Diag(diag::err_drv_clang_unsupported)
+ << (std::string(XRayInstrumentOption) + " on non-Linux target OS");
+ XRayInstrument = true;
+ if (const Arg *A =
+ Args.getLastArg(options::OPT_fxray_instruction_threshold_,
+ options::OPT_fxray_instruction_threshold_EQ)) {
+ StringRef S = A->getValue();
+ if (S.getAsInteger(0, InstructionThreshold) || InstructionThreshold < 0)
+ D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
+ }
+
+ // Validate the always/never attribute files. We also make sure that they
+ // are treated as actual dependencies.
+ for (const auto &Filename :
+ Args.getAllArgValues(options::OPT_fxray_always_instrument)) {
+ if (llvm::sys::fs::exists(Filename)) {
+ AlwaysInstrumentFiles.push_back(Filename);
+ ExtraDeps.push_back(Filename);
+ } else
+ D.Diag(clang::diag::err_drv_no_such_file) << Filename;
+ }
+
+ for (const auto &Filename :
+ Args.getAllArgValues(options::OPT_fxray_never_instrument)) {
+ if (llvm::sys::fs::exists(Filename)) {
+ NeverInstrumentFiles.push_back(Filename);
+ ExtraDeps.push_back(Filename);
+ } else
+ D.Diag(clang::diag::err_drv_no_such_file) << Filename;
+ }
+ }
+}
+
+void XRayArgs::addArgs(const ToolChain &TC, const ArgList &Args,
+ ArgStringList &CmdArgs, types::ID InputType) const {
+ if (!XRayInstrument)
+ return;
+
+ CmdArgs.push_back(XRayInstrumentOption);
+ CmdArgs.push_back(Args.MakeArgString(XRayInstructionThresholdOption +
+ std::to_string(InstructionThreshold)));
+
+ for (const auto &Always : AlwaysInstrumentFiles) {
+ SmallString<64> AlwaysInstrumentOpt(XRayAlwaysInstrumentOption);
+ AlwaysInstrumentOpt += Always;
+ CmdArgs.push_back(Args.MakeArgString(AlwaysInstrumentOpt));
+ }
+
+ for (const auto &Never : NeverInstrumentFiles) {
+ SmallString<64> NeverInstrumentOpt(XRayNeverInstrumentOption);
+ NeverInstrumentOpt += Never;
+ CmdArgs.push_back(Args.MakeArgString(NeverInstrumentOpt));
+ }
+
+ for (const auto &Dep : ExtraDeps) {
+ SmallString<64> ExtraDepOpt("-fdepfile-entry=");
+ ExtraDepOpt += Dep;
+ CmdArgs.push_back(Args.MakeArgString(ExtraDepOpt));
+ }
+}
Opts.SanitizeAddressFieldPadding =
getLastArgIntValue(Args, OPT_fsanitize_address_field_padding, 0, Diags);
Opts.SanitizerBlacklistFiles = Args.getAllArgValues(OPT_fsanitize_blacklist);
+
+ // -fxray-{always,never}-instrument= filenames.
+ Opts.XRayInstrument =
+ Args.hasFlag(OPT_fxray_instrument, OPT_fnoxray_instrument, false);
+ Opts.XRayAlwaysInstrumentFiles =
+ Args.getAllArgValues(OPT_fxray_always_instrument);
+ Opts.XRayNeverInstrumentFiles =
+ Args.getAllArgValues(OPT_fxray_never_instrument);
}
static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
--- /dev/null
+// RUN: echo "fun:*foo*" > %t.always-instrument
+// RUN: echo "src:*xray-always-instrument.cpp" >> %t.always-instrument
+// RUN: %clang_cc1 -fxray-instrument -x c++ -std=c++11 -fxray-always-instrument=%t.always-instrument -emit-llvm -o - %s -triple x86_64-unknown-linux-gnu | FileCheck %s
+
+void foo() {}
+
+[[clang::xray_never_instrument]] void bar() {}
+
+void baz() {}
+
+// CHECK: define void @_Z3foov() #[[ALWAYSATTR:[0-9]+]] {
+// CHECK: define void @_Z3barv() #[[NEVERATTR:[0-9]+]] {
+// CHECK: define void @_Z3bazv() #[[ALWAYSATTR:[0-9]+]] {
+// CHECK: attributes #[[ALWAYSATTR]] = {{.*}} "function-instrument"="xray-always" {{.*}}
+// CHECK: attributes #[[NEVERATTR]] = {{.*}} "function-instrument"="xray-never" {{.*}}