[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

Kostya Serebryany kcc at google.com
Tue Dec 30 11:33:13 PST 2014


On Wed, Dec 24, 2014 at 5:14 AM, 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?
>

Right, thanks!
Updated as part of r224999.

>> Btw, this is an ABI change, how about bumping __asan_init_v?
I don't want to treat the coverage part as a fixed API just yet.
The feature is still *experimental* and we don't have too many users
(most, of not all, existing users of -fsanitize-coverage build all code
from scratch).
In future -- yes, such changes will need an API version bump.


>
> > -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
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20141230/3e563112/attachment.html>


More information about the llvm-commits mailing list