[sanitizer-coverage] remove run-time support for -fsanitize-coverage=indirect-calls

llvm-svn: 300775
This commit is contained in:
Kostya Serebryany 2017-04-19 22:24:03 +00:00
parent 3cc8da3248
commit d32bc3ee38
6 changed files with 0 additions and 230 deletions

View File

@ -35,8 +35,6 @@ extern "C" {
// Get the number of unique covered blocks (or edges).
// This can be useful for coverage-directed in-process fuzzers.
uintptr_t __sanitizer_get_total_unique_coverage();
// Get the number of unique indirect caller-callee pairs.
uintptr_t __sanitizer_get_total_unique_caller_callee_pairs();
// Reset the basic-block (edge) coverage to the initial state.
// Useful for in-process fuzzing to start collecting coverage from scratch.

View File

@ -285,10 +285,6 @@ fun:__sanitizer_cov_module_init=uninstrumented
fun:__sanitizer_cov_module_init=discard
fun:__sanitizer_cov_with_check=uninstrumented
fun:__sanitizer_cov_with_check=discard
fun:__sanitizer_cov_indir_call16=uninstrumented
fun:__sanitizer_cov_indir_call16=discard
fun:__sanitizer_cov_indir_call16=uninstrumented
fun:__sanitizer_cov_indir_call16=discard
fun:__sanitizer_reset_coverage=uninstrumented
fun:__sanitizer_reset_coverage=discard
fun:__sanitizer_set_death_callback=uninstrumented

View File

@ -10,14 +10,12 @@
//===----------------------------------------------------------------------===//
INTERFACE_FUNCTION(__sanitizer_cov)
INTERFACE_FUNCTION(__sanitizer_cov_dump)
INTERFACE_FUNCTION(__sanitizer_cov_indir_call16)
INTERFACE_FUNCTION(__sanitizer_cov_init)
INTERFACE_FUNCTION(__sanitizer_cov_module_init)
INTERFACE_FUNCTION(__sanitizer_cov_with_check)
INTERFACE_FUNCTION(__sanitizer_dump_coverage)
INTERFACE_FUNCTION(__sanitizer_dump_trace_pc_guard_coverage)
INTERFACE_FUNCTION(__sanitizer_get_coverage_guards)
INTERFACE_FUNCTION(__sanitizer_get_total_unique_caller_callee_pairs)
INTERFACE_FUNCTION(__sanitizer_get_total_unique_coverage)
INTERFACE_FUNCTION(__sanitizer_maybe_open_cov_file)
INTERFACE_FUNCTION(__sanitizer_reset_coverage)

View File

@ -57,11 +57,9 @@ static const u64 kMagic = SANITIZER_WORDSIZE == 64 ? kMagic64 : kMagic32;
static atomic_uint32_t dump_once_guard; // Ensure that CovDump runs only once.
static atomic_uintptr_t coverage_counter;
static atomic_uintptr_t caller_callee_counter;
static void ResetGlobalCounters() {
return atomic_store(&coverage_counter, 0, memory_order_relaxed);
return atomic_store(&caller_callee_counter, 0, memory_order_relaxed);
}
// pc_array is the array containing the covered PCs.
@ -90,9 +88,6 @@ class CoverageData {
void AfterFork(int child_pid);
void Extend(uptr npcs);
void Add(uptr pc, u32 *guard);
void IndirCall(uptr caller, uptr callee, uptr callee_cache[],
uptr cache_size);
void DumpCallerCalleePairs();
void DumpAsBitSet();
void DumpOffsets();
void DumpAll();
@ -142,12 +137,6 @@ class CoverageData {
InternalMmapVectorNoCtor<NamedPcRange> comp_unit_name_vec;
InternalMmapVectorNoCtor<NamedPcRange> module_name_vec;
// Caller-Callee (cc) array, size and current index.
static const uptr kCcArrayMaxSize = FIRST_32_SECOND_64(1 << 18, 1 << 24);
uptr **cc_array;
atomic_uintptr_t cc_array_index;
atomic_uintptr_t cc_array_size;
StaticSpinMutex mu;
};
@ -184,11 +173,6 @@ void CoverageData::Enable() {
} else {
atomic_store(&pc_array_size, kPcArrayMaxSize, memory_order_relaxed);
}
cc_array = reinterpret_cast<uptr **>(MmapNoReserveOrDie(
sizeof(uptr *) * kCcArrayMaxSize, "CovInit::cc_array"));
atomic_store(&cc_array_size, kCcArrayMaxSize, memory_order_relaxed);
atomic_store(&cc_array_index, 0, memory_order_relaxed);
}
void CoverageData::InitializeGuardArray(s32 *guards) {
@ -206,10 +190,6 @@ void CoverageData::Disable() {
UnmapOrDie(pc_array, sizeof(uptr) * kPcArrayMaxSize);
pc_array = nullptr;
}
if (cc_array) {
UnmapOrDie(cc_array, sizeof(uptr *) * kCcArrayMaxSize);
cc_array = nullptr;
}
if (pc_fd != kInvalidFd) {
CloseFile(pc_fd);
pc_fd = kInvalidFd;
@ -363,40 +343,6 @@ void CoverageData::Add(uptr pc, u32 *guard) {
pc_array[idx] = BundlePcAndCounter(pc, counter);
}
// Registers a pair caller=>callee.
// When a given caller is seen for the first time, the callee_cache is added
// to the global array cc_array, callee_cache[0] is set to caller and
// callee_cache[1] is set to cache_size.
// Then we are trying to add callee to callee_cache [2,cache_size) if it is
// not there yet.
// If the cache is full we drop the callee (may want to fix this later).
void CoverageData::IndirCall(uptr caller, uptr callee, uptr callee_cache[],
uptr cache_size) {
if (!cc_array) return;
atomic_uintptr_t *atomic_callee_cache =
reinterpret_cast<atomic_uintptr_t *>(callee_cache);
uptr zero = 0;
if (atomic_compare_exchange_strong(&atomic_callee_cache[0], &zero, caller,
memory_order_seq_cst)) {
uptr idx = atomic_fetch_add(&cc_array_index, 1, memory_order_relaxed);
CHECK_LT(idx * sizeof(uptr),
atomic_load(&cc_array_size, memory_order_acquire));
callee_cache[1] = cache_size;
cc_array[idx] = callee_cache;
}
CHECK_EQ(atomic_load(&atomic_callee_cache[0], memory_order_relaxed), caller);
for (uptr i = 2; i < cache_size; i++) {
uptr was = 0;
if (atomic_compare_exchange_strong(&atomic_callee_cache[i], &was, callee,
memory_order_seq_cst)) {
atomic_fetch_add(&caller_callee_counter, 1, memory_order_relaxed);
return;
}
if (was == callee) // Already have this callee.
return;
}
}
uptr *CoverageData::data() {
return pc_array;
}
@ -477,46 +423,6 @@ static fd_t CovOpenFile(InternalScopedString *path, bool packed,
return fd;
}
// This function dumps the caller=>callee pairs into a file as a sequence of
// lines like "module_name offset".
void CoverageData::DumpCallerCalleePairs() {
uptr max_idx = atomic_load(&cc_array_index, memory_order_relaxed);
if (!max_idx) return;
auto sym = Symbolizer::GetOrInit();
if (!sym)
return;
InternalScopedString out(32 << 20);
uptr total = 0;
for (uptr i = 0; i < max_idx; i++) {
uptr *cc_cache = cc_array[i];
CHECK(cc_cache);
uptr caller = cc_cache[0];
uptr n_callees = cc_cache[1];
const char *caller_module_name = "<unknown>";
uptr caller_module_address = 0;
sym->GetModuleNameAndOffsetForPC(caller, &caller_module_name,
&caller_module_address);
for (uptr j = 2; j < n_callees; j++) {
uptr callee = cc_cache[j];
if (!callee) break;
total++;
const char *callee_module_name = "<unknown>";
uptr callee_module_address = 0;
sym->GetModuleNameAndOffsetForPC(callee, &callee_module_name,
&callee_module_address);
out.append("%s 0x%zx\n%s 0x%zx\n", caller_module_name,
caller_module_address, callee_module_name,
callee_module_address);
}
}
InternalScopedString path(kMaxPathLength);
fd_t fd = CovOpenFile(&path, false, "caller-callee");
if (fd == kInvalidFd) return;
WriteToFile(fd, out.data(), out.length());
CloseFile(fd);
VReport(1, " CovDump: %zd caller-callee pairs written\n", total);
}
void CoverageData::DumpAsBitSet() {
if (!common_flags()->coverage_bitset) return;
if (!size()) return;
@ -665,7 +571,6 @@ void CoverageData::DumpAll() {
return;
DumpAsBitSet();
DumpOffsets();
DumpCallerCalleePairs();
}
void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
@ -739,11 +644,6 @@ SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_with_check(u32 *guard) {
coverage_data.Add(StackTrace::GetPreviousInstructionPc(GET_CALLER_PC()),
guard);
}
SANITIZER_INTERFACE_ATTRIBUTE void
__sanitizer_cov_indir_call16(uptr callee, uptr callee_cache16[]) {
coverage_data.IndirCall(StackTrace::GetPreviousInstructionPc(GET_CALLER_PC()),
callee, callee_cache16, 16);
}
SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_init() {
coverage_enabled = true;
coverage_dir = common_flags()->coverage_dir;
@ -774,11 +674,6 @@ uptr __sanitizer_get_total_unique_coverage() {
return atomic_load(&coverage_counter, memory_order_relaxed);
}
SANITIZER_INTERFACE_ATTRIBUTE
uptr __sanitizer_get_total_unique_caller_callee_pairs() {
return atomic_load(&caller_callee_counter, memory_order_relaxed);
}
SANITIZER_INTERFACE_ATTRIBUTE
void __sanitizer_reset_coverage() {
ResetGlobalCounters();

View File

@ -1,75 +0,0 @@
// Test caller-callee coverage with large number of threads
// and various numbers of callers and callees.
// RUN: %clangxx_asan -fsanitize-coverage=edge,indirect-calls %s -o %t
// RUN: %env_asan_opts=coverage=1:verbosity=1 %run %t 10 1 2>&1 | FileCheck %s --check-prefix=CHECK-10-1
// RUN: %env_asan_opts=coverage=1:verbosity=1 %run %t 9 2 2>&1 | FileCheck %s --check-prefix=CHECK-9-2
// RUN: %env_asan_opts=coverage=1:verbosity=1 %run %t 7 3 2>&1 | FileCheck %s --check-prefix=CHECK-7-3
// RUN: %env_asan_opts=coverage=1:verbosity=1 %run %t 17 1 2>&1 | FileCheck %s --check-prefix=CHECK-17-1
// RUN: %env_asan_opts=coverage=1:verbosity=1 %run %t 15 2 2>&1 | FileCheck %s --check-prefix=CHECK-15-2
// RUN: %env_asan_opts=coverage=1:verbosity=1 %run %t 18 3 2>&1 | FileCheck %s --check-prefix=CHECK-18-3
// RUN: rm -f caller-callee*.sancov
//
// REQUIRES: asan-64-bits
// UNSUPPORTED: android
//
// CHECK-10-1: CovDump: 10 caller-callee pairs written
// CHECK-9-2: CovDump: 18 caller-callee pairs written
// CHECK-7-3: CovDump: 21 caller-callee pairs written
// CHECK-17-1: CovDump: 14 caller-callee pairs written
// CHECK-15-2: CovDump: 28 caller-callee pairs written
// CHECK-18-3: CovDump: 42 caller-callee pairs written
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
int P = 0;
struct Foo {virtual void f() {if (P) printf("Foo::f()\n");}};
struct Foo1 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
struct Foo2 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
struct Foo3 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
struct Foo4 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
struct Foo5 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
struct Foo6 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
struct Foo7 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
struct Foo8 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
struct Foo9 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
struct Foo10 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
struct Foo11 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
struct Foo12 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
struct Foo13 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
struct Foo14 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
struct Foo15 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
struct Foo16 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
struct Foo17 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
struct Foo18 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
struct Foo19 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
Foo *foo[20] = {
new Foo, new Foo1, new Foo2, new Foo3, new Foo4, new Foo5, new Foo6,
new Foo7, new Foo8, new Foo9, new Foo10, new Foo11, new Foo12, new Foo13,
new Foo14, new Foo15, new Foo16, new Foo17, new Foo18, new Foo19,
};
int n_functions = 10;
int n_callers = 2;
void *Thread(void *arg) {
if (n_callers >= 1) for (int i = 0; i < 2000; i++) foo[i % n_functions]->f();
if (n_callers >= 2) for (int i = 0; i < 2000; i++) foo[i % n_functions]->f();
if (n_callers >= 3) for (int i = 0; i < 2000; i++) foo[i % n_functions]->f();
return arg;
}
int main(int argc, char **argv) {
if (argc >= 2)
n_functions = atoi(argv[1]);
if (argc >= 3)
n_callers = atoi(argv[2]);
const int kNumThreads = 16;
pthread_t t[kNumThreads];
for (int i = 0; i < kNumThreads; i++)
pthread_create(&t[i], 0, Thread, 0);
for (int i = 0; i < kNumThreads; i++)
pthread_join(t[i], 0);
}

View File

@ -1,42 +0,0 @@
// Test __sanitizer_get_total_unique_coverage for caller-callee coverage
// RUN: %clangxx_asan -fsanitize-coverage=edge,indirect-calls %s -o %t
// RUN: %env_asan_opts=coverage=1 %run %t
// RUN: rm -f caller-callee*.sancov
//
// REQUIRES: asan-64-bits
#include <sanitizer/coverage_interface.h>
#include <stdio.h>
#include <assert.h>
int P = 0;
struct Foo {virtual void f() {if (P) printf("Foo::f()\n");}};
struct Foo1 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
struct Foo2 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
Foo *foo[3] = {new Foo, new Foo1, new Foo2};
uintptr_t CheckNewTotalUniqueCoverageIsLargerAndReturnIt(uintptr_t old_total) {
uintptr_t new_total = __sanitizer_get_total_unique_caller_callee_pairs();
fprintf(stderr, "Caller-Callee: old %zd new %zd\n", old_total, new_total);
assert(new_total > old_total);
return new_total;
}
int main(int argc, char **argv) {
uintptr_t total = __sanitizer_get_total_unique_caller_callee_pairs();
foo[0]->f();
total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(total);
foo[1]->f();
total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(total);
foo[2]->f();
total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(total);
// Ok, called every function once.
// Now call them again from another call site. Should get new coverage.
foo[0]->f();
total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(total);
foo[1]->f();
total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(total);
foo[2]->f();
total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(total);
}