Index: include/clang/Driver/CC1Options.td =================================================================== --- include/clang/Driver/CC1Options.td +++ include/clang/Driver/CC1Options.td @@ -256,9 +256,9 @@ def fsanitize_coverage_indirect_calls : Flag<["-"], "fsanitize-coverage-indirect-calls">, HelpText<"Enable sanitizer coverage for indirect calls">; -def fsanitize_coverage_trace_bb - : Flag<["-"], "fsanitize-coverage-trace-bb">, - HelpText<"Enable basic block tracing in sanitizer coverage">; +def fsanitize_coverage_trace + : Flag<["-"], "fsanitize-coverage-trace">, + HelpText<"Enable tracing in sanitizer coverage">; def fsanitize_coverage_trace_cmp : Flag<["-"], "fsanitize-coverage-trace-cmp">, HelpText<"Enable cmp instruction tracing in sanitizer coverage">; Index: include/clang/Frontend/CodeGenOptions.def =================================================================== --- include/clang/Frontend/CodeGenOptions.def +++ include/clang/Frontend/CodeGenOptions.def @@ -124,8 +124,7 @@ ///< instrumentation. CODEGENOPT(SanitizeCoverageIndirectCalls, 1, 0) ///< Enable sanitizer coverage ///< for indirect calls. -CODEGENOPT(SanitizeCoverageTraceBB, 1, 0) ///< Enable basic block tracing in - ///< in sanitizer coverage. +CODEGENOPT(SanitizeCoverageTrace, 1, 0) ///< Enable tracing in sanitizer coverage. CODEGENOPT(SanitizeCoverageTraceCmp, 1, 0) ///< Enable cmp instruction tracing ///< in sanitizer coverage. CODEGENOPT(SanitizeCoverage8bitCounters, 1, 0) ///< Use 8-bit frequency counters Index: include/llvm/Transforms/Instrumentation.h =================================================================== --- include/llvm/Transforms/Instrumentation.h +++ include/llvm/Transforms/Instrumentation.h @@ -114,7 +114,7 @@ // Options for sanitizer coverage instrumentation. struct SanitizerCoverageOptions { SanitizerCoverageOptions() - : CoverageType(SCK_None), IndirectCalls(false), TraceBB(false), + : CoverageType(SCK_None), IndirectCalls(false), Trace(false), TraceCmp(false), Use8bitCounters(false) {} enum Type { @@ -124,7 +124,7 @@ SCK_Edge } CoverageType; bool IndirectCalls; - bool TraceBB; + bool Trace; bool TraceCmp; bool Use8bitCounters; }; Index: include/sanitizer/coverage_interface.h =================================================================== --- include/sanitizer/coverage_interface.h +++ include/sanitizer/coverage_interface.h @@ -58,6 +58,29 @@ // __sanitizer_get_number_of_counters bytes long and 8-aligned. uintptr_t __sanitizer_update_counter_bitset_and_clear_counters(uint8_t *bitset); + + // Per-thread, in-memory trace coverage. + // Code must be compiled with -fsanitize-coverage=trace. + + // Enable tracing for the current thread with buffer for size PCs. + // Size must be a power-of-two. + // Fails if tracing is already enabled, size is not a power of two or + // out of memory. + bool __sanitizer_trace_enable(uintptr_t size); + // Disable tracing for the current thread and free all associated resources. + // Fails if tracing is not enabled for the current thread. + bool __sanitizer_trace_disable(); + // Reset trace for the current thread. + // Fails if tracing is not enabled for the current thread. + bool __sanitizer_trace_reset(); + // Read trace of the current thread. + // Trace is set to point to an array of traced PCs, size is set to number + // of PCs in the trace. Trace memory is owned by sanitizer library, and + // is valid until call to __sanitizer_trace_disable() in this thread. + // However, the trace buffer can be overwritten if the thread executes + // instrumented code. + // Fails if tracing is not enabled for the current thread. + bool __sanitizer_trace_read(uintptr_t **trace, uintptr_t *size); #ifdef __cplusplus } // extern "C" #endif Index: lib/CodeGen/BackendUtil.cpp =================================================================== --- lib/CodeGen/BackendUtil.cpp +++ lib/CodeGen/BackendUtil.cpp @@ -186,7 +186,7 @@ Opts.CoverageType = static_cast(CGOpts.SanitizeCoverageType); Opts.IndirectCalls = CGOpts.SanitizeCoverageIndirectCalls; - Opts.TraceBB = CGOpts.SanitizeCoverageTraceBB; + Opts.Trace = CGOpts.SanitizeCoverageTrace; Opts.TraceCmp = CGOpts.SanitizeCoverageTraceCmp; Opts.Use8bitCounters = CGOpts.SanitizeCoverage8bitCounters; PM.add(createSanitizerCoverageModulePass(Opts)); Index: lib/Driver/SanitizerArgs.cpp =================================================================== --- lib/Driver/SanitizerArgs.cpp +++ lib/Driver/SanitizerArgs.cpp @@ -46,7 +46,7 @@ CoverageBB = 1 << 1, CoverageEdge = 1 << 2, CoverageIndirCall = 1 << 3, - CoverageTraceBB = 1 << 4, + CoverageTrace = 1 << 4, CoverageTraceCmp = 1 << 5, Coverage8bitCounters = 1 << 6, }; @@ -481,19 +481,12 @@ 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)"; + // Tracing and 8-bit counters require some type of coverage enabled. + // Enable edge by default. + if (((CoverageFeatures & CoverageTrace) || + (CoverageFeatures & Coverage8bitCounters)) && + !(CoverageFeatures & (CoverageFunc | CoverageBB | CoverageEdge))) + CoverageFeatures |= CoverageEdge; if (AllAddedKinds & Address) { AsanSharedRuntime = @@ -589,7 +582,7 @@ 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(CoverageTrace, "-fsanitize-coverage-trace"), std::make_pair(CoverageTraceCmp, "-fsanitize-coverage-trace-cmp"), std::make_pair(Coverage8bitCounters, "-fsanitize-coverage-8bit-counters")}; for (auto F : CoverageFlags) { @@ -657,7 +650,7 @@ .Case("bb", CoverageBB) .Case("edge", CoverageEdge) .Case("indirect-calls", CoverageIndirCall) - .Case("trace-bb", CoverageTraceBB) + .Case("trace", CoverageTrace) .Case("trace-cmp", CoverageTraceCmp) .Case("8bit-counters", Coverage8bitCounters) .Default(0); Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -568,7 +568,7 @@ getLastArgIntValue(Args, OPT_fsanitize_coverage_type, 0, Diags); Opts.SanitizeCoverageIndirectCalls = Args.hasArg(OPT_fsanitize_coverage_indirect_calls); - Opts.SanitizeCoverageTraceBB = Args.hasArg(OPT_fsanitize_coverage_trace_bb); + Opts.SanitizeCoverageTrace = Args.hasArg(OPT_fsanitize_coverage_trace); Opts.SanitizeCoverageTraceCmp = Args.hasArg(OPT_fsanitize_coverage_trace_cmp); Opts.SanitizeCoverage8bitCounters = Args.hasArg(OPT_fsanitize_coverage_8bit_counters); Index: lib/Transforms/Instrumentation/SanitizerCoverage.cpp =================================================================== --- lib/Transforms/Instrumentation/SanitizerCoverage.cpp +++ lib/Transforms/Instrumentation/SanitizerCoverage.cpp @@ -57,8 +57,7 @@ static const char *const kSanCovName = "__sanitizer_cov"; static const char *const kSanCovWithCheckName = "__sanitizer_cov_with_check"; static const char *const kSanCovIndirCallName = "__sanitizer_cov_indir_call16"; -static const char *const kSanCovTraceEnter = "__sanitizer_cov_trace_func_enter"; -static const char *const kSanCovTraceBB = "__sanitizer_cov_trace_basic_block"; +static const char *const kSanCovTrace = "__sanitizer_cov_trace"; static const char *const kSanCovTraceCmp = "__sanitizer_cov_trace_cmp"; static const char *const kSanCovTraceSwitch = "__sanitizer_cov_trace_switch"; static const char *const kSanCovModuleCtorName = "sancov.module_ctor"; @@ -77,9 +76,9 @@ cl::Hidden, cl::init(500)); static cl::opt - ClExperimentalTracing("sanitizer-coverage-experimental-tracing", - cl::desc("Experimental basic-block tracing: insert " - "callbacks at every basic block"), + ClTracing("sanitizer-coverage-trace", + cl::desc("Tacing: insert callbacks at every basic" + " function/block/edge"), cl::Hidden, cl::init(false)); static cl::opt @@ -128,7 +127,7 @@ SanitizerCoverageOptions CLOpts = getOptions(ClCoverageLevel); Options.CoverageType = std::max(Options.CoverageType, CLOpts.CoverageType); Options.IndirectCalls |= CLOpts.IndirectCalls; - Options.TraceBB |= ClExperimentalTracing; + Options.Trace |= ClTracing; Options.TraceCmp |= ClExperimentalCMPTracing; Options.Use8bitCounters |= ClUse8bitCounters; return Options; @@ -161,7 +160,7 @@ Function *SanCovFunction; Function *SanCovWithCheckFunction; Function *SanCovIndirCallFunction; - Function *SanCovTraceEnter, *SanCovTraceBB; + Function *SanCovTrace; Function *SanCovTraceCmpFunction; Function *SanCovTraceSwitchFunction; InlineAsm *EmptyAsm; @@ -211,12 +210,9 @@ StringRef(""), StringRef(""), /*hasSideEffects=*/true); - if (Options.TraceBB) { - SanCovTraceEnter = checkSanitizerInterfaceFunction( - M.getOrInsertFunction(kSanCovTraceEnter, VoidTy, Int32PtrTy, nullptr)); - SanCovTraceBB = checkSanitizerInterfaceFunction( - M.getOrInsertFunction(kSanCovTraceBB, VoidTy, Int32PtrTy, nullptr)); - } + if (Options.Trace) + SanCovTrace = checkSanitizerInterfaceFunction( + M.getOrInsertFunction(kSanCovTrace, VoidTy, nullptr)); // At this point we create a dummy array of guards because we don't // know how many elements we will need. @@ -496,11 +492,10 @@ SetNoSanitizeMetadata(SI); } - if (Options.TraceBB) { - // Experimental support for tracing. - // Insert a callback with the same guard variable as used for coverage. + if (Options.Trace) { + // Trace coverage. IRB.SetInsertPoint(&*IP); - IRB.CreateCall(IsEntryBB ? SanCovTraceEnter : SanCovTraceBB, GuardP); + IRB.CreateCall(SanCovTrace); } } Index: lib/sanitizer_common/sanitizer_coverage_libcdep.cc =================================================================== --- lib/sanitizer_common/sanitizer_coverage_libcdep.cc +++ lib/sanitizer_common/sanitizer_coverage_libcdep.cc @@ -91,7 +91,7 @@ void DumpAll(); ALWAYS_INLINE - void TraceBasicBlock(s32 *id); + void TraceBasicBlock(uptr pc); void InitializeGuardArray(s32 *guards); void InitializeGuards(s32 *guards, uptr n, const char *module_name, @@ -154,18 +154,7 @@ atomic_uintptr_t cc_array_index; atomic_uintptr_t cc_array_size; - // Tracing event array, size and current pointer. - // We record all events (basic block entries) in a global buffer of u32 - // values. Each such value is the index in pc_array. - // So far the tracing is highly experimental: - // - not thread-safe; - // - does not support long traces; - // - not tuned for performance. - static const uptr kTrEventArrayMaxSize = FIRST_32_SECOND_64(1 << 22, 1 << 30); - u32 *tr_event_array; - uptr tr_event_array_size; - u32 *tr_event_pointer; - static const uptr kTrPcArrayMaxSize = FIRST_32_SECOND_64(1 << 22, 1 << 27); + uptr tr_size; StaticSpinMutex mu; }; @@ -209,16 +198,6 @@ atomic_store(&cc_array_size, kCcArrayMaxSize, memory_order_relaxed); atomic_store(&cc_array_index, 0, memory_order_relaxed); - // Allocate tr_event_array with a guard page at the end. - tr_event_array = reinterpret_cast(MmapNoReserveOrDie( - sizeof(tr_event_array[0]) * kTrEventArrayMaxSize + GetMmapGranularity(), - "CovInit::tr_event_array")); - MprotectNoAccess( - reinterpret_cast(&tr_event_array[kTrEventArrayMaxSize]), - GetMmapGranularity()); - tr_event_array_size = kTrEventArrayMaxSize; - tr_event_pointer = tr_event_array; - num_8bit_counters = 0; } @@ -241,13 +220,6 @@ UnmapOrDie(cc_array, sizeof(uptr *) * kCcArrayMaxSize); cc_array = nullptr; } - if (tr_event_array) { - UnmapOrDie(tr_event_array, - sizeof(tr_event_array[0]) * kTrEventArrayMaxSize + - GetMmapGranularity()); - tr_event_array = nullptr; - tr_event_pointer = nullptr; - } if (pc_fd != kInvalidFd) { CloseFile(pc_fd); pc_fd = kInvalidFd; @@ -583,53 +555,11 @@ return fd; } -// Dump trace PCs and trace events into two separate files. void CoverageData::DumpTrace() { - uptr max_idx = tr_event_pointer - tr_event_array; - if (!max_idx) return; - auto sym = Symbolizer::GetOrInit(); - if (!sym) + if (tr_size == 0) return; - InternalScopedString out(32 << 20); - for (uptr i = 0, n = size(); i < n; i++) { - const char *module_name = ""; - uptr module_address = 0; - sym->GetModuleNameAndOffsetForPC(UnbundlePc(pc_array[i]), &module_name, - &module_address); - out.append("%s 0x%zx\n", module_name, module_address); - } - InternalScopedString path(kMaxPathLength); - fd_t fd = CovOpenFile(&path, false, "trace-points"); - if (fd == kInvalidFd) return; - WriteToFile(fd, out.data(), out.length()); - CloseFile(fd); - - fd = CovOpenFile(&path, false, "trace-compunits"); - if (fd == kInvalidFd) return; - out.clear(); - for (uptr i = 0; i < comp_unit_name_vec.size(); i++) - out.append("%s\n", comp_unit_name_vec[i].copied_module_name); - WriteToFile(fd, out.data(), out.length()); - CloseFile(fd); - - fd = CovOpenFile(&path, false, "trace-events"); - if (fd == kInvalidFd) return; - uptr bytes_to_write = max_idx * sizeof(tr_event_array[0]); - u8 *event_bytes = reinterpret_cast(tr_event_array); - // The trace file could be huge, and may not be written with a single syscall. - while (bytes_to_write) { - uptr actually_written; - if (WriteToFile(fd, event_bytes, bytes_to_write, &actually_written) && - actually_written <= bytes_to_write) { - bytes_to_write -= actually_written; - event_bytes += actually_written; - } else { - break; - } - } - CloseFile(fd); VReport(1, " CovDump: Trace: %zd PCs written\n", size()); - VReport(1, " CovDump: Trace: %zd Events written\n", max_idx); + VReport(1, " CovDump: Trace: %zd Events written\n", tr_size); } // This function dumps the caller=>callee pairs into a file as a sequence of @@ -673,16 +603,8 @@ } // Record the current PC into the event buffer. -// Every event is a u32 value (index in tr_pc_array_index) so we compute -// it once and then cache in the provided 'cache' storage. -// -// This function will eventually be inlined by the compiler. -void CoverageData::TraceBasicBlock(s32 *id) { - // Will trap here if - // 1. coverage is not enabled at run-time. - // 2. The array tr_event_array is full. - *tr_event_pointer = static_cast(*id - 1); - tr_event_pointer++; +void CoverageData::TraceBasicBlock(uptr pc) { + tr_size++; } void CoverageData::DumpCounters() { @@ -915,12 +837,9 @@ } SANITIZER_INTERFACE_ATTRIBUTE -void __sanitizer_cov_trace_func_enter(s32 *id) { - coverage_data.TraceBasicBlock(id); -} -SANITIZER_INTERFACE_ATTRIBUTE -void __sanitizer_cov_trace_basic_block(s32 *id) { - coverage_data.TraceBasicBlock(id); +void __sanitizer_cov_trace() { + // TBD + coverage_data.TraceBasicBlock(GET_CALLER_PC()); } SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_reset_coverage() { Index: test/Driver/fsanitize-coverage.c =================================================================== --- test/Driver/fsanitize-coverage.c +++ test/Driver/fsanitize-coverage.c @@ -31,14 +31,14 @@ // RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=1 -fno-sanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-SAN-DISABLED // CHECK-SANITIZE-COVERAGE-SAN-DISABLED-NOT: argument unused -// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=edge,indirect-calls,trace-bb,trace-cmp,8bit-counters %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-FEATURES +// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=edge,indirect-calls,trace,trace-cmp,8bit-counters %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-FEATURES // CHECK-SANITIZE-COVERAGE-FEATURES: -fsanitize-coverage-type=3 // CHECK-SANITIZE-COVERAGE-FEATURES: -fsanitize-coverage-indirect-calls -// CHECK-SANITIZE-COVERAGE-FEATURES: -fsanitize-coverage-trace-bb +// CHECK-SANITIZE-COVERAGE-FEATURES: -fsanitize-coverage-trace // CHECK-SANITIZE-COVERAGE-FEATURES: -fsanitize-coverage-trace-cmp // CHECK-SANITIZE-COVERAGE-FEATURES: -fsanitize-coverage-8bit-counters -// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=func,edge,indirect-calls,trace-bb,trace-cmp -fno-sanitize-coverage=edge,indirect-calls,trace-bb %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-MASK +// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=func,edge,indirect-calls,trace,trace-cmp -fno-sanitize-coverage=edge,indirect-calls,trace %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-MASK // CHECK-MASK: -fsanitize-coverage-type=1 // CHECK-MASK: -fsanitize-coverage-trace-cmp // CHECK-MASK-NOT: -fsanitize-coverage- @@ -49,8 +49,11 @@ // RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=func -fsanitize-coverage=edge %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-INCOMPATIBLE // CHECK-INCOMPATIBLE: error: invalid argument '-fsanitize-coverage=func' not allowed with '-fsanitize-coverage=edge' +// Driver must enable edge coverage by default. // RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=8bit-counters %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-MISSING-TYPE -// CHECK-MISSING-TYPE: error: invalid argument '-fsanitize-coverage=8bit-counters' only allowed with '-fsanitize-coverage=(func|bb|edge)' +// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=trace %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-MISSING-TYPE +// CHECK-MISSING-TYPE-NOT: error +// CHECK-MISSING-TYPE-NOT: fsanitize // RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=trace-cmp,indirect-calls %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-TYPE-NECESSARY // CHECK-NO-TYPE-NECESSARY-NOT: error: Index: test/Instrumentation/SanitizerCoverage/tracing.ll =================================================================== --- test/Instrumentation/SanitizerCoverage/tracing.ll +++ test/Instrumentation/SanitizerCoverage/tracing.ll @@ -1,6 +1,6 @@ ; Test -sanitizer-coverage-experimental-tracing -; RUN: opt < %s -sancov -sanitizer-coverage-level=2 -sanitizer-coverage-experimental-tracing -S | FileCheck %s --check-prefix=CHECK1 -; RUN: opt < %s -sancov -sanitizer-coverage-level=3 -sanitizer-coverage-experimental-tracing -S | FileCheck %s --check-prefix=CHECK3 +; RUN: opt < %s -sancov -sanitizer-coverage-level=2 -sanitizer-coverage-trace -S | FileCheck %s --check-prefix=CHECK1 +; RUN: opt < %s -sancov -sanitizer-coverage-level=3 -sanitizer-coverage-trace -S | FileCheck %s --check-prefix=CHECK3 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" @@ -18,16 +18,16 @@ } ; CHECK1-LABEL: define void @foo -; CHECK1: call void @__sanitizer_cov_trace_func_enter -; CHECK1: call void @__sanitizer_cov_trace_basic_block -; CHECK1: call void @__sanitizer_cov_trace_basic_block -; CHECK1-NOT: call void @__sanitizer_cov_trace_basic_block +; CHECK1: call void @__sanitizer_cov_trace +; CHECK1: call void @__sanitizer_cov_trace +; CHECK1: call void @__sanitizer_cov_trace +; CHECK1-NOT: call void @__sanitizer_cov_trace ; CHECK1: ret void ; CHECK3-LABEL: define void @foo -; CHECK3: call void @__sanitizer_cov_trace_func_enter -; CHECK3: call void @__sanitizer_cov_trace_basic_block -; CHECK3: call void @__sanitizer_cov_trace_basic_block -; CHECK3: call void @__sanitizer_cov_trace_basic_block -; CHECK3-NOT: call void @__sanitizer_cov_trace_basic_block +; CHECK3: call void @__sanitizer_cov_trace +; CHECK3: call void @__sanitizer_cov_trace +; CHECK3: call void @__sanitizer_cov_trace +; CHECK3: call void @__sanitizer_cov_trace +; CHECK3-NOT: call void @__sanitizer_cov_trace ; CHECK3: ret void Index: test/asan/TestCases/coverage-tracing.cc =================================================================== --- test/asan/TestCases/coverage-tracing.cc +++ test/asan/TestCases/coverage-tracing.cc @@ -1,28 +1,11 @@ -// Test -fsanitize-coverage=trace-bb +// Test -fsanitize-coverage=trace // -// RUN: %clangxx_asan -O1 -fsanitize-coverage=func,trace-bb %s -o %t -// RUN: rm -rf %T/coverage-tracing -// RUN: mkdir %T/coverage-tracing -// RUN: cd %T/coverage-tracing -// RUN: A=x; %env_asan_opts=coverage=1:verbosity=1 %run %t $A 1 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK1; mv trace-points.*.sancov $A.points -// RUN: A=f; %env_asan_opts=coverage=1:verbosity=1 %run %t $A 1 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK2; mv trace-points.*.sancov $A.points -// RUN: A=b; %env_asan_opts=coverage=1:verbosity=1 %run %t $A 1 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK2; mv trace-points.*.sancov $A.points -// RUN: A=bf; %env_asan_opts=coverage=1:verbosity=1 %run %t $A 1 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK3; mv trace-points.*.sancov $A.points -// RUN: A=fb; %env_asan_opts=coverage=1:verbosity=1 %run %t $A 1 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK3; mv trace-points.*.sancov $A.points -// RUN: A=ffb; %env_asan_opts=coverage=1:verbosity=1 %run %t $A 1 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK4; mv trace-points.*.sancov $A.points -// RUN: A=fff; %env_asan_opts=coverage=1:verbosity=1 %run %t $A 1 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK4; mv trace-points.*.sancov $A.points -// RUN: A=bbf; %env_asan_opts=coverage=1:verbosity=1 %run %t $A 100 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK301; mv trace-points.*.sancov $A.points -// RUN: diff f.points fff.points -// RUN: diff bf.points fb.points -// RUN: diff bf.points ffb.points -// RUN: diff bf.points bbf.points -// RUN: not diff x.points f.points -// RUN: not diff x.points b.points -// RUN: not diff x.points bf.points -// RUN: not diff f.points b.points -// RUN: not diff f.points bf.points -// RUN: not diff b.points bf.points -// RUN: rm -rf %T/coverage-tracing +// RUN: %clangxx_asan -O1 -fsanitize-coverage=func,trace %s -o %t +// RUN: A=x; %env_asan_opts=coverage=1:verbosity=1 %run %t $A 1 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK1 +// RUN: A=f; %env_asan_opts=coverage=1:verbosity=1 %run %t $A 1 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK2 +// RUN: A=fb; %env_asan_opts=coverage=1:verbosity=1 %run %t $A 1 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK3 +// RUN: A=fff; %env_asan_opts=coverage=1:verbosity=1 %run %t $A 1 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK4 +// RUN: A=bbf; %env_asan_opts=coverage=1:verbosity=1 %run %t $A 100 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK301 // // REQUIRES: asan-64-bits // UNSUPPORTED: android