forked from OSchip/llvm-project
[sanitizer-coverage] remove run-time support for -fsanitize-coverage=indirect-calls
llvm-svn: 300775
This commit is contained in:
parent
3cc8da3248
commit
d32bc3ee38
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue