From 04897dcc3d2176460b30607ad59bbc13f02efb70 Mon Sep 17 00:00:00 2001 From: Mike Aizatsky Date: Fri, 5 Aug 2016 20:09:42 +0000 Subject: [PATCH] [sanitizers] trace buffer API to use user-allocated buffer. Subscribers: kubabrecka Differential Revision: https://reviews.llvm.org/D23186 llvm-svn: 277858 --- compiler-rt/include/sanitizer/coverage_interface.h | 16 +++++---- compiler-rt/lib/asan/asan_win_dll_thunk.cc | 3 +- .../sanitizer_common/sanitizer_coverage_libcdep.cc | 27 +++++++++------ .../lib/sanitizer_common/sanitizer_flags.inc | 3 -- .../test/asan/TestCases/coverage-pc-buffer.cc | 40 ++++++++++------------ 5 files changed, 45 insertions(+), 44 deletions(-) diff --git a/compiler-rt/include/sanitizer/coverage_interface.h b/compiler-rt/include/sanitizer/coverage_interface.h index 2dcc09f..72ac843 100644 --- a/compiler-rt/include/sanitizer/coverage_interface.h +++ b/compiler-rt/include/sanitizer/coverage_interface.h @@ -41,13 +41,6 @@ extern "C" { // Some of the entries in *data will be zero. uintptr_t __sanitizer_get_coverage_guards(uintptr_t **data); - // Set *data to the growing buffer with covered PCs and return the size - // of the buffer. The entries are never zero. - // When only unique pcs are collected, the size is equal to - // __sanitizer_get_total_unique_coverage. - // WARNING: EXPERIMENTAL API. - uintptr_t __sanitizer_get_coverage_pc_buffer(uintptr_t **data); - // The coverage instrumentation may optionally provide imprecise counters. // Rather than exposing the counter values to the user we instead map // the counters to a bitset. @@ -65,6 +58,15 @@ extern "C" { // __sanitizer_get_number_of_counters bytes long and 8-aligned. uintptr_t __sanitizer_update_counter_bitset_and_clear_counters(uint8_t *bitset); + + // EXPERIMENTAL API + // Set allocated buffer to record new coverage PCs as they are executed. + // Buffer length is specified in uptrs. + void __sanitizer_set_coverage_pc_buffer(uintptr_t *buffer, uintptr_t length); + // Number of pcs recorded in the buffer. + // Reset by __sanitizer_reset_coverage(); + uintptr_t __sanitizer_get_coverage_pc_buffer_pos(); + #ifdef __cplusplus } // extern "C" #endif diff --git a/compiler-rt/lib/asan/asan_win_dll_thunk.cc b/compiler-rt/lib/asan/asan_win_dll_thunk.cc index c8f4867..09c3b20 100644 --- a/compiler-rt/lib/asan/asan_win_dll_thunk.cc +++ b/compiler-rt/lib/asan/asan_win_dll_thunk.cc @@ -320,7 +320,7 @@ INTERFACE_FUNCTION(__sanitizer_cov_trace_switch) INTERFACE_FUNCTION(__sanitizer_cov_with_check) INTERFACE_FUNCTION(__sanitizer_get_allocated_size) INTERFACE_FUNCTION(__sanitizer_get_coverage_guards) -INTERFACE_FUNCTION(__sanitizer_get_coverage_pc_buffer) +INTERFACE_FUNCTION(__sanitizer_get_coverage_pc_buffer_pos) INTERFACE_FUNCTION(__sanitizer_get_current_allocated_bytes) INTERFACE_FUNCTION(__sanitizer_get_estimated_allocated_size) INTERFACE_FUNCTION(__sanitizer_get_free_bytes) @@ -338,6 +338,7 @@ INTERFACE_FUNCTION(__sanitizer_reset_coverage) INTERFACE_FUNCTION(__sanitizer_get_number_of_counters) INTERFACE_FUNCTION(__sanitizer_update_counter_bitset_and_clear_counters) INTERFACE_FUNCTION(__sanitizer_sandbox_on_notify) +INTERFACE_FUNCTION(__sanitizer_set_coverage_pc_buffer) INTERFACE_FUNCTION(__sanitizer_set_death_callback) INTERFACE_FUNCTION(__sanitizer_set_report_path) INTERFACE_FUNCTION(__sanitizer_set_report_fd) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep.cc b/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep.cc index 0087266..2c69788 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep.cc @@ -110,7 +110,8 @@ class CoverageData { uptr *data(); uptr size() const; - uptr *buffer() const { return pc_buffer; } + + void SetPcBuffer(uptr* data, uptr length); private: struct NamedPcRange { @@ -143,6 +144,7 @@ class CoverageData { fd_t pc_fd; uptr *pc_buffer; + uptr pc_buffer_len; // Vector of coverage guard arrays, protected by mu. InternalMmapVectorNoCtor guard_array_vec; @@ -216,9 +218,7 @@ void CoverageData::Enable() { } pc_buffer = nullptr; - if (common_flags()->coverage_pc_buffer) - pc_buffer = reinterpret_cast(MmapNoReserveOrDie( - sizeof(uptr) * kPcArrayMaxSize, "CovInit::pc_buffer")); + pc_buffer_len = 0; cc_array = reinterpret_cast(MmapNoReserveOrDie( sizeof(uptr *) * kCcArrayMaxSize, "CovInit::cc_array")); @@ -257,10 +257,6 @@ void CoverageData::Disable() { UnmapOrDie(cc_array, sizeof(uptr *) * kCcArrayMaxSize); cc_array = nullptr; } - if (pc_buffer) { - UnmapOrDie(pc_buffer, sizeof(uptr) * kPcArrayMaxSize); - pc_buffer = nullptr; - } if (tr_event_array) { UnmapOrDie(tr_event_array, sizeof(tr_event_array[0]) * kTrEventArrayMaxSize + @@ -429,7 +425,7 @@ void CoverageData::Add(uptr pc, u32 *guard) { atomic_load(&pc_array_size, memory_order_acquire)); uptr counter = atomic_fetch_add(&coverage_counter, 1, memory_order_relaxed); pc_array[idx] = BundlePcAndCounter(pc, counter); - if (pc_buffer) pc_buffer[counter] = pc; + if (pc_buffer && counter < pc_buffer_len) pc_buffer[counter] = pc; } // Registers a pair caller=>callee. @@ -883,6 +879,11 @@ void CoverageData::DumpAll() { DumpCallerCalleePairs(); } +void CoverageData::SetPcBuffer(uptr* data, uptr length) { + pc_buffer = data; + pc_buffer_len = length; +} + void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args) { if (!args) return; if (!coverage_enabled) return; @@ -1018,8 +1019,12 @@ uptr __sanitizer_get_coverage_guards(uptr **data) { } SANITIZER_INTERFACE_ATTRIBUTE -uptr __sanitizer_get_coverage_pc_buffer(uptr **data) { - *data = coverage_data.buffer(); +void __sanitizer_set_coverage_pc_buffer(uptr *data, uptr length) { + coverage_data.SetPcBuffer(data, length); +} + +SANITIZER_INTERFACE_ATTRIBUTE +uptr __sanitizer_get_coverage_pc_buffer_pos() { return __sanitizer_get_total_unique_coverage(); } diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc b/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc index 450436a..8c9bc0e 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc @@ -144,9 +144,6 @@ COMMON_FLAG(bool, coverage_direct, SANITIZER_ANDROID, COMMON_FLAG(const char *, coverage_dir, ".", "Target directory for coverage dumps. Defaults to the current " "directory.") -COMMON_FLAG(bool, coverage_pc_buffer, true, - "If set (and if 'coverage' is set too), the pcs would be collected " - "in a buffer.") COMMON_FLAG(bool, full_address_space, false, "Sanitize complete address space; " "by default kernel area on 32-bit platforms will not be sanitized") diff --git a/compiler-rt/test/asan/TestCases/coverage-pc-buffer.cc b/compiler-rt/test/asan/TestCases/coverage-pc-buffer.cc index 5895a5c..0e0434a 100644 --- a/compiler-rt/test/asan/TestCases/coverage-pc-buffer.cc +++ b/compiler-rt/test/asan/TestCases/coverage-pc-buffer.cc @@ -1,11 +1,13 @@ // Test __sanitizer_coverage_pc_buffer(). -// RUN: %clangxx_asan -fsanitize-coverage=edge %s -o %t && %run %t +// RUN: %clangxx_asan -fsanitize-coverage=edge -std=c++11 %s -O3 -o %t && %run %t // UNSUPPORTED: android #include +#include #include +#include #include static volatile int sink; @@ -19,47 +21,41 @@ void assertNotZeroPcs(uintptr_t *buf, uintptr_t size) { } int main() { + uintptr_t buf_size = 1 << 20; + std::unique_ptr buf(new uintptr_t[buf_size]); + __sanitizer_set_coverage_pc_buffer(buf.get(), buf_size); + { - uintptr_t *buf = NULL; - uintptr_t sz = __sanitizer_get_coverage_pc_buffer(&buf); - assertNotZeroPcs(buf, sz); + uintptr_t sz = __sanitizer_get_coverage_pc_buffer_pos(); + assertNotZeroPcs(buf.get(), sz); assert(sz); } { - uintptr_t *buf = NULL; - uintptr_t sz = __sanitizer_get_coverage_pc_buffer(&buf); + uintptr_t sz = __sanitizer_get_coverage_pc_buffer_pos(); // call functions for the first time. foo(); bar(); - uintptr_t *buf1 = NULL; - uintptr_t sz1 = __sanitizer_get_coverage_pc_buffer(&buf1); - assertNotZeroPcs(buf1, sz1); - assert(buf1 == buf); + uintptr_t sz1 = __sanitizer_get_coverage_pc_buffer_pos(); + assertNotZeroPcs(buf.get(), sz1); assert(sz1 > sz); } { - uintptr_t *buf = NULL; - uintptr_t sz = __sanitizer_get_coverage_pc_buffer(&buf); + uintptr_t sz = __sanitizer_get_coverage_pc_buffer_pos(); // second call shouldn't increase coverage. bar(); - uintptr_t *buf1 = NULL; - uintptr_t sz1 = __sanitizer_get_coverage_pc_buffer(&buf1); - assertNotZeroPcs(buf1, sz1); - assert(buf1 == buf); + uintptr_t sz1 = __sanitizer_get_coverage_pc_buffer_pos(); assert(sz1 == sz); + assertNotZeroPcs(buf.get(), sz1); } { - uintptr_t *buf = NULL; - uintptr_t sz = __sanitizer_get_coverage_pc_buffer(&buf); + uintptr_t sz = __sanitizer_get_coverage_pc_buffer_pos(); // reset coverage to 0. __sanitizer_reset_coverage(); - uintptr_t *buf1 = NULL; - uintptr_t sz1 = __sanitizer_get_coverage_pc_buffer(&buf1); - assertNotZeroPcs(buf1, sz1); - assert(buf1 == buf); + uintptr_t sz1 = __sanitizer_get_coverage_pc_buffer_pos(); + assertNotZeroPcs(buf.get(), sz1); assert(sz1 < sz); } } -- 2.7.4