1 //===-- sanitizer_coverage_libcdep_new.cpp --------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
8 // Sanitizer Coverage Controller for Trace PC Guard.
10 #include "sanitizer_platform.h"
12 #if !SANITIZER_FUCHSIA
13 # include "sancov_flags.h"
14 # include "sanitizer_allocator_internal.h"
15 # include "sanitizer_atomic.h"
16 # include "sanitizer_common.h"
17 # include "sanitizer_common/sanitizer_stacktrace.h"
18 # include "sanitizer_file.h"
19 # include "sanitizer_interface_internal.h"
21 using namespace __sanitizer
;
23 using AddressRange
= LoadedModule::AddressRange
;
28 static const u64 Magic64
= 0xC0BFFFFFFFFFFF64ULL
;
29 static const u64 Magic32
= 0xC0BFFFFFFFFFFF32ULL
;
30 static const u64 Magic
= SANITIZER_WORDSIZE
== 64 ? Magic64
: Magic32
;
32 static fd_t
OpenFile(const char* path
) {
34 fd_t fd
= OpenFile(path
, WrOnly
, &err
);
36 Report("SanitizerCoverage: failed to open %s for writing (reason: %d)\n",
41 static void GetCoverageFilename(char* path
, const char* name
,
42 const char* extension
) {
44 internal_snprintf(path
, kMaxPathLength
, "%s/%s.%zd.%s",
45 common_flags()->coverage_dir
, name
, internal_getpid(),
49 static void WriteModuleCoverage(char* file_path
, const char* module_name
,
50 const uptr
* pcs
, uptr len
) {
51 GetCoverageFilename(file_path
, StripModuleName(module_name
), "sancov");
52 fd_t fd
= OpenFile(file_path
);
53 WriteToFile(fd
, &Magic
, sizeof(Magic
));
54 WriteToFile(fd
, pcs
, len
* sizeof(*pcs
));
56 Printf("SanitizerCoverage: %s: %zd PCs written\n", file_path
, len
);
59 static void SanitizerDumpCoverage(const uptr
* unsorted_pcs
, uptr len
) {
62 char* file_path
= static_cast<char*>(InternalAlloc(kMaxPathLength
));
63 char* module_name
= static_cast<char*>(InternalAlloc(kMaxPathLength
));
64 uptr
* pcs
= static_cast<uptr
*>(InternalAlloc(len
* sizeof(uptr
)));
66 internal_memcpy(pcs
, unsorted_pcs
, len
* sizeof(uptr
));
69 bool module_found
= false;
71 uptr module_start_idx
= 0;
73 for (uptr i
= 0; i
< len
; ++i
) {
74 const uptr pc
= pcs
[i
];
77 if (!GetModuleAndOffsetForPc(pc
, nullptr, 0, &pcs
[i
])) {
78 Printf("ERROR: unknown pc 0x%zx (may happen if dlclose is used)\n", pc
);
81 uptr module_base
= pc
- pcs
[i
];
83 if (module_base
!= last_base
|| !module_found
) {
85 WriteModuleCoverage(file_path
, module_name
, &pcs
[module_start_idx
],
86 i
- module_start_idx
);
89 last_base
= module_base
;
92 GetModuleAndOffsetForPc(pc
, module_name
, kMaxPathLength
, &pcs
[i
]);
97 WriteModuleCoverage(file_path
, module_name
, &pcs
[module_start_idx
],
98 len
- module_start_idx
);
101 InternalFree(file_path
);
102 InternalFree(module_name
);
106 // Collects trace-pc guard coverage.
107 // This class relies on zero-initialization.
108 class TracePcGuardController
{
114 InitializeSancovFlags();
116 pc_vector
.Initialize(0);
119 void InitTracePcGuard(u32
* start
, u32
* end
) {
120 if (!initialized
) Initialize();
122 CHECK_NE(start
, end
);
124 u32 i
= pc_vector
.size();
125 for (u32
* p
= start
; p
< end
; p
++) *p
= ++i
;
129 void TracePcGuard(u32
* guard
, uptr pc
) {
132 // we start indices from 1.
133 atomic_uintptr_t
* pc_ptr
=
134 reinterpret_cast<atomic_uintptr_t
*>(&pc_vector
[idx
- 1]);
135 if (atomic_load(pc_ptr
, memory_order_relaxed
) == 0)
136 atomic_store(pc_ptr
, pc
, memory_order_relaxed
);
140 internal_memset(&pc_vector
[0], 0, sizeof(pc_vector
[0]) * pc_vector
.size());
144 if (!initialized
|| !common_flags()->coverage
) return;
145 __sanitizer_dump_coverage(pc_vector
.data(), pc_vector
.size());
150 InternalMmapVectorNoCtor
<uptr
> pc_vector
;
153 static TracePcGuardController pc_guard_controller
;
155 // A basic default implementation of callbacks for
156 // -fsanitize-coverage=inline-8bit-counters,pc-table.
157 // Use TOOL_OPTIONS (UBSAN_OPTIONS, etc) to dump the coverage data:
158 // * cov_8bit_counters_out=PATH to dump the 8bit counters.
159 // * cov_pcs_out=PATH to dump the pc table.
161 // Most users will still need to define their own callbacks for greater
163 namespace SingletonCounterCoverage
{
165 static char *counters_beg
, *counters_end
;
166 static const uptr
*pcs_beg
, *pcs_end
;
168 static void DumpCoverage() {
169 const char* file_path
= common_flags()->cov_8bit_counters_out
;
170 if (file_path
&& internal_strlen(file_path
)) {
171 fd_t fd
= OpenFile(file_path
);
172 FileCloser
file_closer(fd
);
173 uptr size
= counters_end
- counters_beg
;
174 WriteToFile(fd
, counters_beg
, size
);
175 if (common_flags()->verbosity
)
176 __sanitizer::Printf("cov_8bit_counters_out: written %zd bytes to %s\n",
179 file_path
= common_flags()->cov_pcs_out
;
180 if (file_path
&& internal_strlen(file_path
)) {
181 fd_t fd
= OpenFile(file_path
);
182 FileCloser
file_closer(fd
);
183 uptr size
= (pcs_end
- pcs_beg
) * sizeof(uptr
);
184 WriteToFile(fd
, pcs_beg
, size
);
185 if (common_flags()->verbosity
)
186 __sanitizer::Printf("cov_pcs_out: written %zd bytes to %s\n", size
,
191 static void Cov8bitCountersInit(char* beg
, char* end
) {
194 Atexit(DumpCoverage
);
197 static void CovPcsInit(const uptr
* beg
, const uptr
* end
) {
202 } // namespace SingletonCounterCoverage
205 } // namespace __sancov
207 namespace __sanitizer
{
208 void InitializeCoverage(bool enabled
, const char *dir
) {
209 static bool coverage_enabled
= false;
210 if (coverage_enabled
)
211 return; // May happen if two sanitizer enable coverage in the same process.
212 coverage_enabled
= enabled
;
213 Atexit(__sanitizer_cov_dump
);
214 AddDieCallback(__sanitizer_cov_dump
);
216 } // namespace __sanitizer
219 SANITIZER_INTERFACE_ATTRIBUTE
void __sanitizer_dump_coverage(const uptr
* pcs
,
221 return __sancov::SanitizerDumpCoverage(pcs
, len
);
224 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard
, u32
* guard
) {
226 __sancov::pc_guard_controller
.TracePcGuard(
227 guard
, StackTrace::GetPreviousInstructionPc(GET_CALLER_PC()));
230 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard_init
,
231 u32
* start
, u32
* end
) {
232 if (start
== end
|| *start
) return;
233 __sancov::pc_guard_controller
.InitTracePcGuard(start
, end
);
236 SANITIZER_INTERFACE_ATTRIBUTE
void __sanitizer_dump_trace_pc_guard_coverage() {
237 __sancov::pc_guard_controller
.Dump();
239 SANITIZER_INTERFACE_ATTRIBUTE
void __sanitizer_cov_dump() {
240 __sanitizer_dump_trace_pc_guard_coverage();
242 SANITIZER_INTERFACE_ATTRIBUTE
void __sanitizer_cov_reset() {
243 __sancov::pc_guard_controller
.Reset();
245 // Default implementations (weak).
246 // Either empty or very simple.
247 // Most users should redefine them.
248 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp
, void) {}
249 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp1
, void) {}
250 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp2
, void) {}
251 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp4
, void) {}
252 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp8
, void) {}
253 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp1
, void) {}
254 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp2
, void) {}
255 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp4
, void) {}
256 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp8
, void) {}
257 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_switch
, void) {}
258 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div4
, void) {}
259 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div8
, void) {}
260 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_gep
, void) {}
261 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir
, void) {}
262 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_load1
, void){}
263 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_load2
, void){}
264 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_load4
, void){}
265 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_load8
, void){}
266 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_load16
, void){}
267 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_store1
, void){}
268 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_store2
, void){}
269 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_store4
, void){}
270 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_store8
, void){}
271 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_store16
, void){}
272 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_8bit_counters_init
,
273 char* start
, char* end
) {
274 __sancov::SingletonCounterCoverage::Cov8bitCountersInit(start
, end
);
276 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_bool_flag_init
, void) {}
277 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_pcs_init
, const uptr
* beg
,
279 __sancov::SingletonCounterCoverage::CovPcsInit(beg
, end
);
282 // Weak definition for code instrumented with -fsanitize-coverage=stack-depth
283 // and later linked with code containing a strong definition.
284 // E.g., -fsanitize=fuzzer-no-link
285 // FIXME: Update Apple deployment target so that thread_local is always
286 // supported, and remove the #if.
287 // FIXME: Figure out how this should work on Windows, exported thread_local
288 // symbols are not supported:
289 // "data with thread storage duration may not have dll interface"
290 #if !SANITIZER_APPLE && !SANITIZER_WINDOWS
291 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
292 thread_local uptr __sancov_lowest_stack
;
295 #endif // !SANITIZER_FUCHSIA