diff options
| author | Alexey Samsonov <vonosmas@gmail.com> | 2015-05-07 22:34:06 +0000 |
|---|---|---|
| committer | Alexey Samsonov <vonosmas@gmail.com> | 2015-05-07 22:34:06 +0000 |
| commit | dfa908c8d5afc9d583f2aab3664b14144b4bdb97 (patch) | |
| tree | 402cf39895c05541fc2ec5f4ab7fb66bf9fdc1ab /clang/lib | |
| parent | 9c70ea4790a4368eac5350cfecc5dfce9b3bd314 (diff) | |
| download | bcm5719-llvm-dfa908c8d5afc9d583f2aab3664b14144b4bdb97.tar.gz bcm5719-llvm-dfa908c8d5afc9d583f2aab3664b14144b4bdb97.zip | |
[SanitizerCoverage] Implement user-friendly -fsanitize-coverage= flags.
Summary:
Possible coverage levels are:
* -fsanitize-coverage=func - function-level coverage
* -fsanitize-coverage=bb - basic-block-level coverage
* -fsanitize-coverage=edge - edge-level coverage
Extra features are:
* -fsanitize-coverage=indirect-calls - coverage for indirect calls
* -fsanitize-coverage=trace-bb - tracing for basic blocks
* -fsanitize-coverage=trace-cmp - tracing for cmp instructions
* -fsanitize-coverage=8bit-counters - frequency counters
Levels and features can be combined in comma-separated list, and
can be disabled by subsequent -fno-sanitize-coverage= flags, e.g.:
-fsanitize-coverage=bb,trace-bb,8bit-counters -fno-sanitize-coverage=trace-bb
is equivalient to:
-fsanitize-coverage=bb,8bit-counters
Original semantics of -fsanitize-coverage flag is preserved:
* -fsanitize-coverage=0 disables the coverage
* -fsanitize-coverage=1 is a synonym for -fsanitize-coverage=func
* -fsanitize-coverage=2 is a synonym for -fsanitize-coverage=bb
* -fsanitize-coverage=3 is a synonym for -fsanitize-coverage=edge
* -fsanitize-coverage=4 is a synonym for -fsanitize-coverage=edge,indirect-calls
Driver tries to diagnose invalid flag usage, in particular:
* At most one level (func,bb,edge) must be specified.
* "trace-bb" and "8bit-counters" features require some level to be specified.
See test case for more examples.
Test Plan: regression test suite
Reviewers: kcc
Subscribers: cfe-commits
Differential Revision: http://reviews.llvm.org/D9577
llvm-svn: 236790
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/CodeGen/BackendUtil.cpp | 4 | ||||
| -rw-r--r-- | clang/lib/Driver/SanitizerArgs.cpp | 128 |
2 files changed, 116 insertions, 16 deletions
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index 0206ad5838b..20fd9af169d 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -313,7 +313,9 @@ void EmitAssemblyHelper::CreatePasses() { addBoundsCheckingPass); } - if (CodeGenOpts.SanitizeCoverageType) { + if (CodeGenOpts.SanitizeCoverageType || + CodeGenOpts.SanitizeCoverageIndirectCalls || + CodeGenOpts.SanitizeCoverageTraceCmp) { PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast, addSanitizerCoveragePass); PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0, diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index 528b7243c5f..94379ba6290 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -50,6 +50,16 @@ enum SanitizeKind : uint64_t { LegacyFsanitizeRecoverMask = Undefined | Integer, NeedsLTO = CFI, }; + +enum CoverageFeature { + CoverageFunc = 1 << 0, + CoverageBB = 1 << 1, + CoverageEdge = 1 << 2, + CoverageIndirCall = 1 << 3, + CoverageTraceBB = 1 << 4, + CoverageTraceCmp = 1 << 5, + Coverage8bitCounters = 1 << 6, +}; } /// Returns true if set of \p Sanitizers contain at least one sanitizer from @@ -88,6 +98,10 @@ static uint64_t parseValue(const char *Value); static uint64_t parseArgValues(const Driver &D, const llvm::opt::Arg *A, bool DiagnoseErrors); +/// Parse -f(no-)?sanitize-coverage= flag values, diagnosing any invalid +/// components. Returns OR of members of \c CoverageFeature enumeration. +static int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A); + /// Produce an argument string from ArgList \p Args, which shows how it /// provides some sanitizer kind from \p Mask. For example, the argument list /// "-fsanitize=thread,vptr -fsanitize=address" with mask \c NeedsUbsanRt @@ -181,7 +195,7 @@ void SanitizerArgs::clear() { Sanitizers.clear(); RecoverableSanitizers.clear(); BlacklistFiles.clear(); - SanitizeCoverage = 0; + CoverageFeatures = 0; MsanTrackOrigins = 0; AsanFieldPadding = 0; AsanZeroBaseShadow = false; @@ -393,16 +407,70 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, } } - // Parse -fsanitize-coverage=N. Currently one of asan/msan/lsan is required. + // Parse -f(no-)?sanitize-coverage flags if coverage is supported by the + // enabled sanitizers. if (Kinds & SanitizeKind::SupportsCoverage) { - if (Arg *A = Args.getLastArg(options::OPT_fsanitize_coverage)) { - StringRef S = A->getValue(); - // Legal values are 0..4. - if (S.getAsInteger(0, SanitizeCoverage) || SanitizeCoverage < 0 || - SanitizeCoverage > 4) - D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; + for (const auto *Arg : Args) { + if (Arg->getOption().matches(options::OPT_fsanitize_coverage)) { + Arg->claim(); + int LegacySanitizeCoverage; + if (Arg->getNumValues() == 1 && + !StringRef(Arg->getValue(0)) + .getAsInteger(0, LegacySanitizeCoverage) && + LegacySanitizeCoverage >= 0 && LegacySanitizeCoverage <= 4) { + // TODO: Add deprecation notice for this form. + switch (LegacySanitizeCoverage) { + case 0: + CoverageFeatures = 0; + break; + case 1: + CoverageFeatures = CoverageFunc; + break; + case 2: + CoverageFeatures = CoverageBB; + break; + case 3: + CoverageFeatures = CoverageEdge; + break; + case 4: + CoverageFeatures = CoverageEdge | CoverageIndirCall; + break; + } + continue; + } + CoverageFeatures |= parseCoverageFeatures(D, Arg); + } else if (Arg->getOption().matches(options::OPT_fno_sanitize_coverage)) { + Arg->claim(); + CoverageFeatures &= ~parseCoverageFeatures(D, Arg); + } } } + // Choose at most one coverage type: function, bb, or edge. + if ((CoverageFeatures & CoverageFunc) && (CoverageFeatures & CoverageBB)) + D.Diag(clang::diag::err_drv_argument_not_allowed_with) + << "-fsanitize-coverage=func" + << "-fsanitize-coverage=bb"; + if ((CoverageFeatures & CoverageFunc) && (CoverageFeatures & CoverageEdge)) + D.Diag(clang::diag::err_drv_argument_not_allowed_with) + << "-fsanitize-coverage=func" + << "-fsanitize-coverage=edge"; + if ((CoverageFeatures & CoverageBB) && (CoverageFeatures & CoverageEdge)) + D.Diag(clang::diag::err_drv_argument_not_allowed_with) + << "-fsanitize-coverage=bb" + << "-fsanitize-coverage=edge"; + // Basic block tracing and 8-bit counters require some type of coverage + // enabled. + int CoverageTypes = CoverageFunc | CoverageBB | CoverageEdge; + if ((CoverageFeatures & CoverageTraceBB) && + !(CoverageFeatures & CoverageTypes)) + D.Diag(clang::diag::err_drv_argument_only_allowed_with) + << "-fsanitize-coverage=trace-bb" + << "-fsanitize-coverage=(func|bb|edge)"; + if ((CoverageFeatures & Coverage8bitCounters) && + !(CoverageFeatures & CoverageTypes)) + D.Diag(clang::diag::err_drv_argument_only_allowed_with) + << "-fsanitize-coverage=8bit-counters" + << "-fsanitize-coverage=(func|bb|edge)"; if (Kinds & SanitizeKind::Address) { AsanSharedRuntime = @@ -482,14 +550,21 @@ void SanitizerArgs::addArgs(const llvm::opt::ArgList &Args, if (AsanFieldPadding) CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-field-padding=" + llvm::utostr(AsanFieldPadding))); - if (SanitizeCoverage) { - int CoverageType = std::min(SanitizeCoverage, 3); - CmdArgs.push_back(Args.MakeArgString("-fsanitize-coverage-type=" + - llvm::utostr(CoverageType))); - if (SanitizeCoverage == 4) - CmdArgs.push_back( - Args.MakeArgString("-fsanitize-coverage-indirect-calls")); + // Translate available CoverageFeatures to corresponding clang-cc1 flags. + std::pair<int, const char *> CoverageFlags[] = { + std::make_pair(CoverageFunc, "-fsanitize-coverage-type=1"), + std::make_pair(CoverageBB, "-fsanitize-coverage-type=2"), + std::make_pair(CoverageEdge, "-fsanitize-coverage-type=3"), + std::make_pair(CoverageIndirCall, "-fsanitize-coverage-indirect-calls"), + std::make_pair(CoverageTraceBB, "-fsanitize-coverage-trace-bb"), + std::make_pair(CoverageTraceCmp, "-fsanitize-coverage-trace-cmp"), + std::make_pair(Coverage8bitCounters, "-fsanitize-coverage-8bit-counters")}; + for (auto F : CoverageFlags) { + if (CoverageFeatures & F.first) + CmdArgs.push_back(Args.MakeArgString(F.second)); } + + // MSan: Workaround for PR16386. // ASan: This is mainly to help LSan with cases such as // https://code.google.com/p/address-sanitizer/issues/detail?id=373 @@ -543,6 +618,29 @@ uint64_t parseArgValues(const Driver &D, const llvm::opt::Arg *A, return Kinds; } +int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A) { + assert(A->getOption().matches(options::OPT_fsanitize_coverage) || + A->getOption().matches(options::OPT_fno_sanitize_coverage)); + int Features = 0; + for (int i = 0, n = A->getNumValues(); i != n; ++i) { + const char *Value = A->getValue(i); + int F = llvm::StringSwitch<int>(Value) + .Case("func", CoverageFunc) + .Case("bb", CoverageBB) + .Case("edge", CoverageEdge) + .Case("indirect-calls", CoverageIndirCall) + .Case("trace-bb", CoverageTraceBB) + .Case("trace-cmp", CoverageTraceCmp) + .Case("8bit-counters", Coverage8bitCounters) + .Default(0); + if (F == 0) + D.Diag(clang::diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << Value; + Features |= F; + } + return Features; +} + std::string lastArgumentForMask(const Driver &D, const llvm::opt::ArgList &Args, uint64_t Mask) { for (llvm::opt::ArgList::const_reverse_iterator I = Args.rbegin(), |

