1 //===-- sanitizer_coverage.cc ---------------------------------------------===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
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:
14 // __sanitizer_cov(&F);
17 // It's fine to call __sanitizer_cov more than once for a given function.
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"
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
) {
62 // Dump the coverage on disk.
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);
76 proc_maps
.Next(&mb
, &me
, &off
, module
.data(), module
.size(), &prot
);
78 if ((prot
& MemoryMappingLayout::kProtectionExecute
) == 0)
81 if (mb
<= *vb
&& *vb
< me
) {
83 const uptr
*old_vb
= 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
));
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
107 SANITIZER_INTERFACE_ATTRIBUTE
void __sanitizer_cov(void *pc
) {
108 CovAdd(reinterpret_cast<uptr
>(pc
));
110 SANITIZER_INTERFACE_ATTRIBUTE
void __sanitizer_cov_dump() { CovDump(); }