@@ -50,6 +50,16 @@ enum SanitizeKind : uint64_t {
50
50
LegacyFsanitizeRecoverMask = Undefined | Integer,
51
51
NeedsLTO = CFI,
52
52
};
53
+
54
+ enum CoverageFeature {
55
+ CoverageFunc = 1 << 0 ,
56
+ CoverageBB = 1 << 1 ,
57
+ CoverageEdge = 1 << 2 ,
58
+ CoverageIndirCall = 1 << 3 ,
59
+ CoverageTraceBB = 1 << 4 ,
60
+ CoverageTraceCmp = 1 << 5 ,
61
+ Coverage8bitCounters = 1 << 6 ,
62
+ };
53
63
}
54
64
55
65
// / Returns true if set of \p Sanitizers contain at least one sanitizer from
@@ -88,6 +98,10 @@ static uint64_t parseValue(const char *Value);
88
98
static uint64_t parseArgValues (const Driver &D, const llvm::opt::Arg *A,
89
99
bool DiagnoseErrors);
90
100
101
+ // / Parse -f(no-)?sanitize-coverage= flag values, diagnosing any invalid
102
+ // / components. Returns OR of members of \c CoverageFeature enumeration.
103
+ static int parseCoverageFeatures (const Driver &D, const llvm::opt::Arg *A);
104
+
91
105
// / Produce an argument string from ArgList \p Args, which shows how it
92
106
// / provides some sanitizer kind from \p Mask. For example, the argument list
93
107
// / "-fsanitize=thread,vptr -fsanitize=address" with mask \c NeedsUbsanRt
@@ -181,7 +195,7 @@ void SanitizerArgs::clear() {
181
195
Sanitizers.clear ();
182
196
RecoverableSanitizers.clear ();
183
197
BlacklistFiles.clear ();
184
- SanitizeCoverage = 0 ;
198
+ CoverageFeatures = 0 ;
185
199
MsanTrackOrigins = 0 ;
186
200
AsanFieldPadding = 0 ;
187
201
AsanZeroBaseShadow = false ;
@@ -393,16 +407,70 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
393
407
}
394
408
}
395
409
396
- // Parse -fsanitize-coverage=N. Currently one of asan/msan/lsan is required.
410
+ // Parse -f(no-)?sanitize-coverage flags if coverage is supported by the
411
+ // enabled sanitizers.
397
412
if (Kinds & SanitizeKind::SupportsCoverage) {
398
- if (Arg *A = Args.getLastArg (options::OPT_fsanitize_coverage)) {
399
- StringRef S = A->getValue ();
400
- // Legal values are 0..4.
401
- if (S.getAsInteger (0 , SanitizeCoverage) || SanitizeCoverage < 0 ||
402
- SanitizeCoverage > 4 )
403
- D.Diag (clang::diag::err_drv_invalid_value) << A->getAsString (Args) << S;
413
+ for (const auto *Arg : Args) {
414
+ if (Arg->getOption ().matches (options::OPT_fsanitize_coverage)) {
415
+ Arg->claim ();
416
+ int LegacySanitizeCoverage;
417
+ if (Arg->getNumValues () == 1 &&
418
+ !StringRef (Arg->getValue (0 ))
419
+ .getAsInteger (0 , LegacySanitizeCoverage) &&
420
+ LegacySanitizeCoverage >= 0 && LegacySanitizeCoverage <= 4 ) {
421
+ // TODO: Add deprecation notice for this form.
422
+ switch (LegacySanitizeCoverage) {
423
+ case 0 :
424
+ CoverageFeatures = 0 ;
425
+ break ;
426
+ case 1 :
427
+ CoverageFeatures = CoverageFunc;
428
+ break ;
429
+ case 2 :
430
+ CoverageFeatures = CoverageBB;
431
+ break ;
432
+ case 3 :
433
+ CoverageFeatures = CoverageEdge;
434
+ break ;
435
+ case 4 :
436
+ CoverageFeatures = CoverageEdge | CoverageIndirCall;
437
+ break ;
438
+ }
439
+ continue ;
440
+ }
441
+ CoverageFeatures |= parseCoverageFeatures (D, Arg);
442
+ } else if (Arg->getOption ().matches (options::OPT_fno_sanitize_coverage)) {
443
+ Arg->claim ();
444
+ CoverageFeatures &= ~parseCoverageFeatures (D, Arg);
445
+ }
404
446
}
405
447
}
448
+ // Choose at most one coverage type: function, bb, or edge.
449
+ if ((CoverageFeatures & CoverageFunc) && (CoverageFeatures & CoverageBB))
450
+ D.Diag (clang::diag::err_drv_argument_not_allowed_with)
451
+ << " -fsanitize-coverage=func"
452
+ << " -fsanitize-coverage=bb" ;
453
+ if ((CoverageFeatures & CoverageFunc) && (CoverageFeatures & CoverageEdge))
454
+ D.Diag (clang::diag::err_drv_argument_not_allowed_with)
455
+ << " -fsanitize-coverage=func"
456
+ << " -fsanitize-coverage=edge" ;
457
+ if ((CoverageFeatures & CoverageBB) && (CoverageFeatures & CoverageEdge))
458
+ D.Diag (clang::diag::err_drv_argument_not_allowed_with)
459
+ << " -fsanitize-coverage=bb"
460
+ << " -fsanitize-coverage=edge" ;
461
+ // Basic block tracing and 8-bit counters require some type of coverage
462
+ // enabled.
463
+ int CoverageTypes = CoverageFunc | CoverageBB | CoverageEdge;
464
+ if ((CoverageFeatures & CoverageTraceBB) &&
465
+ !(CoverageFeatures & CoverageTypes))
466
+ D.Diag (clang::diag::err_drv_argument_only_allowed_with)
467
+ << " -fsanitize-coverage=trace-bb"
468
+ << " -fsanitize-coverage=(func|bb|edge)" ;
469
+ if ((CoverageFeatures & Coverage8bitCounters) &&
470
+ !(CoverageFeatures & CoverageTypes))
471
+ D.Diag (clang::diag::err_drv_argument_only_allowed_with)
472
+ << " -fsanitize-coverage=8bit-counters"
473
+ << " -fsanitize-coverage=(func|bb|edge)" ;
406
474
407
475
if (Kinds & SanitizeKind::Address) {
408
476
AsanSharedRuntime =
@@ -482,14 +550,21 @@ void SanitizerArgs::addArgs(const llvm::opt::ArgList &Args,
482
550
if (AsanFieldPadding)
483
551
CmdArgs.push_back (Args.MakeArgString (" -fsanitize-address-field-padding=" +
484
552
llvm::utostr (AsanFieldPadding)));
485
- if (SanitizeCoverage) {
486
- int CoverageType = std::min (SanitizeCoverage, 3 );
487
- CmdArgs.push_back (Args.MakeArgString (" -fsanitize-coverage-type=" +
488
- llvm::utostr (CoverageType)));
489
- if (SanitizeCoverage == 4 )
490
- CmdArgs.push_back (
491
- Args.MakeArgString (" -fsanitize-coverage-indirect-calls" ));
553
+ // Translate available CoverageFeatures to corresponding clang-cc1 flags.
554
+ std::pair<int , const char *> CoverageFlags[] = {
555
+ std::make_pair (CoverageFunc, " -fsanitize-coverage-type=1" ),
556
+ std::make_pair (CoverageBB, " -fsanitize-coverage-type=2" ),
557
+ std::make_pair (CoverageEdge, " -fsanitize-coverage-type=3" ),
558
+ std::make_pair (CoverageIndirCall, " -fsanitize-coverage-indirect-calls" ),
559
+ std::make_pair (CoverageTraceBB, " -fsanitize-coverage-trace-bb" ),
560
+ std::make_pair (CoverageTraceCmp, " -fsanitize-coverage-trace-cmp" ),
561
+ std::make_pair (Coverage8bitCounters, " -fsanitize-coverage-8bit-counters" )};
562
+ for (auto F : CoverageFlags) {
563
+ if (CoverageFeatures & F.first )
564
+ CmdArgs.push_back (Args.MakeArgString (F.second ));
492
565
}
566
+
567
+
493
568
// MSan: Workaround for PR16386.
494
569
// ASan: This is mainly to help LSan with cases such as
495
570
// 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,
543
618
return Kinds;
544
619
}
545
620
621
+ int parseCoverageFeatures (const Driver &D, const llvm::opt::Arg *A) {
622
+ assert (A->getOption ().matches (options::OPT_fsanitize_coverage) ||
623
+ A->getOption ().matches (options::OPT_fno_sanitize_coverage));
624
+ int Features = 0 ;
625
+ for (int i = 0 , n = A->getNumValues (); i != n; ++i) {
626
+ const char *Value = A->getValue (i);
627
+ int F = llvm::StringSwitch<int >(Value)
628
+ .Case (" func" , CoverageFunc)
629
+ .Case (" bb" , CoverageBB)
630
+ .Case (" edge" , CoverageEdge)
631
+ .Case (" indirect-calls" , CoverageIndirCall)
632
+ .Case (" trace-bb" , CoverageTraceBB)
633
+ .Case (" trace-cmp" , CoverageTraceCmp)
634
+ .Case (" 8bit-counters" , Coverage8bitCounters)
635
+ .Default (0 );
636
+ if (F == 0 )
637
+ D.Diag (clang::diag::err_drv_unsupported_option_argument)
638
+ << A->getOption ().getName () << Value;
639
+ Features |= F;
640
+ }
641
+ return Features;
642
+ }
643
+
546
644
std::string lastArgumentForMask (const Driver &D, const llvm::opt::ArgList &Args,
547
645
uint64_t Mask) {
548
646
for (llvm::opt::ArgList::const_reverse_iterator I = Args.rbegin (),
0 commit comments