Skip to content
This repository was archived by the owner on May 21, 2019. It is now read-only.

Commit dbd69cc

Browse files
committed
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. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@194790 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent ae51c27 commit dbd69cc

File tree

10 files changed

+189
-12
lines changed

10 files changed

+189
-12
lines changed

include/sanitizer/common_interface_defs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ extern "C" {
4747
void __sanitizer_unaligned_store32(void *p, uint32_t x);
4848
void __sanitizer_unaligned_store64(void *p, uint64_t x);
4949

50+
// Record and dump coverage info.
51+
void __sanitizer_cov_dump();
52+
5053
#ifdef __cplusplus
5154
} // extern "C"
5255
#endif

lib/asan/asan_flags.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ struct Flags {
8383
bool print_legend;
8484
// If set, prints ASan exit stats even after program terminates successfully.
8585
bool atexit;
86+
// If set, coverage information will be dumped at shutdown time if the
87+
// appropriate instrumentation was enabled.
88+
bool coverage;
8689
// By default, disable core dumper on 64-bit - it makes little sense
8790
// to dump 16T+ core.
8891
bool disable_core;

lib/asan/asan_rtl.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ static void ParseFlagsFromString(Flags *f, const char *str) {
120120
ParseFlag(str, &f->print_stats, "print_stats");
121121
ParseFlag(str, &f->print_legend, "print_legend");
122122
ParseFlag(str, &f->atexit, "atexit");
123+
ParseFlag(str, &f->coverage, "coverage");
123124
ParseFlag(str, &f->disable_core, "disable_core");
124125
ParseFlag(str, &f->allow_reexec, "allow_reexec");
125126
ParseFlag(str, &f->print_full_thread_history, "print_full_thread_history");
@@ -161,6 +162,7 @@ void InitializeFlags(Flags *f, const char *env) {
161162
f->print_stats = false;
162163
f->print_legend = true;
163164
f->atexit = false;
165+
f->coverage = false;
164166
f->disable_core = (SANITIZER_WORDSIZE == 64);
165167
f->allow_reexec = true;
166168
f->print_full_thread_history = true;
@@ -541,6 +543,9 @@ void __asan_init() {
541543
if (flags()->atexit)
542544
Atexit(asan_atexit);
543545

546+
if (flags()->coverage)
547+
Atexit(__sanitizer_cov_dump);
548+
544549
// interceptors
545550
InitTlsSize();
546551

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// RUN: %clangxx_asan -mllvm -asan-coverage=1 -DSHARED %s -shared -o %t.so -fPIC
2+
// RUN: %clangxx_asan -mllvm -asan-coverage=1 %s -o %t -Wl,-R. %t.so
3+
// RUN: export ASAN_OPTIONS=coverage=1:verbosity=1
4+
// RUN: %t 2>&1 | FileCheck %s --check-prefix=CHECK-main
5+
// RUN: %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-foo
6+
// RUN: %t bar 2>&1 | FileCheck %s --check-prefix=CHECK-bar
7+
// RUN: %t foo bar 2>&1 | FileCheck %s --check-prefix=CHECK-foo-bar
8+
9+
#include <stdio.h>
10+
#include <string.h>
11+
#include <unistd.h>
12+
13+
#ifdef SHARED
14+
void bar() { printf("bar\n"); }
15+
#else
16+
__attribute__((noinline))
17+
void foo() { printf("foo\n"); }
18+
extern void bar();
19+
20+
int main(int argc, char **argv) {
21+
fprintf(stderr, "PID: %d\n", getpid());
22+
for (int i = 1; i < argc; i++) {
23+
if (!strcmp(argv[i], "foo"))
24+
foo();
25+
if (!strcmp(argv[i], "bar"))
26+
bar();
27+
}
28+
}
29+
#endif
30+
31+
// CHECK-main: PID: [[PID:[0-9]+]]
32+
// CHECK-main: [[PID]].sancov: 1 PCs written
33+
// CHECK-main-NOT: .so.[[PID]]
34+
//
35+
// CHECK-foo: PID: [[PID:[0-9]+]]
36+
// CHECK-foo: [[PID]].sancov: 2 PCs written
37+
// CHECK-foo-NOT: .so.[[PID]]
38+
//
39+
// CHECK-bar: PID: [[PID:[0-9]+]]
40+
// CHECK-bar: [[PID]].sancov: 1 PCs written
41+
// CHECK-bar: .so.[[PID]].sancov: 1 PCs written
42+
//
43+
// CHECK-foo-bar: PID: [[PID:[0-9]+]]
44+
// CHECK-foo-bar: [[PID]].sancov: 2 PCs written
45+
// CHECK-foo-bar: so.[[PID]].sancov: 1 PCs written

lib/sanitizer_common/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
set(SANITIZER_SOURCES
55
sanitizer_allocator.cc
66
sanitizer_common.cc
7+
sanitizer_coverage.cc
78
sanitizer_flags.cc
89
sanitizer_libc.cc
910
sanitizer_libignore.cc

lib/sanitizer_common/sanitizer_common.cc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,17 @@ bool LoadedModule::containsAddress(uptr address) const {
226226
return false;
227227
}
228228

229+
char *StripModuleName(const char *module) {
230+
if (module == 0)
231+
return 0;
232+
const char *short_module_name = internal_strrchr(module, '/');
233+
if (short_module_name)
234+
short_module_name += 1;
235+
else
236+
short_module_name = module;
237+
return internal_strdup(short_module_name);
238+
}
239+
229240
} // namespace __sanitizer
230241

231242
using namespace __sanitizer; // NOLINT

lib/sanitizer_common/sanitizer_common.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,9 @@ void SleepForMillis(int millis);
180180
u64 NanoTime();
181181
int Atexit(void (*function)(void));
182182
void SortArray(uptr *array, uptr size);
183+
// Strip the directories from the module name, return a new string allocated
184+
// with internal_strdup.
185+
char *StripModuleName(const char *module);
183186

184187
// Exit
185188
void NORETURN Abort();
@@ -359,6 +362,8 @@ class InternalMmapVector {
359362
return capacity_;
360363
}
361364

365+
void clear() { size_ = 0; }
366+
362367
private:
363368
void Resize(uptr new_capacity) {
364369
CHECK_GT(new_capacity, 0);
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
//===-- sanitizer_coverage.cc ---------------------------------------------===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// Sanitizer Coverage.
11+
// This file implements run-time support for a poor man's coverage tool.
12+
//
13+
// Compiler instrumentation:
14+
// For every function F the compiler injects the following code:
15+
// if (*Guard) {
16+
// __sanitizer_cov(&F);
17+
// *Guard = 1;
18+
// }
19+
// It's fine to call __sanitizer_cov more than once for a given function.
20+
//
21+
// Run-time:
22+
// - __sanitizer_cov(pc): record that we've executed a given PC.
23+
// - __sanitizer_cov_dump: dump the coverage data to disk.
24+
// For every module of the current process that has coverage data
25+
// this will create a file module_name.PID.sancov. The file format is simple:
26+
// it's just a sorted sequence of 4-byte offsets in the module.
27+
//
28+
// Eventually, this coverage implementation should be obsoleted by a more
29+
// powerful general purpose Clang/LLVM coverage instrumentation.
30+
// Consider this implementation as prototype.
31+
//
32+
// FIXME: support (or at least test with) dlclose.
33+
//===----------------------------------------------------------------------===//
34+
35+
#include "sanitizer_allocator_internal.h"
36+
#include "sanitizer_common.h"
37+
#include "sanitizer_libc.h"
38+
#include "sanitizer_mutex.h"
39+
#include "sanitizer_procmaps.h"
40+
#include "sanitizer_flags.h"
41+
42+
struct CovData {
43+
BlockingMutex mu;
44+
InternalMmapVector<uptr> v;
45+
};
46+
47+
static uptr cov_data_placeholder[sizeof(CovData) / sizeof(uptr)];
48+
COMPILER_CHECK(sizeof(cov_data_placeholder) >= sizeof(CovData));
49+
static CovData *cov_data = reinterpret_cast<CovData*>(cov_data_placeholder);
50+
51+
namespace __sanitizer {
52+
53+
// Simply add the pc into the vector under lock. If the function is called more
54+
// than once for a given PC it will be inserted multiple times, which is fine.
55+
static void CovAdd(uptr pc) {
56+
BlockingMutexLock lock(&cov_data->mu);
57+
cov_data->v.push_back(pc);
58+
}
59+
60+
static inline bool CompareLess(const uptr &a, const uptr &b) {
61+
return a < b;
62+
}
63+
64+
// Dump the coverage on disk.
65+
void CovDump() {
66+
#if !SANITIZER_WINDOWS
67+
BlockingMutexLock lock(&cov_data->mu);
68+
InternalMmapVector<uptr> &v = cov_data->v;
69+
InternalSort(&v, v.size(), CompareLess);
70+
InternalMmapVector<u32> offsets(v.size());
71+
const uptr *vb = v.data();
72+
const uptr *ve = vb + v.size();
73+
MemoryMappingLayout proc_maps(/*cache_enabled*/false);
74+
uptr mb, me, off, prot;
75+
InternalScopedBuffer<char> module(4096);
76+
InternalScopedBuffer<char> path(4096 * 2);
77+
for (int i = 0;
78+
proc_maps.Next(&mb, &me, &off, module.data(), module.size(), &prot);
79+
i++) {
80+
if ((prot & MemoryMappingLayout::kProtectionExecute) == 0)
81+
continue;
82+
if (vb >= ve) break;
83+
if (mb <= *vb && *vb < me) {
84+
offsets.clear();
85+
const uptr *old_vb = vb;
86+
CHECK_LE(off, *vb);
87+
for (; vb < ve && *vb < me; vb++) {
88+
uptr diff = *vb - (i ? mb : 0) + off;
89+
CHECK_LE(diff, 0xffffffffU);
90+
offsets.push_back(static_cast<u32>(diff));
91+
}
92+
char *module_name = StripModuleName(module.data());
93+
internal_snprintf((char *)path.data(), path.size(), "%s.%zd.sancov",
94+
module_name, internal_getpid());
95+
InternalFree(module_name);
96+
uptr fd = OpenFile(path.data(), true);
97+
internal_write(fd, offsets.data(), offsets.size() * sizeof(u32));
98+
internal_close(fd);
99+
if (common_flags()->verbosity)
100+
Report(" CovDump: %s: %zd PCs written\n", path.data(), vb - old_vb);
101+
}
102+
}
103+
#endif // !SANITIZER_WINDOWS
104+
}
105+
106+
} // namespace __sanitizer
107+
108+
extern "C" {
109+
SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov(void *pc) {
110+
CovAdd(reinterpret_cast<uptr>(pc));
111+
}
112+
SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { CovDump(); }
113+
} // extern "C"

lib/sanitizer_common/sanitizer_internal_defs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,9 @@ extern "C" {
110110
// the error message. This function can be overridden by the client.
111111
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
112112
void __sanitizer_report_error_summary(const char *error_summary);
113+
114+
SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump();
115+
SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov(void *pc);
113116
} // extern "C"
114117

115118

lib/tsan/rtl/tsan_symbolize.cc

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,18 +42,6 @@ ReportStack *NewReportStackEntry(uptr addr) {
4242
return ent;
4343
}
4444

45-
// Strip module path to make output shorter.
46-
static char *StripModuleName(const char *module) {
47-
if (module == 0)
48-
return 0;
49-
const char *short_module_name = internal_strrchr(module, '/');
50-
if (short_module_name)
51-
short_module_name += 1;
52-
else
53-
short_module_name = module;
54-
return internal_strdup(short_module_name);
55-
}
56-
5745
static ReportStack *NewReportStackEntry(const AddressInfo &info) {
5846
ReportStack *ent = NewReportStackEntry(info.address);
5947
ent->module = StripModuleName(info.module);

0 commit comments

Comments
 (0)