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