mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-02 18:58:15 +00:00
Introduce -fsanitize-stats flag.
This is part of a new statistics gathering feature for the sanitizers. See clang/docs/SanitizerStats.rst for further info and docs. Differential Revision: http://reviews.llvm.org/D16175 llvm-svn: 257971
This commit is contained in:
parent
f0f5e87083
commit
dc13453128
62
clang/docs/SanitizerStats.rst
Normal file
62
clang/docs/SanitizerStats.rst
Normal file
@ -0,0 +1,62 @@
|
||||
==============
|
||||
SanitizerStats
|
||||
==============
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
The sanitizers support a simple mechanism for gathering profiling statistics
|
||||
to help understand the overhead associated with sanitizers.
|
||||
|
||||
How to build and run
|
||||
====================
|
||||
|
||||
SanitizerStats can currently only be used with :doc:`ControlFlowIntegrity`.
|
||||
In addition to ``-fsanitize=cfi*``, pass the ``-fsanitize-stats`` flag.
|
||||
This will cause the program to count the number of times that each control
|
||||
flow integrity check in the program fires.
|
||||
|
||||
At run time, set the ``SANITIZER_STATS_PATH`` environment variable to direct
|
||||
statistics output to a file. The file will be written on process exit.
|
||||
The following substitutions will be applied to the environment variable:
|
||||
|
||||
- ``%b`` -- The executable basename.
|
||||
- ``%p`` -- The process ID.
|
||||
|
||||
You can also send the ``SIGUSR2`` signal to a process to make it write
|
||||
sanitizer statistics immediately.
|
||||
|
||||
The ``sanstats`` program can be used to dump statistics. It takes as a
|
||||
command line argument the path to a statistics file produced by a program
|
||||
compiled with ``-fsanitize-stats``.
|
||||
|
||||
The output of ``sanstats`` is in four columns, separated by spaces. The first
|
||||
column is the file and line number of the call site. The second column is
|
||||
the function name. The third column is the type of statistic gathered (in
|
||||
this case, the type of control flow integrity check). The fourth column is
|
||||
the call count.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ cat -n vcall.cc
|
||||
1 struct A {
|
||||
2 virtual void f() {}
|
||||
3 };
|
||||
4
|
||||
5 __attribute__((noinline)) void g(A *a) {
|
||||
6 a->f();
|
||||
7 }
|
||||
8
|
||||
9 int main() {
|
||||
10 A a;
|
||||
11 g(&a);
|
||||
12 }
|
||||
$ clang++ -fsanitize=cfi -flto -fuse-ld=gold vcall.cc -fsanitize-stats -g
|
||||
$ SANITIZER_STATS_PATH=a.stats ./a.out
|
||||
$ sanstats a.stats
|
||||
vcall.cc:6 _Z1gP1A cfi-vcall 1
|
@ -1038,6 +1038,11 @@ are listed below.
|
||||
Enable simple code coverage in addition to certain sanitizers.
|
||||
See :doc:`SanitizerCoverage` for more details.
|
||||
|
||||
**-f[no-]sanitize-stats**
|
||||
|
||||
Enable simple statistics gathering for the enabled sanitizers.
|
||||
See :doc:`SanitizerStats` for more details.
|
||||
|
||||
.. option:: -fsanitize-undefined-trap-on-error
|
||||
|
||||
Deprecated alias for ``-fsanitize-trap=undefined``.
|
||||
|
@ -28,6 +28,7 @@ Using Clang as a Compiler
|
||||
DataFlowSanitizer
|
||||
LeakSanitizer
|
||||
SanitizerCoverage
|
||||
SanitizerStats
|
||||
SanitizerSpecialCaseList
|
||||
ControlFlowIntegrity
|
||||
SafeStack
|
||||
|
@ -94,9 +94,10 @@ public:
|
||||
/// The default implementation passes it to HandleTopLevelDecl.
|
||||
virtual void HandleImplicitImportDecl(ImportDecl *D);
|
||||
|
||||
/// \brief Handle a pragma that appends to Linker Options. Currently this
|
||||
/// only exists to support Microsoft's #pragma comment(linker, "/foo").
|
||||
virtual void HandleLinkerOptionPragma(llvm::StringRef Opts) {}
|
||||
/// \brief Handle a pragma or command line flag that appends to Linker
|
||||
/// Options. This exists to support Microsoft's
|
||||
/// #pragma comment(linker, "/foo") and the frontend flag --linker-option=.
|
||||
virtual void HandleLinkerOption(llvm::StringRef Opts) {}
|
||||
|
||||
/// \brief Handle a pragma that emits a mismatch identifier and value to the
|
||||
/// object file for the linker to work with. Currently, this only exists to
|
||||
|
@ -252,6 +252,8 @@ def vectorize_slp_aggressive : Flag<["-"], "vectorize-slp-aggressive">,
|
||||
HelpText<"Run the BB vectorization passes">;
|
||||
def dependent_lib : Joined<["--"], "dependent-lib=">,
|
||||
HelpText<"Add dependent library">;
|
||||
def linker_option : Joined<["--"], "linker-option=">,
|
||||
HelpText<"Add linker option">;
|
||||
def fsanitize_coverage_type : Joined<["-"], "fsanitize-coverage-type=">,
|
||||
HelpText<"Sanitizer coverage type">;
|
||||
def fsanitize_coverage_indirect_calls
|
||||
|
@ -644,6 +644,12 @@ def fsanitize_cfi_cross_dso : Flag<["-"], "fsanitize-cfi-cross-dso">,
|
||||
def fno_sanitize_cfi_cross_dso : Flag<["-"], "fno-sanitize-cfi-cross-dso">,
|
||||
Group<f_clang_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"Disable control flow integrity (CFI) checks for cross-DSO calls.">;
|
||||
def fsanitize_stats : Flag<["-"], "fsanitize-stats">,
|
||||
Group<f_clang_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"Enable sanitizer statistics gathering.">;
|
||||
def fno_sanitize_stats : Flag<["-"], "fno-sanitize-stats">,
|
||||
Group<f_clang_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"Disable sanitizer statistics gathering.">;
|
||||
def funsafe_math_optimizations : Flag<["-"], "funsafe-math-optimizations">,
|
||||
Group<f_Group>;
|
||||
def fno_unsafe_math_optimizations : Flag<["-"], "fno-unsafe-math-optimizations">,
|
||||
|
@ -36,6 +36,7 @@ class SanitizerArgs {
|
||||
bool AsanSharedRuntime = false;
|
||||
bool LinkCXXRuntimes = false;
|
||||
bool NeedPIE = false;
|
||||
bool Stats = false;
|
||||
|
||||
public:
|
||||
/// Parses the sanitizer arguments from an argument list.
|
||||
@ -56,6 +57,7 @@ class SanitizerArgs {
|
||||
}
|
||||
bool needsCfiRt() const;
|
||||
bool needsCfiDiagRt() const;
|
||||
bool needsStatsRt() const { return Stats; }
|
||||
|
||||
bool requiresPIE() const;
|
||||
bool needsUnwindTables() const;
|
||||
|
@ -134,6 +134,7 @@ CODEGENOPT(SanitizeCoverageTraceCmp, 1, 0) ///< Enable cmp instruction tracing
|
||||
///< in sanitizer coverage.
|
||||
CODEGENOPT(SanitizeCoverage8bitCounters, 1, 0) ///< Use 8-bit frequency counters
|
||||
///< in sanitizer coverage.
|
||||
CODEGENOPT(SanitizeStats , 1, 0) ///< Collect statistics for sanitizers.
|
||||
CODEGENOPT(SimplifyLibCalls , 1, 1) ///< Set when -fbuiltin is enabled.
|
||||
CODEGENOPT(SoftFloat , 1, 0) ///< -soft-float.
|
||||
CODEGENOPT(StrictEnums , 1, 0) ///< Optimize based on strict enum definition.
|
||||
|
@ -164,6 +164,9 @@ public:
|
||||
/// A list of dependent libraries.
|
||||
std::vector<std::string> DependentLibraries;
|
||||
|
||||
/// A list of linker options to embed in the object file.
|
||||
std::vector<std::string> LinkerOptions;
|
||||
|
||||
/// Name of the profile file to use as output for -fprofile-instr-generate
|
||||
/// and -fprofile-generate.
|
||||
std::string InstrProfileOutput;
|
||||
|
@ -44,7 +44,7 @@ public:
|
||||
void HandleCXXImplicitFunctionInstantiation(FunctionDecl *D) override;
|
||||
void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) override;
|
||||
void HandleImplicitImportDecl(ImportDecl *D) override;
|
||||
void HandleLinkerOptionPragma(llvm::StringRef Opts) override;
|
||||
void HandleLinkerOption(llvm::StringRef Opts) override;
|
||||
void HandleDetectMismatch(llvm::StringRef Name,
|
||||
llvm::StringRef Value) override;
|
||||
void HandleDependentLibrary(llvm::StringRef Lib) override;
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "clang/Frontend/CodeGenOptions.h"
|
||||
#include "llvm/IR/Intrinsics.h"
|
||||
#include "llvm/IR/Metadata.h"
|
||||
#include "llvm/Transforms/Utils/SanitizerStats.h"
|
||||
|
||||
using namespace clang;
|
||||
using namespace CodeGen;
|
||||
@ -2551,6 +2552,22 @@ void CodeGenFunction::EmitVTablePtrCheck(const CXXRecordDecl *RD,
|
||||
return;
|
||||
|
||||
SanitizerScope SanScope(this);
|
||||
llvm::SanitizerStatKind SSK;
|
||||
switch (TCK) {
|
||||
case CFITCK_VCall:
|
||||
SSK = llvm::SanStat_CFI_VCall;
|
||||
break;
|
||||
case CFITCK_NVCall:
|
||||
SSK = llvm::SanStat_CFI_NVCall;
|
||||
break;
|
||||
case CFITCK_DerivedCast:
|
||||
SSK = llvm::SanStat_CFI_DerivedCast;
|
||||
break;
|
||||
case CFITCK_UnrelatedCast:
|
||||
SSK = llvm::SanStat_CFI_UnrelatedCast;
|
||||
break;
|
||||
}
|
||||
EmitSanitizerStatReport(SSK);
|
||||
|
||||
llvm::Metadata *MD =
|
||||
CGM.CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0));
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "llvm/IR/MDBuilder.h"
|
||||
#include "llvm/Support/ConvertUTF.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include "llvm/Transforms/Utils/SanitizerStats.h"
|
||||
|
||||
using namespace clang;
|
||||
using namespace CodeGen;
|
||||
@ -3852,6 +3853,7 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee,
|
||||
if (SanOpts.has(SanitizerKind::CFIICall) &&
|
||||
(!TargetDecl || !isa<FunctionDecl>(TargetDecl))) {
|
||||
SanitizerScope SanScope(this);
|
||||
EmitSanitizerStatReport(llvm::SanStat_CFI_ICall);
|
||||
|
||||
llvm::Metadata *MD = CGM.CreateMetadataIdentifierForType(QualType(FnType, 0));
|
||||
llvm::Value *BitSetName = llvm::MetadataAsValue::get(getLLVMContext(), MD);
|
||||
|
@ -214,8 +214,8 @@ namespace clang {
|
||||
Gen->HandleVTable(RD);
|
||||
}
|
||||
|
||||
void HandleLinkerOptionPragma(llvm::StringRef Opts) override {
|
||||
Gen->HandleLinkerOptionPragma(Opts);
|
||||
void HandleLinkerOption(llvm::StringRef Opts) override {
|
||||
Gen->HandleLinkerOption(Opts);
|
||||
}
|
||||
|
||||
void HandleDetectMismatch(llvm::StringRef Name,
|
||||
|
@ -1956,3 +1956,12 @@ void CodeGenFunction::checkTargetFeatures(const CallExpr *E,
|
||||
<< FD->getDeclName() << TargetDecl->getDeclName() << MissingFeature;
|
||||
}
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitSanitizerStatReport(llvm::SanitizerStatKind SSK) {
|
||||
if (!CGM.getCodeGenOpts().SanitizeStats)
|
||||
return;
|
||||
|
||||
llvm::IRBuilder<> IRB(Builder.GetInsertBlock(), Builder.GetInsertPoint());
|
||||
IRB.SetCurrentDebugLocation(Builder.getCurrentDebugLocation());
|
||||
CGM.getSanStats().create(IRB, SSK);
|
||||
}
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/IR/ValueHandle.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Transforms/Utils/SanitizerStats.h"
|
||||
|
||||
namespace llvm {
|
||||
class BasicBlock;
|
||||
@ -3187,6 +3188,8 @@ public:
|
||||
Address EmitPointerWithAlignment(const Expr *Addr,
|
||||
AlignmentSource *Source = nullptr);
|
||||
|
||||
void EmitSanitizerStatReport(llvm::SanitizerStatKind SSK);
|
||||
|
||||
private:
|
||||
QualType getVarArgType(const Expr *Arg);
|
||||
|
||||
|
@ -392,6 +392,8 @@ void CodeGenModule::Release() {
|
||||
if (CoverageMapping)
|
||||
CoverageMapping->emit();
|
||||
emitLLVMUsed();
|
||||
if (SanStats)
|
||||
SanStats->finish();
|
||||
|
||||
if (CodeGenOpts.Autolink &&
|
||||
(Context.getLangOpts().Modules || !LinkerOptionsMetadata.empty())) {
|
||||
@ -4066,3 +4068,10 @@ void CodeGenModule::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
|
||||
Target.getTargetOpts().Features);
|
||||
}
|
||||
}
|
||||
|
||||
llvm::SanitizerStatReport &CodeGenModule::getSanStats() {
|
||||
if (!SanStats)
|
||||
SanStats = llvm::make_unique<llvm::SanitizerStatReport>(&getModule());
|
||||
|
||||
return *SanStats;
|
||||
}
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/ValueHandle.h"
|
||||
#include "llvm/Transforms/Utils/SanitizerStats.h"
|
||||
|
||||
namespace llvm {
|
||||
class Module;
|
||||
@ -289,6 +290,7 @@ private:
|
||||
llvm::MDNode *NoObjCARCExceptionsMetadata;
|
||||
std::unique_ptr<llvm::IndexedInstrProfReader> PGOReader;
|
||||
InstrProfStats PGOStats;
|
||||
std::unique_ptr<llvm::SanitizerStatReport> SanStats;
|
||||
|
||||
// A set of references that have only been seen via a weakref so far. This is
|
||||
// used to remove the weak of the reference if we ever see a direct reference
|
||||
@ -1129,6 +1131,8 @@ public:
|
||||
/// \breif Get the declaration of std::terminate for the platform.
|
||||
llvm::Constant *getTerminateFn();
|
||||
|
||||
llvm::SanitizerStatReport &getSanStats();
|
||||
|
||||
private:
|
||||
llvm::Constant *
|
||||
GetOrCreateLLVMFunction(StringRef MangledName, llvm::Type *Ty, GlobalDecl D,
|
||||
|
@ -103,8 +103,10 @@ namespace {
|
||||
PreprocessorOpts, CodeGenOpts,
|
||||
*M, Diags, CoverageInfo));
|
||||
|
||||
for (size_t i = 0, e = CodeGenOpts.DependentLibraries.size(); i < e; ++i)
|
||||
HandleDependentLibrary(CodeGenOpts.DependentLibraries[i]);
|
||||
for (auto &&Lib : CodeGenOpts.DependentLibraries)
|
||||
HandleDependentLibrary(Lib);
|
||||
for (auto &&Opt : CodeGenOpts.LinkerOptions)
|
||||
HandleLinkerOption(Opt);
|
||||
}
|
||||
|
||||
void HandleCXXStaticMemberVarInstantiation(VarDecl *VD) override {
|
||||
@ -222,7 +224,7 @@ namespace {
|
||||
Builder->EmitVTable(RD);
|
||||
}
|
||||
|
||||
void HandleLinkerOptionPragma(llvm::StringRef Opts) override {
|
||||
void HandleLinkerOption(llvm::StringRef Opts) override {
|
||||
Builder->AppendLinkerOptions(Opts);
|
||||
}
|
||||
|
||||
|
@ -431,6 +431,9 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
|
||||
NeedPIE |= CfiCrossDso;
|
||||
}
|
||||
|
||||
Stats = Args.hasFlag(options::OPT_fsanitize_stats,
|
||||
options::OPT_fno_sanitize_stats, false);
|
||||
|
||||
// Parse -f(no-)?sanitize-coverage flags if coverage is supported by the
|
||||
// enabled sanitizers.
|
||||
if (AllAddedKinds & SupportsCoverage) {
|
||||
@ -548,6 +551,20 @@ static std::string toString(const clang::SanitizerSet &Sanitizers) {
|
||||
return Res;
|
||||
}
|
||||
|
||||
static void addIncludeLinkerOption(const ToolChain &TC,
|
||||
const llvm::opt::ArgList &Args,
|
||||
llvm::opt::ArgStringList &CmdArgs,
|
||||
StringRef SymbolName) {
|
||||
SmallString<64> LinkerOptionFlag;
|
||||
LinkerOptionFlag = "--linker-option=/include:";
|
||||
if (TC.getTriple().getArch() == llvm::Triple::x86) {
|
||||
// Win32 mangles C function names with a '_' prefix.
|
||||
LinkerOptionFlag += '_';
|
||||
}
|
||||
LinkerOptionFlag += SymbolName;
|
||||
CmdArgs.push_back(Args.MakeArgString(LinkerOptionFlag));
|
||||
}
|
||||
|
||||
void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
|
||||
llvm::opt::ArgStringList &CmdArgs,
|
||||
types::ID InputType) const {
|
||||
@ -584,6 +601,9 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
|
||||
if (CfiCrossDso)
|
||||
CmdArgs.push_back(Args.MakeArgString("-fsanitize-cfi-cross-dso"));
|
||||
|
||||
if (Stats)
|
||||
CmdArgs.push_back(Args.MakeArgString("-fsanitize-stats"));
|
||||
|
||||
if (AsanFieldPadding)
|
||||
CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-field-padding=" +
|
||||
llvm::utostr(AsanFieldPadding)));
|
||||
@ -619,6 +639,18 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
|
||||
CmdArgs.push_back(Args.MakeArgString(
|
||||
"--dependent-lib=" + TC.getCompilerRT(Args, "ubsan_standalone_cxx")));
|
||||
}
|
||||
if (TC.getTriple().isOSWindows() && needsStatsRt()) {
|
||||
CmdArgs.push_back(Args.MakeArgString("--dependent-lib=" +
|
||||
TC.getCompilerRT(Args, "stats_client")));
|
||||
|
||||
// The main executable must export the stats runtime.
|
||||
// FIXME: Only exporting from the main executable (e.g. based on whether the
|
||||
// translation unit defines main()) would save a little space, but having
|
||||
// multiple copies of the runtime shouldn't hurt.
|
||||
CmdArgs.push_back(Args.MakeArgString("--dependent-lib=" +
|
||||
TC.getCompilerRT(Args, "stats")));
|
||||
addIncludeLinkerOption(TC, Args, CmdArgs, "__sanitizer_stats_register");
|
||||
}
|
||||
}
|
||||
|
||||
SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
|
||||
|
@ -413,6 +413,13 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
|
||||
AddLinkSanitizerLibArgs(Args, CmdArgs, "ubsan");
|
||||
if (Sanitize.needsTsanRt())
|
||||
AddLinkSanitizerLibArgs(Args, CmdArgs, "tsan");
|
||||
if (Sanitize.needsStatsRt()) {
|
||||
StringRef OS = isTargetMacOS() ? "osx" : "iossim";
|
||||
AddLinkRuntimeLib(Args, CmdArgs,
|
||||
(Twine("libclang_rt.stats_client_") + OS + ".a").str(),
|
||||
/*AlwaysLink=*/true);
|
||||
AddLinkSanitizerLibArgs(Args, CmdArgs, "stats");
|
||||
}
|
||||
|
||||
// Otherwise link libSystem, then the dynamic runtime library, and finally any
|
||||
// target specific static runtime library.
|
||||
|
@ -2773,12 +2773,12 @@ static void addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC,
|
||||
|
||||
static void addSanitizerRuntime(const ToolChain &TC, const ArgList &Args,
|
||||
ArgStringList &CmdArgs, StringRef Sanitizer,
|
||||
bool IsShared) {
|
||||
// Static runtimes must be forced into executable, so we wrap them in
|
||||
bool IsShared, bool IsWhole) {
|
||||
// Wrap any static runtimes that must be forced into executable in
|
||||
// whole-archive.
|
||||
if (!IsShared) CmdArgs.push_back("-whole-archive");
|
||||
if (IsWhole) CmdArgs.push_back("-whole-archive");
|
||||
CmdArgs.push_back(TC.getCompilerRTArgString(Args, Sanitizer, IsShared));
|
||||
if (!IsShared) CmdArgs.push_back("-no-whole-archive");
|
||||
if (IsWhole) CmdArgs.push_back("-no-whole-archive");
|
||||
}
|
||||
|
||||
// Tries to use a file with the list of dynamic symbols that need to be exported
|
||||
@ -2811,12 +2811,17 @@ static void
|
||||
collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
|
||||
SmallVectorImpl<StringRef> &SharedRuntimes,
|
||||
SmallVectorImpl<StringRef> &StaticRuntimes,
|
||||
SmallVectorImpl<StringRef> &HelperStaticRuntimes) {
|
||||
SmallVectorImpl<StringRef> &NonWholeStaticRuntimes,
|
||||
SmallVectorImpl<StringRef> &HelperStaticRuntimes,
|
||||
SmallVectorImpl<StringRef> &RequiredSymbols) {
|
||||
const SanitizerArgs &SanArgs = TC.getSanitizerArgs();
|
||||
// Collect shared runtimes.
|
||||
if (SanArgs.needsAsanRt() && SanArgs.needsSharedAsanRt()) {
|
||||
SharedRuntimes.push_back("asan");
|
||||
}
|
||||
// The stats_client library is also statically linked into DSOs.
|
||||
if (SanArgs.needsStatsRt())
|
||||
StaticRuntimes.push_back("stats_client");
|
||||
|
||||
// Collect static runtimes.
|
||||
if (Args.hasArg(options::OPT_shared) || TC.getTriple().isAndroid()) {
|
||||
@ -2857,6 +2862,10 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
|
||||
StaticRuntimes.push_back("cfi");
|
||||
if (SanArgs.needsCfiDiagRt())
|
||||
StaticRuntimes.push_back("cfi_diag");
|
||||
if (SanArgs.needsStatsRt()) {
|
||||
NonWholeStaticRuntimes.push_back("stats");
|
||||
RequiredSymbols.push_back("__sanitizer_stats_register");
|
||||
}
|
||||
}
|
||||
|
||||
// Should be called before we add system libraries (C++ ABI, libstdc++/libc++,
|
||||
@ -2864,18 +2873,27 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
|
||||
static bool addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
|
||||
ArgStringList &CmdArgs) {
|
||||
SmallVector<StringRef, 4> SharedRuntimes, StaticRuntimes,
|
||||
HelperStaticRuntimes;
|
||||
NonWholeStaticRuntimes, HelperStaticRuntimes, RequiredSymbols;
|
||||
collectSanitizerRuntimes(TC, Args, SharedRuntimes, StaticRuntimes,
|
||||
HelperStaticRuntimes);
|
||||
NonWholeStaticRuntimes, HelperStaticRuntimes,
|
||||
RequiredSymbols);
|
||||
for (auto RT : SharedRuntimes)
|
||||
addSanitizerRuntime(TC, Args, CmdArgs, RT, true);
|
||||
addSanitizerRuntime(TC, Args, CmdArgs, RT, true, false);
|
||||
for (auto RT : HelperStaticRuntimes)
|
||||
addSanitizerRuntime(TC, Args, CmdArgs, RT, false);
|
||||
addSanitizerRuntime(TC, Args, CmdArgs, RT, false, true);
|
||||
bool AddExportDynamic = false;
|
||||
for (auto RT : StaticRuntimes) {
|
||||
addSanitizerRuntime(TC, Args, CmdArgs, RT, false);
|
||||
addSanitizerRuntime(TC, Args, CmdArgs, RT, false, true);
|
||||
AddExportDynamic |= !addSanitizerDynamicList(TC, Args, CmdArgs, RT);
|
||||
}
|
||||
for (auto RT : NonWholeStaticRuntimes) {
|
||||
addSanitizerRuntime(TC, Args, CmdArgs, RT, false, false);
|
||||
AddExportDynamic |= !addSanitizerDynamicList(TC, Args, CmdArgs, RT);
|
||||
}
|
||||
for (auto S : RequiredSymbols) {
|
||||
CmdArgs.push_back("-u");
|
||||
CmdArgs.push_back(Args.MakeArgString(S));
|
||||
}
|
||||
// If there is a static runtime with no dynamic list, force all the symbols
|
||||
// to be dynamic to be sure we export sanitizer interface functions.
|
||||
if (AddExportDynamic)
|
||||
|
@ -623,6 +623,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
|
||||
Opts.SanitizeMemoryUseAfterDtor =
|
||||
Args.hasArg(OPT_fsanitize_memory_use_after_dtor);
|
||||
Opts.SanitizeCfiCrossDso = Args.hasArg(OPT_fsanitize_cfi_cross_dso);
|
||||
Opts.SanitizeStats = Args.hasArg(OPT_fsanitize_stats);
|
||||
Opts.SSPBufferSize =
|
||||
getLastArgIntValue(Args, OPT_stack_protector_buffer_size, 8, Diags);
|
||||
Opts.StackRealignment = Args.hasArg(OPT_mstackrealign);
|
||||
@ -697,6 +698,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
|
||||
}
|
||||
|
||||
Opts.DependentLibraries = Args.getAllArgValues(OPT_dependent_lib);
|
||||
Opts.LinkerOptions = Args.getAllArgValues(OPT_linker_option);
|
||||
bool NeedLocTracking = false;
|
||||
|
||||
if (Arg *A = Args.getLastArg(OPT_Rpass_EQ)) {
|
||||
|
@ -317,9 +317,9 @@ void MultiplexConsumer::HandleImplicitImportDecl(ImportDecl *D) {
|
||||
Consumer->HandleImplicitImportDecl(D);
|
||||
}
|
||||
|
||||
void MultiplexConsumer::HandleLinkerOptionPragma(llvm::StringRef Opts) {
|
||||
void MultiplexConsumer::HandleLinkerOption(llvm::StringRef Opts) {
|
||||
for (auto &Consumer : Consumers)
|
||||
Consumer->HandleLinkerOptionPragma(Opts);
|
||||
Consumer->HandleLinkerOption(Opts);
|
||||
}
|
||||
|
||||
void MultiplexConsumer::HandleDetectMismatch(llvm::StringRef Name, llvm::StringRef Value) {
|
||||
|
@ -275,7 +275,7 @@ void Sema::ActOnPragmaMSComment(PragmaMSCommentKind Kind, StringRef Arg) {
|
||||
case PCK_Unknown:
|
||||
llvm_unreachable("unexpected pragma comment kind");
|
||||
case PCK_Linker:
|
||||
Consumer.HandleLinkerOptionPragma(Arg);
|
||||
Consumer.HandleLinkerOption(Arg);
|
||||
return;
|
||||
case PCK_Lib:
|
||||
Consumer.HandleDependentLibrary(Arg);
|
||||
|
8
clang/test/CodeGen/linker-option.c
Normal file
8
clang/test/CodeGen/linker-option.c
Normal file
@ -0,0 +1,8 @@
|
||||
// RUN: %clang_cc1 %s --linker-option=/include:foo -triple i686-pc-win32 -emit-llvm -o - | FileCheck %s
|
||||
|
||||
// CHECK: !llvm.module.flags = !{{{.*}}}
|
||||
// CHECK: !{{[0-9]+}} = !{i32 6, !"Linker Options", ![[link_opts:[0-9]+]]}
|
||||
// CHECK: ![[link_opts]] = !{![[msvcrt:[0-9]+]]}
|
||||
// CHECK: ![[msvcrt]] = !{!"/include:foo"}
|
||||
|
||||
int f();
|
50
clang/test/CodeGenCXX/cfi-stats.cpp
Normal file
50
clang/test/CodeGenCXX/cfi-stats.cpp
Normal file
@ -0,0 +1,50 @@
|
||||
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-vcall,cfi-nvcall,cfi-derived-cast,cfi-unrelated-cast,cfi-icall -fsanitize-stats -emit-llvm -o - %s | FileCheck --check-prefix=CHECK %s
|
||||
|
||||
// CHECK: [[STATS:@[^ ]*]] = internal global { i8*, i32, [5 x [2 x i8*]] } { i8* null, i32 5, [5 x [2 x i8*]]
|
||||
// CHECK: {{\[\[}}2 x i8*] zeroinitializer,
|
||||
// CHECK: [2 x i8*] [i8* null, i8* inttoptr (i64 2305843009213693952 to i8*)],
|
||||
// CHECK: [2 x i8*] [i8* null, i8* inttoptr (i64 4611686018427387904 to i8*)],
|
||||
// CHECK: [2 x i8*] [i8* null, i8* inttoptr (i64 6917529027641081856 to i8*)],
|
||||
// CHECK: [2 x i8*] [i8* null, i8* inttoptr (i64 -9223372036854775808 to i8*)]] }
|
||||
|
||||
// CHECK: @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 0, void ()* [[CTOR:@[^ ]*]], i8* null }]
|
||||
|
||||
struct A {
|
||||
virtual void vf();
|
||||
void nvf();
|
||||
};
|
||||
struct B : A {};
|
||||
|
||||
// CHECK: @vcall
|
||||
extern "C" void vcall(A *a) {
|
||||
// CHECK: call void @__sanitizer_stat_report({{.*}}[[STATS]]{{.*}}i64 0, i32 2, i64 0
|
||||
a->vf();
|
||||
}
|
||||
|
||||
// CHECK: @nvcall
|
||||
extern "C" void nvcall(A *a) {
|
||||
// CHECK: call void @__sanitizer_stat_report({{.*}}[[STATS]]{{.*}}i64 0, i32 2, i64 1
|
||||
a->nvf();
|
||||
}
|
||||
|
||||
// CHECK: @dcast
|
||||
extern "C" void dcast(A *a) {
|
||||
// CHECK: call void @__sanitizer_stat_report({{.*}}[[STATS]]{{.*}}i64 0, i32 2, i64 2
|
||||
static_cast<B *>(a);
|
||||
}
|
||||
|
||||
// CHECK: @ucast
|
||||
extern "C" void ucast(void *a) {
|
||||
// CHECK: call void @__sanitizer_stat_report({{.*}}[[STATS]]{{.*}}i64 0, i32 2, i64 3
|
||||
reinterpret_cast<A *>(a);
|
||||
}
|
||||
|
||||
// CHECK: @icall
|
||||
extern "C" void icall(void (*p)()) {
|
||||
// CHECK: call void @__sanitizer_stat_report({{.*}}[[STATS]]{{.*}}i64 0, i32 2, i64 4
|
||||
p();
|
||||
}
|
||||
|
||||
// CHECK: define internal void [[CTOR]]()
|
||||
// CHECK-NEXT: call void @__sanitizer_stat_init(i8* bitcast ({ i8*, i32, [5 x [2 x i8*]] }* [[STATS]] to i8*))
|
||||
// CHECK-NEXT: ret void
|
@ -272,6 +272,9 @@
|
||||
// CHECK-CFI-NO-CROSS-DSO: -emit-llvm-bc
|
||||
// CHECK-CFI-NO-CROSS-DSO-NOT: -fsanitize-cfi-cross-dso
|
||||
|
||||
// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi -fsanitize-stats -flto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-STATS
|
||||
// CHECK-CFI-STATS: -fsanitize-stats
|
||||
|
||||
// RUN: %clang_cl -fsanitize=address -c -MDd -### -- %s 2>&1 | FileCheck %s -check-prefix=CHECK-ASAN-DEBUGRTL
|
||||
// RUN: %clang_cl -fsanitize=address -c -MTd -### -- %s 2>&1 | FileCheck %s -check-prefix=CHECK-ASAN-DEBUGRTL
|
||||
// RUN: %clang_cl -fsanitize=address -c -LDd -### -- %s 2>&1 | FileCheck %s -check-prefix=CHECK-ASAN-DEBUGRTL
|
||||
|
@ -345,6 +345,39 @@
|
||||
// CHECK-SAFESTACK-LINUX: "-lpthread"
|
||||
// CHECK-SAFESTACK-LINUX: "-ldl"
|
||||
|
||||
// RUN: %clang -fsanitize=cfi -fsanitize-stats %s -### -o %t.o 2>&1 \
|
||||
// RUN: -target x86_64-unknown-linux \
|
||||
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
|
||||
// RUN: | FileCheck --check-prefix=CHECK-CFI-STATS-LINUX %s
|
||||
// CHECK-CFI-STATS-LINUX: "{{.*}}ld{{(.exe)?}}"
|
||||
// CHECK-CFI-STATS-LINUX: "-whole-archive" "{{[^"]*}}libclang_rt.stats_client-x86_64.a" "-no-whole-archive"
|
||||
// CHECK-CFI-STATS-LINUX-NOT: "-whole-archive"
|
||||
// CHECK-CFI-STATS-LINUX: "{{[^"]*}}libclang_rt.stats-x86_64.a"
|
||||
|
||||
// RUN: %clang -fsanitize=cfi -fsanitize-stats %s -### -o %t.o 2>&1 \
|
||||
// RUN: -target x86_64-apple-darwin \
|
||||
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
|
||||
// RUN: | FileCheck --check-prefix=CHECK-CFI-STATS-DARWIN %s
|
||||
// CHECK-CFI-STATS-DARWIN: "{{.*}}ld{{(.exe)?}}"
|
||||
// CHECK-CFI-STATS-DARWIN: "{{[^"]*}}libclang_rt.stats_client_osx.a"
|
||||
// CHECK-CFI-STATS-DARWIN: "{{[^"]*}}libclang_rt.stats_osx_dynamic.dylib"
|
||||
|
||||
// RUN: %clang -fsanitize=cfi -fsanitize-stats %s -### -o %t.o 2>&1 \
|
||||
// RUN: -target x86_64-pc-windows \
|
||||
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
|
||||
// RUN: | FileCheck --check-prefix=CHECK-CFI-STATS-WIN64 %s
|
||||
// CHECK-CFI-STATS-WIN64: "--dependent-lib={{[^"]*}}clang_rt.stats_client-x86_64.lib"
|
||||
// CHECK-CFI-STATS-WIN64: "--dependent-lib={{[^"]*}}clang_rt.stats-x86_64.lib"
|
||||
// CHECK-CFI-STATS-WIN64: "--linker-option=/include:__sanitizer_stats_register"
|
||||
|
||||
// RUN: %clang -fsanitize=cfi -fsanitize-stats %s -### -o %t.o 2>&1 \
|
||||
// RUN: -target i686-pc-windows \
|
||||
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
|
||||
// RUN: | FileCheck --check-prefix=CHECK-CFI-STATS-WIN32 %s
|
||||
// CHECK-CFI-STATS-WIN32: "--dependent-lib={{[^"]*}}clang_rt.stats_client-i386.lib"
|
||||
// CHECK-CFI-STATS-WIN32: "--dependent-lib={{[^"]*}}clang_rt.stats-i386.lib"
|
||||
// CHECK-CFI-STATS-WIN32: "--linker-option=/include:___sanitizer_stats_register"
|
||||
|
||||
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
|
||||
// RUN: -target arm-linux-androideabi -fsanitize=safe-stack \
|
||||
// RUN: --sysroot=%S/Inputs/basic_android_tree \
|
||||
|
Loading…
Reference in New Issue
Block a user