[clang] 3e52c09 - Add -fsanitizer-coverage=control-flow
Vitaly Buka via cfe-commits
cfe-commits at lists.llvm.org
Thu Sep 15 15:56:18 PDT 2022
Author: Navid Emamdoost
Date: 2022-09-15T15:56:04-07:00
New Revision: 3e52c0926c22575d918e7ca8369522b986635cd3
URL: https://github.com/llvm/llvm-project/commit/3e52c0926c22575d918e7ca8369522b986635cd3
DIFF: https://github.com/llvm/llvm-project/commit/3e52c0926c22575d918e7ca8369522b986635cd3.diff
LOG: Add -fsanitizer-coverage=control-flow
Reviewed By: kcc, vitalybuka, MaskRay
Differential Revision: https://reviews.llvm.org/D133157
Added:
compiler-rt/test/sanitizer_common/TestCases/sanitizer_coverage_control_flow.cpp
llvm/test/Instrumentation/SanitizerCoverage/control-flow.ll
Modified:
clang/docs/SanitizerCoverage.rst
clang/include/clang/Basic/CodeGenOptions.def
clang/include/clang/Basic/CodeGenOptions.h
clang/include/clang/Driver/Options.td
clang/lib/CodeGen/BackendUtil.cpp
clang/lib/Driver/SanitizerArgs.cpp
clang/test/Driver/fsanitize-coverage.c
llvm/include/llvm/Transforms/Instrumentation.h
llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp
Removed:
################################################################################
diff --git a/clang/docs/SanitizerCoverage.rst b/clang/docs/SanitizerCoverage.rst
index 9d4a32231b60d..c6e77cd7295c2 100644
--- a/clang/docs/SanitizerCoverage.rst
+++ b/clang/docs/SanitizerCoverage.rst
@@ -331,6 +331,60 @@ will not be instrumented.
void __sanitizer_cov_store8(uint64_t *addr);
void __sanitizer_cov_store16(__int128 *addr);
+
+Tracing control flow
+====================
+
+With ``-fsanitize-coverage=control-flow`` the compiler will create a table to collect
+control flow for each function. More specifically, for each basic block in the function,
+two lists are populated. One list for successors of the basic block and another list for
+non-intrinsic called functions.
+
+**TODO:** in the current implementation, indirect calls are not tracked
+and are only marked with special value (-1) in the list.
+
+Each table row consists of the basic block address
+followed by ``null``-ended lists of successors and callees.
+The table is encoded in a special section named ``sancov_cfs``
+
+Example:
+
+.. code-block:: c++
+ int foo (int x) {
+ if (x > 0)
+ bar(x);
+ else
+ x = 0;
+ return x;
+ }
+
+The code above contains 4 basic blocks, let's name them A, B, C, D:
+
+.. code-block:: none
+
+ A
+ |\
+ | \
+ B C
+ | /
+ |/
+ D
+
+The collected control flow table is as follows:
+``A, B, C, null, null, B, D, null, @bar, null, C, D, null, null, D, null, null.``
+
+Users need to implement a single function to capture the CF table at startup:
+
+.. code-block:: c++
+
+ extern "C"
+ void __sanitizer_cov_cfs_init(const uintptr_t *cfs_beg,
+ const uintptr_t *cfs_end) {
+ // [cfs_beg,cfs_end) is the array of ptr-sized integers representing
+ // the collected control flow.
+ }
+
+
Disabling instrumentation with ``__attribute__((no_sanitize("coverage")))``
===========================================================================
diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index 9c1a23cb17261..c3b6b289fcff8 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -281,6 +281,7 @@ CODEGENOPT(SanitizeCoverageTracePCGuard, 1, 0) ///< Enable PC tracing with guard
CODEGENOPT(SanitizeCoverageInline8bitCounters, 1, 0) ///< Use inline 8bit counters.
CODEGENOPT(SanitizeCoverageInlineBoolFlag, 1, 0) ///< Use inline bool flag.
CODEGENOPT(SanitizeCoveragePCTable, 1, 0) ///< Create a PC Table.
+CODEGENOPT(SanitizeCoverageControlFlow, 1, 0) ///< Collect control flow
CODEGENOPT(SanitizeCoverageNoPrune, 1, 0) ///< Disable coverage pruning.
CODEGENOPT(SanitizeCoverageStackDepth, 1, 0) ///< Enable max stack depth tracing
CODEGENOPT(SanitizeCoverageTraceLoads, 1, 0) ///< Enable tracing of loads.
diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h
index 0504012badb04..98f537e62b608 100644
--- a/clang/include/clang/Basic/CodeGenOptions.h
+++ b/clang/include/clang/Basic/CodeGenOptions.h
@@ -483,7 +483,7 @@ class CodeGenOptions : public CodeGenOptionsBase {
bool hasSanitizeCoverage() const {
return SanitizeCoverageType || SanitizeCoverageIndirectCalls ||
SanitizeCoverageTraceCmp || SanitizeCoverageTraceLoads ||
- SanitizeCoverageTraceStores;
+ SanitizeCoverageTraceStores || SanitizeCoverageControlFlow;
}
// Check if any one of SanitizeBinaryMetadata* is enabled.
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 2e0f4c9452d65..a1071294ff6f5 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -5486,6 +5486,10 @@ def fsanitize_coverage_pc_table
: Flag<["-"], "fsanitize-coverage-pc-table">,
HelpText<"Create a table of coverage-instrumented PCs">,
MarshallingInfoFlag<CodeGenOpts<"SanitizeCoveragePCTable">>;
+def fsanitize_coverage_control_flow
+ : Flag<["-"], "fsanitize-coverage-control-flow">,
+ HelpText<"Collect control flow of function">,
+ MarshallingInfoFlag<CodeGenOpts<"SanitizeCoverageControlFlow">>;
def fsanitize_coverage_trace_pc
: Flag<["-"], "fsanitize-coverage-trace-pc">,
HelpText<"Enable PC tracing in sanitizer coverage">,
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index e9f2f5d9d1c67..874fed795da9f 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -225,6 +225,7 @@ getSancovOptsFromCGOpts(const CodeGenOptions &CGOpts) {
Opts.StackDepth = CGOpts.SanitizeCoverageStackDepth;
Opts.TraceLoads = CGOpts.SanitizeCoverageTraceLoads;
Opts.TraceStores = CGOpts.SanitizeCoverageTraceStores;
+ Opts.CollectControlFlow = CGOpts.SanitizeCoverageControlFlow;
return Opts;
}
diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp
index 6319e3c433ab1..631cf007da5d9 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -98,6 +98,7 @@ enum CoverageFeature {
CoverageInlineBoolFlag = 1 << 15,
CoverageTraceLoads = 1 << 16,
CoverageTraceStores = 1 << 17,
+ CoverageControlFlow = 1 << 18,
};
enum BinaryMetadataFeature {
@@ -808,19 +809,21 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
int InsertionPointTypes = CoverageFunc | CoverageBB | CoverageEdge;
int InstrumentationTypes = CoverageTracePC | CoverageTracePCGuard |
CoverageInline8bitCounters | CoverageTraceLoads |
- CoverageTraceStores | CoverageInlineBoolFlag;
+ CoverageTraceStores | CoverageInlineBoolFlag |
+ CoverageControlFlow;
if ((CoverageFeatures & InsertionPointTypes) &&
!(CoverageFeatures & InstrumentationTypes) && DiagnoseErrors) {
D.Diag(clang::diag::warn_drv_deprecated_arg)
<< "-fsanitize-coverage=[func|bb|edge]"
- << "-fsanitize-coverage=[func|bb|edge],[trace-pc-guard|trace-pc]";
+ << "-fsanitize-coverage=[func|bb|edge],[trace-pc-guard|trace-pc],["
+ "control-flow]";
}
// trace-pc w/o func/bb/edge implies edge.
if (!(CoverageFeatures & InsertionPointTypes)) {
if (CoverageFeatures &
(CoverageTracePC | CoverageTracePCGuard | CoverageInline8bitCounters |
- CoverageInlineBoolFlag))
+ CoverageInlineBoolFlag | CoverageControlFlow))
CoverageFeatures |= CoverageEdge;
if (CoverageFeatures & CoverageStackDepth)
@@ -1111,7 +1114,8 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
std::make_pair(CoverageNoPrune, "-fsanitize-coverage-no-prune"),
std::make_pair(CoverageStackDepth, "-fsanitize-coverage-stack-depth"),
std::make_pair(CoverageTraceLoads, "-fsanitize-coverage-trace-loads"),
- std::make_pair(CoverageTraceStores, "-fsanitize-coverage-trace-stores")};
+ std::make_pair(CoverageTraceStores, "-fsanitize-coverage-trace-stores"),
+ std::make_pair(CoverageControlFlow, "-fsanitize-coverage-control-flow")};
for (auto F : CoverageFlags) {
if (CoverageFeatures & F.first)
CmdArgs.push_back(F.second);
@@ -1369,6 +1373,7 @@ int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A,
.Case("stack-depth", CoverageStackDepth)
.Case("trace-loads", CoverageTraceLoads)
.Case("trace-stores", CoverageTraceStores)
+ .Case("control-flow", CoverageControlFlow)
.Default(0);
if (F == 0 && DiagnoseErrors)
D.Diag(clang::diag::err_drv_unsupported_option_argument)
diff --git a/clang/test/Driver/fsanitize-coverage.c b/clang/test/Driver/fsanitize-coverage.c
index 27d292ab2cd33..d18321d77d55f 100644
--- a/clang/test/Driver/fsanitize-coverage.c
+++ b/clang/test/Driver/fsanitize-coverage.c
@@ -36,7 +36,7 @@
// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=func %s -### 2>&1 | FileCheck %s --check-prefix=CHECK_FUNC_BB_EDGE_DEPRECATED
// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=bb %s -### 2>&1 | FileCheck %s --check-prefix=CHECK_FUNC_BB_EDGE_DEPRECATED
// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=edge %s -### 2>&1 | FileCheck %s --check-prefix=CHECK_FUNC_BB_EDGE_DEPRECATED
-// CHECK_FUNC_BB_EDGE_DEPRECATED: warning: argument '-fsanitize-coverage=[func|bb|edge]' is deprecated, use '-fsanitize-coverage=[func|bb|edge],[trace-pc-guard|trace-pc]' instead
+// CHECK_FUNC_BB_EDGE_DEPRECATED: warning: argument '-fsanitize-coverage=[func|bb|edge]' is deprecated, use '-fsanitize-coverage=[func|bb|edge],[trace-pc-guard|trace-pc],[control-flow]' instead
// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=edge,indirect-calls,trace-pc,trace-cmp,trace-loads,trace-stores,trace-div,trace-gep %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-FEATURES
// CHECK-SANITIZE-COVERAGE-FEATURES: -fsanitize-coverage-type=3
diff --git a/compiler-rt/test/sanitizer_common/TestCases/sanitizer_coverage_control_flow.cpp b/compiler-rt/test/sanitizer_common/TestCases/sanitizer_coverage_control_flow.cpp
new file mode 100644
index 0000000000000..4e85395731179
--- /dev/null
+++ b/compiler-rt/test/sanitizer_common/TestCases/sanitizer_coverage_control_flow.cpp
@@ -0,0 +1,75 @@
+// Tests -fsanitize-coverage=control-flow.
+
+// REQUIRES: has_sancovcc,stable-runtime
+// UNSUPPORTED: i386-darwin, x86_64-darwin
+
+// RUN: %clangxx -O0 -std=c++11 -fsanitize-coverage=control-flow %s -o %t
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#include <cstdint>
+#include <cstdio>
+
+uintptr_t *CFS_BEG, *CFS_END;
+
+extern "C" void __sanitizer_cov_cfs_init(const uintptr_t *cfs_beg,
+ const uintptr_t *cfs_end) {
+ CFS_BEG = (uintptr_t *)cfs_beg;
+ CFS_END = (uintptr_t *)cfs_end;
+}
+
+__attribute__((noinline)) void foo(int x) { /* empty body */
+}
+
+void check_cfs_section(uintptr_t main_ptr, uintptr_t foo_ptr) {
+ printf("Control Flow section boundaries: [%p %p)\n", CFS_BEG, CFS_END);
+ uintptr_t *pt = CFS_BEG;
+ uintptr_t currBB;
+
+ while (pt < CFS_END) {
+ currBB = *pt;
+ pt++;
+
+ if (currBB == main_ptr)
+ printf("Saw the main().\n");
+ else if (currBB == foo_ptr)
+ printf("Saw the foo().\n");
+
+ // Iterate over successors.
+ while (*pt) {
+ pt++;
+ }
+ pt++;
+ // Iterate over callees.
+ while (*pt) {
+ if (*pt == foo_ptr && currBB != main_ptr)
+ printf("Direct call matched.\n");
+ if (*pt == -1 && currBB != main_ptr)
+ printf("Indirect call matched.\n");
+ pt++;
+ }
+ pt++;
+ }
+}
+
+int main() {
+ auto main_ptr = &main;
+ auto foo_ptr = &foo;
+ int x = 10;
+
+ if (x > 0)
+ foo(x);
+ else
+ (*foo_ptr)(x);
+
+ check_cfs_section((uintptr_t)(*main_ptr), (uintptr_t)(*foo_ptr));
+
+ printf("Finished!\n");
+ return 0;
+}
+
+// CHECK: Control Flow section boundaries
+// CHECK-DAG: Saw the foo().
+// CHECK-DAG: Saw the main().
+// CHECK-DAG: Direct call matched.
+// CHECK-DAG: Indirect call matched.
+// CHECK: Finished!
diff --git a/llvm/include/llvm/Transforms/Instrumentation.h b/llvm/include/llvm/Transforms/Instrumentation.h
index 4b33dad08b6b7..2cbd46d414efd 100644
--- a/llvm/include/llvm/Transforms/Instrumentation.h
+++ b/llvm/include/llvm/Transforms/Instrumentation.h
@@ -150,6 +150,7 @@ struct SanitizerCoverageOptions {
bool StackDepth = false;
bool TraceLoads = false;
bool TraceStores = false;
+ bool CollectControlFlow = false;
SanitizerCoverageOptions() = default;
};
diff --git a/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp b/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp
index 2eed3d7cf995e..5cfa520db4eba 100644
--- a/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp
+++ b/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp
@@ -76,11 +76,13 @@ const char SanCovTracePCGuardInitName[] = "__sanitizer_cov_trace_pc_guard_init";
const char SanCov8bitCountersInitName[] = "__sanitizer_cov_8bit_counters_init";
const char SanCovBoolFlagInitName[] = "__sanitizer_cov_bool_flag_init";
const char SanCovPCsInitName[] = "__sanitizer_cov_pcs_init";
+const char SanCovCFsInitName[] = "__sanitizer_cov_cfs_init";
const char SanCovGuardsSectionName[] = "sancov_guards";
const char SanCovCountersSectionName[] = "sancov_cntrs";
const char SanCovBoolFlagSectionName[] = "sancov_bools";
const char SanCovPCsSectionName[] = "sancov_pcs";
+const char SanCovCFsSectionName[] = "sancov_cfs";
const char SanCovLowestStackName[] = "__sancov_lowest_stack";
@@ -148,6 +150,11 @@ static cl::opt<bool> ClStackDepth("sanitizer-coverage-stack-depth",
cl::desc("max stack depth tracing"),
cl::Hidden, cl::init(false));
+static cl::opt<bool>
+ ClCollectCF("sanitizer-coverage-control-flow",
+ cl::desc("collect control flow for each function"), cl::Hidden,
+ cl::init(false));
+
namespace {
SanitizerCoverageOptions getOptions(int LegacyCoverageLevel) {
@@ -194,6 +201,7 @@ SanitizerCoverageOptions OverrideFromCL(SanitizerCoverageOptions Options) {
!Options.Inline8bitCounters && !Options.StackDepth &&
!Options.InlineBoolFlag && !Options.TraceLoads && !Options.TraceStores)
Options.TracePCGuard = true; // TracePCGuard is default.
+ Options.CollectControlFlow |= ClCollectCF;
return Options;
}
@@ -213,6 +221,7 @@ class ModuleSanitizerCoverage {
PostDomTreeCallback PDTCallback);
private:
+ void createFunctionControlFlow(Function &F);
void instrumentFunction(Function &F, DomTreeCallback DTCallback,
PostDomTreeCallback PDTCallback);
void InjectCoverageForIndirectCalls(Function &F,
@@ -271,6 +280,7 @@ class ModuleSanitizerCoverage {
GlobalVariable *Function8bitCounterArray; // for inline-8bit-counters.
GlobalVariable *FunctionBoolArray; // for inline-bool-flag.
GlobalVariable *FunctionPCsArray; // for pc-table.
+ GlobalVariable *FunctionCFsArray; // for control flow table
SmallVector<GlobalValue *, 20> GlobalsToAppendToUsed;
SmallVector<GlobalValue *, 20> GlobalsToAppendToCompilerUsed;
@@ -385,6 +395,7 @@ bool ModuleSanitizerCoverage::instrumentModule(
Function8bitCounterArray = nullptr;
FunctionBoolArray = nullptr;
FunctionPCsArray = nullptr;
+ FunctionCFsArray = nullptr;
IntptrTy = Type::getIntNTy(*C, DL->getPointerSizeInBits());
IntptrPtrTy = PointerType::getUnqual(IntptrTy);
Type *VoidTy = Type::getVoidTy(*C);
@@ -509,6 +520,15 @@ bool ModuleSanitizerCoverage::instrumentModule(
IRBuilder<> IRBCtor(Ctor->getEntryBlock().getTerminator());
IRBCtor.CreateCall(InitFunction, {SecStartEnd.first, SecStartEnd.second});
}
+
+ if (Ctor && Options.CollectControlFlow) {
+ auto SecStartEnd = CreateSecStartEnd(M, SanCovCFsSectionName, IntptrPtrTy);
+ FunctionCallee InitFunction = declareSanitizerInitFunction(
+ M, SanCovCFsInitName, {IntptrPtrTy, IntptrPtrTy});
+ IRBuilder<> IRBCtor(Ctor->getEntryBlock().getTerminator());
+ IRBCtor.CreateCall(InitFunction, {SecStartEnd.first, SecStartEnd.second});
+ }
+
appendToUsed(M, GlobalsToAppendToUsed);
appendToCompilerUsed(M, GlobalsToAppendToCompilerUsed);
return true;
@@ -678,6 +698,9 @@ void ModuleSanitizerCoverage::instrumentFunction(
}
}
+ if (Options.CollectControlFlow)
+ createFunctionControlFlow(F);
+
InjectCoverage(F, BlocksToInstrument, IsLeafFunc);
InjectCoverageForIndirectCalls(F, IndirCalls);
InjectTraceForCmp(F, CmpTraceTargets);
@@ -1034,3 +1057,48 @@ ModuleSanitizerCoverage::getSectionEnd(const std::string &Section) const {
return "\1section$end$__DATA$__" + Section;
return "__stop___" + Section;
}
+
+void ModuleSanitizerCoverage::createFunctionControlFlow(Function &F) {
+ SmallVector<Constant *, 32> CFs;
+ IRBuilder<> IRB(&*F.getEntryBlock().getFirstInsertionPt());
+
+ for (auto &BB : F) {
+ // blockaddress can not be used on function's entry block.
+ if (&BB == &F.getEntryBlock())
+ CFs.push_back((Constant *)IRB.CreatePointerCast(&F, IntptrPtrTy));
+ else
+ CFs.push_back((Constant *)IRB.CreatePointerCast(BlockAddress::get(&BB),
+ IntptrPtrTy));
+
+ for (auto SuccBB : successors(&BB)) {
+ assert(SuccBB != &F.getEntryBlock());
+ CFs.push_back((Constant *)IRB.CreatePointerCast(BlockAddress::get(SuccBB),
+ IntptrPtrTy));
+ }
+
+ CFs.push_back((Constant *)Constant::getNullValue(IntptrPtrTy));
+
+ for (auto &Inst : BB) {
+ if (CallBase *CB = dyn_cast<CallBase>(&Inst)) {
+ if (CB->isIndirectCall()) {
+ // TODO(navidem): handle indirect calls, for now mark its existence.
+ CFs.push_back((Constant *)IRB.CreateIntToPtr(
+ ConstantInt::get(IntptrTy, -1), IntptrPtrTy));
+ } else {
+ auto CalledF = CB->getCalledFunction();
+ if (CalledF && !CalledF->isIntrinsic())
+ CFs.push_back(
+ (Constant *)IRB.CreatePointerCast(CalledF, IntptrPtrTy));
+ }
+ }
+ }
+
+ CFs.push_back((Constant *)Constant::getNullValue(IntptrPtrTy));
+ }
+
+ FunctionCFsArray = CreateFunctionLocalArrayInSection(
+ CFs.size(), F, IntptrPtrTy, SanCovCFsSectionName);
+ FunctionCFsArray->setInitializer(
+ ConstantArray::get(ArrayType::get(IntptrPtrTy, CFs.size()), CFs));
+ FunctionCFsArray->setConstant(true);
+}
diff --git a/llvm/test/Instrumentation/SanitizerCoverage/control-flow.ll b/llvm/test/Instrumentation/SanitizerCoverage/control-flow.ll
new file mode 100644
index 0000000000000..809c826c2bb0a
--- /dev/null
+++ b/llvm/test/Instrumentation/SanitizerCoverage/control-flow.ll
@@ -0,0 +1,22 @@
+; Test -sanitizer-coverage-control-flow.
+; RUN: opt < %s -passes='module(sancov-module)' -sanitizer-coverage-level=3 -sanitizer-coverage-control-flow -S | FileCheck %s
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+target triple = "x86_64-unknown-linux-gnu"
+define void @foo(ptr %a) sanitize_address {
+entry:
+ %tobool = icmp eq i32* %a, null
+ br i1 %tobool, label %if.end, label %if.then
+
+ if.then: ; preds = %entry
+ store i32 0, i32* %a, align 4
+ call void @foo(i32* %a)
+ br label %if.end
+
+ if.end: ; preds = %entry, %if.then
+ ret void
+}
+
+; CHECK: private constant [17 x ptr] [{{.*}}@foo{{.*}}blockaddress{{.*}}blockaddress{{.*}}blockaddress{{.*}}blockaddress{{.*}}blockaddress{{.*}}blockaddress{{.*}}blockaddress{{.*}}@foo{{.*}}null{{.*}}null], section "__sancov_cfs", comdat($foo), align 8
+; CHECK: @__start___sancov_cfs = extern_weak hidden global
+; CHECK-NEXT: @__stop___sancov_cfs = extern_weak hidden global
More information about the cfe-commits
mailing list