[compiler-rt] r224789 - [asan] change the coverage collection scheme so that we can easily emit coverage for the entire process as a single bit set, and if coverage_bitset=1 actually emit that bitset
Evgeniy Stepanov
eugeni.stepanov at gmail.com
Wed Dec 24 08:34:39 PST 2014
Btw, this is an ABI change, how about bumping __asan_init_v?
On Wed, Dec 24, 2014 at 4:14 PM, Evgeniy Stepanov
<eugeni.stepanov at gmail.com> wrote:
> On Wed, Dec 24, 2014 at 1:32 AM, Kostya Serebryany <kcc at google.com> wrote:
>> Author: kcc
>> Date: Tue Dec 23 16:32:17 2014
>> New Revision: 224789
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=224789&view=rev
>> Log:
>> [asan] change the coverage collection scheme so that we can easily emit coverage for the entire process as a single bit set, and if coverage_bitset=1 actually emit that bitset
>>
>> Modified:
>> compiler-rt/trunk/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
>> compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.cc
>> compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.h
>> compiler-rt/trunk/lib/sanitizer_common/sanitizer_internal_defs.h
>> compiler-rt/trunk/test/asan/TestCases/Linux/coverage-fork.cc
>> compiler-rt/trunk/test/asan/TestCases/Linux/coverage-levels.cc
>>
>> Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
>> URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_coverage_libcdep.cc?rev=224789&r1=224788&r2=224789&view=diff
>> ==============================================================================
>> --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_coverage_libcdep.cc (original)
>> +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_coverage_libcdep.cc Tue Dec 23 16:32:17 2014
>> @@ -12,14 +12,16 @@
>> //
>> // Compiler instrumentation:
>> // For every interesting basic block the compiler injects the following code:
>> -// if (Guard) {
>> +// if (Guard < 0) {
>> // __sanitizer_cov(&Guard);
>> // }
>> +// At the module start up time __sanitizer_cov_module_init sets the guards
>> +// to consecutive negative numbers (-1, -2, -3, ...).
>> // It's fine to call __sanitizer_cov more than once for a given block.
>> //
>> // Run-time:
>> // - __sanitizer_cov(): record that we've executed the PC (GET_CALLER_PC).
>> -// and atomically set Guard to 1.
>> +// and atomically set Guard to -Guard.
>> // - __sanitizer_cov_dump: dump the coverage data to disk.
>> // For every module of the current process that has coverage data
>> // this will create a file module_name.PID.sancov. The file format is simple:
>> @@ -65,14 +67,16 @@ class CoverageData {
>> void BeforeFork();
>> void AfterFork(int child_pid);
>> void Extend(uptr npcs);
>> - void Add(uptr pc, u8 *guard);
>> + void Add(uptr pc, u32 *guard);
>> void IndirCall(uptr caller, uptr callee, uptr callee_cache[],
>> uptr cache_size);
>> void DumpCallerCalleePairs();
>> void DumpTrace();
>>
>> ALWAYS_INLINE
>> - void TraceBasicaBlock(uptr *cache);
>> + void TraceBasicBlock(uptr *cache);
>> +
>> + void InitializeGuards(s32 **guards, uptr n);
>>
>> uptr *data();
>> uptr size();
>> @@ -149,12 +153,11 @@ void CoverageData::Init() {
>> pc_array = reinterpret_cast<uptr *>(
>> MmapNoReserveOrDie(sizeof(uptr) * kPcArrayMaxSize, "CovInit"));
>> pc_fd = kInvalidFd;
>> + atomic_store(&pc_array_index, 0, memory_order_relaxed);
>> if (common_flags()->coverage_direct) {
>> atomic_store(&pc_array_size, 0, memory_order_relaxed);
>> - atomic_store(&pc_array_index, 0, memory_order_relaxed);
>> } else {
>> atomic_store(&pc_array_size, kPcArrayMaxSize, memory_order_relaxed);
>> - atomic_store(&pc_array_index, 0, memory_order_relaxed);
>> }
>>
>> cc_array = reinterpret_cast<uptr **>(MmapNoReserveOrDie(
>> @@ -230,15 +233,27 @@ void CoverageData::Extend(uptr npcs) {
>> atomic_store(&pc_array_size, size, memory_order_release);
>> }
>>
>> +void CoverageData::InitializeGuards(s32 **guards, uptr n) {
>> + for (uptr i = 0; i < n; i++) {
>> + uptr idx = atomic_fetch_add(&pc_array_index, 1, memory_order_relaxed);
>> + *guards[i] = -static_cast<s32>(idx + 1);
>> + }
>> +}
>> +
>> // Atomically add the pc to the vector. The atomically set the guard to 1.
>> // If the function is called more than once for a given PC it will
>> // be inserted multiple times, which is fine.
>
> This comment is no longer true, is it?
>
>> -void CoverageData::Add(uptr pc, u8 *guard) {
>> - // Set the guard.
>> - atomic_uint8_t *atomic_guard = reinterpret_cast<atomic_uint8_t*>(guard);
>> - atomic_store(atomic_guard, 1, memory_order_relaxed);
>> +void CoverageData::Add(uptr pc, u32 *guard) {
>> + atomic_uint32_t *atomic_guard = reinterpret_cast<atomic_uint32_t*>(guard);
>> + s32 guard_value = atomic_load(atomic_guard, memory_order_relaxed);
>> + if (guard_value >= 0) return;
>> +
>> + atomic_store(atomic_guard, -guard_value, memory_order_relaxed);
>> if (!pc_array) return;
>> - uptr idx = atomic_fetch_add(&pc_array_index, 1, memory_order_relaxed);
>> +
>> + uptr idx = -guard_value - 1;
>> + if (idx >= atomic_load(&pc_array_index, memory_order_acquire))
>> + return; // May happen after fork when pc_array_index becomes 0.
>> CHECK_LT(idx * sizeof(uptr),
>> atomic_load(&pc_array_size, memory_order_acquire));
>> pc_array[idx] = pc;
>> @@ -338,18 +353,20 @@ static void CovWritePacked(int pid, cons
>> // If packed = true and name == 0: <pid>.<sancov>.<packed>.
>> // If packed = true and name != 0: <name>.<sancov>.<packed> (name is
>> // user-supplied).
>> -static int CovOpenFile(bool packed, const char* name) {
>> +static int CovOpenFile(bool packed, const char *name,
>> + const char *extension = "sancov") {
>> InternalScopedString path(kMaxPathLength);
>> if (!packed) {
>> CHECK(name);
>> - path.append("%s/%s.%zd.sancov", common_flags()->coverage_dir, name,
>> - internal_getpid());
>> + path.append("%s/%s.%zd.%s", common_flags()->coverage_dir, name,
>> + internal_getpid(), extension);
>> } else {
>> if (!name)
>> - path.append("%s/%zd.sancov.packed", common_flags()->coverage_dir,
>> - internal_getpid());
>> + path.append("%s/%zd.%s.packed", common_flags()->coverage_dir,
>> + internal_getpid(), extension);
>> else
>> - path.append("%s/%s.sancov.packed", common_flags()->coverage_dir, name);
>> + path.append("%s/%s.%s.packed", common_flags()->coverage_dir, name,
>> + extension);
>> }
>> uptr fd = OpenFile(path.data(), true);
>> if (internal_iserror(fd)) {
>> @@ -434,7 +451,7 @@ void CoverageData::DumpCallerCalleePairs
>> // 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.
>> -void CoverageData::TraceBasicaBlock(uptr *cache) {
>> +void CoverageData::TraceBasicBlock(uptr *cache) {
>> CHECK(common_flags()->coverage);
>> uptr idx = *cache;
>> if (!idx) {
>> @@ -450,12 +467,33 @@ void CoverageData::TraceBasicaBlock(uptr
>> tr_event_array_index++;
>> }
>>
>> +static void CovDumpAsBitSet() {
>> + if (!common_flags()->coverage_bitset) return;
>> + if (!coverage_data.size()) return;
>> + int fd = CovOpenFile(/* packed */false, "combined", "bitset-sancov");
>> + if (fd < 0) return;
>> + uptr n = coverage_data.size();
>> + uptr n_set_bits = 0;
>> + InternalScopedBuffer<char> out(n);
>> + for (uptr i = 0; i < n; i++) {
>> + uptr pc = coverage_data.data()[i];
>> + out[i] = pc ? '1' : '0';
>> + if (pc)
>> + n_set_bits++;
>> + }
>> + internal_write(fd, out.data(), n);
>> + internal_close(fd);
>> + VReport(1, " CovDump: bitset of %zd bits written, %zd bits are set\n", n,
>> + n_set_bits);
>> +}
>> +
>> // Dump the coverage on disk.
>> static void CovDump() {
>> if (!common_flags()->coverage || common_flags()->coverage_direct) return;
>> #if !SANITIZER_WINDOWS
>> if (atomic_fetch_add(&dump_once_guard, 1, memory_order_relaxed))
>> return;
>> + CovDumpAsBitSet();
>> uptr size = coverage_data.size();
>> InternalMmapVector<u32> offsets(size);
>> uptr *vb = coverage_data.data();
>> @@ -539,7 +577,7 @@ void CovAfterFork(int child_pid) {
>> } // namespace __sanitizer
>>
>> extern "C" {
>> -SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov(u8 *guard) {
>> +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov(u32 *guard) {
>> coverage_data.Add(StackTrace::GetPreviousInstructionPc(GET_CALLER_PC()),
>> guard);
>> }
>> @@ -552,8 +590,11 @@ SANITIZER_INTERFACE_ATTRIBUTE void __san
>> SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_init() {
>> coverage_data.Init();
>> }
>> -SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_module_init(uptr npcs) {
>> - if (!common_flags()->coverage || !common_flags()->coverage_direct) return;
>> +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_module_init(s32 **guards,
>> + uptr npcs) {
>> + coverage_data.InitializeGuards(guards, npcs);
>> + if (!common_flags()->coverage || !common_flags()->coverage_direct)
>> + return;
>> if (SANITIZER_ANDROID) {
>> // dlopen/dlclose interceptors do not work on Android, so we rely on
>> // Extend() calls to update .sancov.map.
>> @@ -572,10 +613,10 @@ uptr __sanitizer_get_total_unique_covera
>>
>> SANITIZER_INTERFACE_ATTRIBUTE
>> void __sanitizer_cov_trace_func_enter(uptr *cache) {
>> - coverage_data.TraceBasicaBlock(cache);
>> + coverage_data.TraceBasicBlock(cache);
>> }
>> SANITIZER_INTERFACE_ATTRIBUTE
>> void __sanitizer_cov_trace_basic_block(uptr *cache) {
>> - coverage_data.TraceBasicaBlock(cache);
>> + coverage_data.TraceBasicBlock(cache);
>> }
>> } // extern "C"
>>
>> Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.cc
>> URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.cc?rev=224789&r1=224788&r2=224789&view=diff
>> ==============================================================================
>> --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.cc (original)
>> +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.cc Tue Dec 23 16:32:17 2014
>> @@ -63,6 +63,7 @@ void CommonFlags::SetDefaults() {
>> legacy_pthread_cond = false;
>> intercept_tls_get_addr = false;
>> coverage = false;
>> + coverage_bitset = false;
>> coverage_direct = SANITIZER_ANDROID;
>> coverage_dir = ".";
>> full_address_space = false;
>> @@ -150,6 +151,9 @@ void CommonFlags::ParseFromString(const
>> ParseFlag(str, &coverage, "coverage",
>> "If set, coverage information will be dumped at program shutdown (if the "
>> "coverage instrumentation was enabled at compile time).");
>> + ParseFlag(str, &coverage_bitset, "coverage_bitset",
>> + "If set (and if 'coverage' is set too), the coverage information "
>> + "will also be dumped as a bitset to a separate file.");
>> ParseFlag(str, &coverage_direct, "coverage_direct",
>> "If set, coverage information will be dumped directly to a memory "
>> "mapped file. This way data is not lost even if the process is "
>>
>> Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.h
>> URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.h?rev=224789&r1=224788&r2=224789&view=diff
>> ==============================================================================
>> --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.h (original)
>> +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.h Tue Dec 23 16:32:17 2014
>> @@ -56,6 +56,7 @@ struct CommonFlags {
>> uptr mmap_limit_mb;
>> uptr hard_rss_limit_mb;
>> bool coverage;
>> + bool coverage_bitset;
>> bool coverage_direct;
>> const char *coverage_dir;
>> bool full_address_space;
>>
>> Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_internal_defs.h
>> URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_internal_defs.h?rev=224789&r1=224788&r2=224789&view=diff
>> ==============================================================================
>> --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_internal_defs.h (original)
>> +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_internal_defs.h Tue Dec 23 16:32:17 2014
>> @@ -120,7 +120,7 @@ extern "C" {
>>
>> SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump();
>> SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_init();
>> - SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov(__sanitizer::u8 *guard);
>> + SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov(__sanitizer::u32 *guard);
>> SANITIZER_INTERFACE_ATTRIBUTE
>> void __sanitizer_annotate_contiguous_container(const void *beg,
>> const void *end,
>>
>> Modified: compiler-rt/trunk/test/asan/TestCases/Linux/coverage-fork.cc
>> URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/Linux/coverage-fork.cc?rev=224789&r1=224788&r2=224789&view=diff
>> ==============================================================================
>> --- compiler-rt/trunk/test/asan/TestCases/Linux/coverage-fork.cc (original)
>> +++ compiler-rt/trunk/test/asan/TestCases/Linux/coverage-fork.cc Tue Dec 23 16:32:17 2014
>> @@ -33,6 +33,7 @@ int main(int argc, char **argv) {
>> }
>>
>> // CHECK-DAG: Child PID: [[ChildPID:[0-9]+]]
>> -// CHECK-DAG: [[ChildPID]].sancov: 1 PCs written
>> +// Coverage in the child (after fork,before exec) is not expected to work.
>> +// (disabled): [[ChildPID]].sancov: 1 PCs written
>> // CHECK-DAG: Parent PID: [[ParentPID:[0-9]+]]
>> // CHECK-DAG: [[ParentPID]].sancov: 3 PCs written
>>
>> Modified: compiler-rt/trunk/test/asan/TestCases/Linux/coverage-levels.cc
>> URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/Linux/coverage-levels.cc?rev=224789&r1=224788&r2=224789&view=diff
>> ==============================================================================
>> --- compiler-rt/trunk/test/asan/TestCases/Linux/coverage-levels.cc (original)
>> +++ compiler-rt/trunk/test/asan/TestCases/Linux/coverage-levels.cc Tue Dec 23 16:32:17 2014
>> @@ -1,11 +1,14 @@
>> // Test various levels of coverage
>> //
>> // RUN: %clangxx_asan -O1 -fsanitize-coverage=1 %s -o %t
>> -// RUN: ASAN_OPTIONS=coverage=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1
>> +// RUN: ASAN_OPTIONS=coverage=1:coverage_bitset=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1
>> // RUN: %clangxx_asan -O1 -fsanitize-coverage=2 %s -o %t
>> -// RUN: ASAN_OPTIONS=coverage=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2
>> +// RUN: ASAN_OPTIONS=coverage=1:coverage_bitset=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2
>> // RUN: %clangxx_asan -O1 -fsanitize-coverage=3 %s -o %t
>> -// RUN: ASAN_OPTIONS=coverage=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3
>> +// RUN: ASAN_OPTIONS=coverage=1:coverage_bitset=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3
>> +
>> +// RUN: ASAN_OPTIONS=coverage=1:coverage_bitset=0:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3_NOBITSET
>> +// RUN: ASAN_OPTIONS=coverage=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3_NOBITSET
>> //
>> // REQUIRES: asan-64-bits
>>
>> @@ -15,6 +18,10 @@ int main(int argc, char **argv) {
>> sink = 0;
>> }
>>
>> +// CHECK1: CovDump: bitset of 1 bits written, 1 bits are set
>> // CHECK1: 1 PCs written
>> +// CHECK2: CovDump: bitset of 3 bits written, 2 bits are set
>> // CHECK2: 2 PCs written
>> +// CHECK3: CovDump: bitset of 4 bits written, 3 bits are set
>> // CHECK3: 3 PCs written
>> +// CHECK3_NOBITSET-NOT: bitset of
>>
>>
>> _______________________________________________
>> llvm-commits mailing list
>> llvm-commits at cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
More information about the llvm-commits
mailing list