forked from OSchip/llvm-project
Reapply asan coverage changes 194702-194704.
I still don't know what is causing our bootstrapped LTO buildbots to fail, but llvm r194701 seems to be OK and I can't imagine that these changes could cause the problem. llvm-svn: 194790
This commit is contained in:
parent
da4147c743
commit
a08e9ac927
|
@ -47,6 +47,9 @@ extern "C" {
|
||||||
void __sanitizer_unaligned_store32(void *p, uint32_t x);
|
void __sanitizer_unaligned_store32(void *p, uint32_t x);
|
||||||
void __sanitizer_unaligned_store64(void *p, uint64_t x);
|
void __sanitizer_unaligned_store64(void *p, uint64_t x);
|
||||||
|
|
||||||
|
// Record and dump coverage info.
|
||||||
|
void __sanitizer_cov_dump();
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -83,6 +83,9 @@ struct Flags {
|
||||||
bool print_legend;
|
bool print_legend;
|
||||||
// If set, prints ASan exit stats even after program terminates successfully.
|
// If set, prints ASan exit stats even after program terminates successfully.
|
||||||
bool atexit;
|
bool atexit;
|
||||||
|
// If set, coverage information will be dumped at shutdown time if the
|
||||||
|
// appropriate instrumentation was enabled.
|
||||||
|
bool coverage;
|
||||||
// By default, disable core dumper on 64-bit - it makes little sense
|
// By default, disable core dumper on 64-bit - it makes little sense
|
||||||
// to dump 16T+ core.
|
// to dump 16T+ core.
|
||||||
bool disable_core;
|
bool disable_core;
|
||||||
|
|
|
@ -120,6 +120,7 @@ static void ParseFlagsFromString(Flags *f, const char *str) {
|
||||||
ParseFlag(str, &f->print_stats, "print_stats");
|
ParseFlag(str, &f->print_stats, "print_stats");
|
||||||
ParseFlag(str, &f->print_legend, "print_legend");
|
ParseFlag(str, &f->print_legend, "print_legend");
|
||||||
ParseFlag(str, &f->atexit, "atexit");
|
ParseFlag(str, &f->atexit, "atexit");
|
||||||
|
ParseFlag(str, &f->coverage, "coverage");
|
||||||
ParseFlag(str, &f->disable_core, "disable_core");
|
ParseFlag(str, &f->disable_core, "disable_core");
|
||||||
ParseFlag(str, &f->allow_reexec, "allow_reexec");
|
ParseFlag(str, &f->allow_reexec, "allow_reexec");
|
||||||
ParseFlag(str, &f->print_full_thread_history, "print_full_thread_history");
|
ParseFlag(str, &f->print_full_thread_history, "print_full_thread_history");
|
||||||
|
@ -161,6 +162,7 @@ void InitializeFlags(Flags *f, const char *env) {
|
||||||
f->print_stats = false;
|
f->print_stats = false;
|
||||||
f->print_legend = true;
|
f->print_legend = true;
|
||||||
f->atexit = false;
|
f->atexit = false;
|
||||||
|
f->coverage = false;
|
||||||
f->disable_core = (SANITIZER_WORDSIZE == 64);
|
f->disable_core = (SANITIZER_WORDSIZE == 64);
|
||||||
f->allow_reexec = true;
|
f->allow_reexec = true;
|
||||||
f->print_full_thread_history = true;
|
f->print_full_thread_history = true;
|
||||||
|
@ -541,6 +543,9 @@ void __asan_init() {
|
||||||
if (flags()->atexit)
|
if (flags()->atexit)
|
||||||
Atexit(asan_atexit);
|
Atexit(asan_atexit);
|
||||||
|
|
||||||
|
if (flags()->coverage)
|
||||||
|
Atexit(__sanitizer_cov_dump);
|
||||||
|
|
||||||
// interceptors
|
// interceptors
|
||||||
InitTlsSize();
|
InitTlsSize();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
// RUN: %clangxx_asan -mllvm -asan-coverage=1 -DSHARED %s -shared -o %t.so -fPIC
|
||||||
|
// RUN: %clangxx_asan -mllvm -asan-coverage=1 %s -o %t -Wl,-R. %t.so
|
||||||
|
// RUN: export ASAN_OPTIONS=coverage=1:verbosity=1
|
||||||
|
// RUN: %t 2>&1 | FileCheck %s --check-prefix=CHECK-main
|
||||||
|
// RUN: %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-foo
|
||||||
|
// RUN: %t bar 2>&1 | FileCheck %s --check-prefix=CHECK-bar
|
||||||
|
// RUN: %t foo bar 2>&1 | FileCheck %s --check-prefix=CHECK-foo-bar
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#ifdef SHARED
|
||||||
|
void bar() { printf("bar\n"); }
|
||||||
|
#else
|
||||||
|
__attribute__((noinline))
|
||||||
|
void foo() { printf("foo\n"); }
|
||||||
|
extern void bar();
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
fprintf(stderr, "PID: %d\n", getpid());
|
||||||
|
for (int i = 1; i < argc; i++) {
|
||||||
|
if (!strcmp(argv[i], "foo"))
|
||||||
|
foo();
|
||||||
|
if (!strcmp(argv[i], "bar"))
|
||||||
|
bar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// CHECK-main: PID: [[PID:[0-9]+]]
|
||||||
|
// CHECK-main: [[PID]].sancov: 1 PCs written
|
||||||
|
// CHECK-main-NOT: .so.[[PID]]
|
||||||
|
//
|
||||||
|
// CHECK-foo: PID: [[PID:[0-9]+]]
|
||||||
|
// CHECK-foo: [[PID]].sancov: 2 PCs written
|
||||||
|
// CHECK-foo-NOT: .so.[[PID]]
|
||||||
|
//
|
||||||
|
// CHECK-bar: PID: [[PID:[0-9]+]]
|
||||||
|
// CHECK-bar: [[PID]].sancov: 1 PCs written
|
||||||
|
// CHECK-bar: .so.[[PID]].sancov: 1 PCs written
|
||||||
|
//
|
||||||
|
// CHECK-foo-bar: PID: [[PID:[0-9]+]]
|
||||||
|
// CHECK-foo-bar: [[PID]].sancov: 2 PCs written
|
||||||
|
// CHECK-foo-bar: so.[[PID]].sancov: 1 PCs written
|
|
@ -4,6 +4,7 @@
|
||||||
set(SANITIZER_SOURCES
|
set(SANITIZER_SOURCES
|
||||||
sanitizer_allocator.cc
|
sanitizer_allocator.cc
|
||||||
sanitizer_common.cc
|
sanitizer_common.cc
|
||||||
|
sanitizer_coverage.cc
|
||||||
sanitizer_flags.cc
|
sanitizer_flags.cc
|
||||||
sanitizer_libc.cc
|
sanitizer_libc.cc
|
||||||
sanitizer_libignore.cc
|
sanitizer_libignore.cc
|
||||||
|
|
|
@ -226,6 +226,17 @@ bool LoadedModule::containsAddress(uptr address) const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *StripModuleName(const char *module) {
|
||||||
|
if (module == 0)
|
||||||
|
return 0;
|
||||||
|
const char *short_module_name = internal_strrchr(module, '/');
|
||||||
|
if (short_module_name)
|
||||||
|
short_module_name += 1;
|
||||||
|
else
|
||||||
|
short_module_name = module;
|
||||||
|
return internal_strdup(short_module_name);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace __sanitizer
|
} // namespace __sanitizer
|
||||||
|
|
||||||
using namespace __sanitizer; // NOLINT
|
using namespace __sanitizer; // NOLINT
|
||||||
|
|
|
@ -180,6 +180,9 @@ void SleepForMillis(int millis);
|
||||||
u64 NanoTime();
|
u64 NanoTime();
|
||||||
int Atexit(void (*function)(void));
|
int Atexit(void (*function)(void));
|
||||||
void SortArray(uptr *array, uptr size);
|
void SortArray(uptr *array, uptr size);
|
||||||
|
// Strip the directories from the module name, return a new string allocated
|
||||||
|
// with internal_strdup.
|
||||||
|
char *StripModuleName(const char *module);
|
||||||
|
|
||||||
// Exit
|
// Exit
|
||||||
void NORETURN Abort();
|
void NORETURN Abort();
|
||||||
|
@ -359,6 +362,8 @@ class InternalMmapVector {
|
||||||
return capacity_;
|
return capacity_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clear() { size_ = 0; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Resize(uptr new_capacity) {
|
void Resize(uptr new_capacity) {
|
||||||
CHECK_GT(new_capacity, 0);
|
CHECK_GT(new_capacity, 0);
|
||||||
|
|
|
@ -0,0 +1,113 @@
|
||||||
|
//===-- sanitizer_coverage.cc ---------------------------------------------===//
|
||||||
|
//
|
||||||
|
// The LLVM Compiler Infrastructure
|
||||||
|
//
|
||||||
|
// This file is distributed under the University of Illinois Open Source
|
||||||
|
// License. See LICENSE.TXT for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Sanitizer Coverage.
|
||||||
|
// This file implements run-time support for a poor man's coverage tool.
|
||||||
|
//
|
||||||
|
// Compiler instrumentation:
|
||||||
|
// For every function F the compiler injects the following code:
|
||||||
|
// if (*Guard) {
|
||||||
|
// __sanitizer_cov(&F);
|
||||||
|
// *Guard = 1;
|
||||||
|
// }
|
||||||
|
// It's fine to call __sanitizer_cov more than once for a given function.
|
||||||
|
//
|
||||||
|
// Run-time:
|
||||||
|
// - __sanitizer_cov(pc): record that we've executed a given PC.
|
||||||
|
// - __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:
|
||||||
|
// it's just a sorted sequence of 4-byte offsets in the module.
|
||||||
|
//
|
||||||
|
// Eventually, this coverage implementation should be obsoleted by a more
|
||||||
|
// powerful general purpose Clang/LLVM coverage instrumentation.
|
||||||
|
// Consider this implementation as prototype.
|
||||||
|
//
|
||||||
|
// FIXME: support (or at least test with) dlclose.
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "sanitizer_allocator_internal.h"
|
||||||
|
#include "sanitizer_common.h"
|
||||||
|
#include "sanitizer_libc.h"
|
||||||
|
#include "sanitizer_mutex.h"
|
||||||
|
#include "sanitizer_procmaps.h"
|
||||||
|
#include "sanitizer_flags.h"
|
||||||
|
|
||||||
|
struct CovData {
|
||||||
|
BlockingMutex mu;
|
||||||
|
InternalMmapVector<uptr> v;
|
||||||
|
};
|
||||||
|
|
||||||
|
static uptr cov_data_placeholder[sizeof(CovData) / sizeof(uptr)];
|
||||||
|
COMPILER_CHECK(sizeof(cov_data_placeholder) >= sizeof(CovData));
|
||||||
|
static CovData *cov_data = reinterpret_cast<CovData*>(cov_data_placeholder);
|
||||||
|
|
||||||
|
namespace __sanitizer {
|
||||||
|
|
||||||
|
// Simply add the pc into the vector under lock. If the function is called more
|
||||||
|
// than once for a given PC it will be inserted multiple times, which is fine.
|
||||||
|
static void CovAdd(uptr pc) {
|
||||||
|
BlockingMutexLock lock(&cov_data->mu);
|
||||||
|
cov_data->v.push_back(pc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool CompareLess(const uptr &a, const uptr &b) {
|
||||||
|
return a < b;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dump the coverage on disk.
|
||||||
|
void CovDump() {
|
||||||
|
#if !SANITIZER_WINDOWS
|
||||||
|
BlockingMutexLock lock(&cov_data->mu);
|
||||||
|
InternalMmapVector<uptr> &v = cov_data->v;
|
||||||
|
InternalSort(&v, v.size(), CompareLess);
|
||||||
|
InternalMmapVector<u32> offsets(v.size());
|
||||||
|
const uptr *vb = v.data();
|
||||||
|
const uptr *ve = vb + v.size();
|
||||||
|
MemoryMappingLayout proc_maps(/*cache_enabled*/false);
|
||||||
|
uptr mb, me, off, prot;
|
||||||
|
InternalScopedBuffer<char> module(4096);
|
||||||
|
InternalScopedBuffer<char> path(4096 * 2);
|
||||||
|
for (int i = 0;
|
||||||
|
proc_maps.Next(&mb, &me, &off, module.data(), module.size(), &prot);
|
||||||
|
i++) {
|
||||||
|
if ((prot & MemoryMappingLayout::kProtectionExecute) == 0)
|
||||||
|
continue;
|
||||||
|
if (vb >= ve) break;
|
||||||
|
if (mb <= *vb && *vb < me) {
|
||||||
|
offsets.clear();
|
||||||
|
const uptr *old_vb = vb;
|
||||||
|
CHECK_LE(off, *vb);
|
||||||
|
for (; vb < ve && *vb < me; vb++) {
|
||||||
|
uptr diff = *vb - (i ? mb : 0) + off;
|
||||||
|
CHECK_LE(diff, 0xffffffffU);
|
||||||
|
offsets.push_back(static_cast<u32>(diff));
|
||||||
|
}
|
||||||
|
char *module_name = StripModuleName(module.data());
|
||||||
|
internal_snprintf((char *)path.data(), path.size(), "%s.%zd.sancov",
|
||||||
|
module_name, internal_getpid());
|
||||||
|
InternalFree(module_name);
|
||||||
|
uptr fd = OpenFile(path.data(), true);
|
||||||
|
internal_write(fd, offsets.data(), offsets.size() * sizeof(u32));
|
||||||
|
internal_close(fd);
|
||||||
|
if (common_flags()->verbosity)
|
||||||
|
Report(" CovDump: %s: %zd PCs written\n", path.data(), vb - old_vb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // !SANITIZER_WINDOWS
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace __sanitizer
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov(void *pc) {
|
||||||
|
CovAdd(reinterpret_cast<uptr>(pc));
|
||||||
|
}
|
||||||
|
SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { CovDump(); }
|
||||||
|
} // extern "C"
|
|
@ -110,6 +110,9 @@ extern "C" {
|
||||||
// the error message. This function can be overridden by the client.
|
// the error message. This function can be overridden by the client.
|
||||||
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
|
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
|
||||||
void __sanitizer_report_error_summary(const char *error_summary);
|
void __sanitizer_report_error_summary(const char *error_summary);
|
||||||
|
|
||||||
|
SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump();
|
||||||
|
SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov(void *pc);
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -42,18 +42,6 @@ ReportStack *NewReportStackEntry(uptr addr) {
|
||||||
return ent;
|
return ent;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Strip module path to make output shorter.
|
|
||||||
static char *StripModuleName(const char *module) {
|
|
||||||
if (module == 0)
|
|
||||||
return 0;
|
|
||||||
const char *short_module_name = internal_strrchr(module, '/');
|
|
||||||
if (short_module_name)
|
|
||||||
short_module_name += 1;
|
|
||||||
else
|
|
||||||
short_module_name = module;
|
|
||||||
return internal_strdup(short_module_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ReportStack *NewReportStackEntry(const AddressInfo &info) {
|
static ReportStack *NewReportStackEntry(const AddressInfo &info) {
|
||||||
ReportStack *ent = NewReportStackEntry(info.address);
|
ReportStack *ent = NewReportStackEntry(info.address);
|
||||||
ent->module = StripModuleName(info.module);
|
ent->module = StripModuleName(info.module);
|
||||||
|
|
Loading…
Reference in New Issue