168d75effSDimitry Andric //===-- sanitizer_coverage_libcdep_new.cpp --------------------------------===// 268d75effSDimitry Andric // 368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 668d75effSDimitry Andric // 768d75effSDimitry Andric //===----------------------------------------------------------------------===// 868d75effSDimitry Andric // Sanitizer Coverage Controller for Trace PC Guard. 968d75effSDimitry Andric 1068d75effSDimitry Andric #include "sanitizer_platform.h" 1168d75effSDimitry Andric 1268d75effSDimitry Andric #if !SANITIZER_FUCHSIA 1368d75effSDimitry Andric # include "sancov_flags.h" 1468d75effSDimitry Andric # include "sanitizer_allocator_internal.h" 1568d75effSDimitry Andric # include "sanitizer_atomic.h" 1668d75effSDimitry Andric # include "sanitizer_common.h" 1781ad6265SDimitry Andric # include "sanitizer_common/sanitizer_stacktrace.h" 1868d75effSDimitry Andric # include "sanitizer_file.h" 1981ad6265SDimitry Andric # include "sanitizer_interface_internal.h" 2068d75effSDimitry Andric 2168d75effSDimitry Andric using namespace __sanitizer; 2268d75effSDimitry Andric 2368d75effSDimitry Andric using AddressRange = LoadedModule::AddressRange; 2468d75effSDimitry Andric 2568d75effSDimitry Andric namespace __sancov { 2668d75effSDimitry Andric namespace { 2768d75effSDimitry Andric 2868d75effSDimitry Andric static const u64 Magic64 = 0xC0BFFFFFFFFFFF64ULL; 2968d75effSDimitry Andric static const u64 Magic32 = 0xC0BFFFFFFFFFFF32ULL; 3068d75effSDimitry Andric static const u64 Magic = SANITIZER_WORDSIZE == 64 ? Magic64 : Magic32; 3168d75effSDimitry Andric 3268d75effSDimitry Andric static fd_t OpenFile(const char* path) { 3368d75effSDimitry Andric error_t err; 3468d75effSDimitry Andric fd_t fd = OpenFile(path, WrOnly, &err); 3568d75effSDimitry Andric if (fd == kInvalidFd) 3668d75effSDimitry Andric Report("SanitizerCoverage: failed to open %s for writing (reason: %d)\n", 3768d75effSDimitry Andric path, err); 3868d75effSDimitry Andric return fd; 3968d75effSDimitry Andric } 4068d75effSDimitry Andric 4168d75effSDimitry Andric static void GetCoverageFilename(char* path, const char* name, 4268d75effSDimitry Andric const char* extension) { 4368d75effSDimitry Andric CHECK(name); 4468d75effSDimitry Andric internal_snprintf(path, kMaxPathLength, "%s/%s.%zd.%s", 4568d75effSDimitry Andric common_flags()->coverage_dir, name, internal_getpid(), 4668d75effSDimitry Andric extension); 4768d75effSDimitry Andric } 4868d75effSDimitry Andric 4968d75effSDimitry Andric static void WriteModuleCoverage(char* file_path, const char* module_name, 5068d75effSDimitry Andric const uptr* pcs, uptr len) { 5168d75effSDimitry Andric GetCoverageFilename(file_path, StripModuleName(module_name), "sancov"); 5268d75effSDimitry Andric fd_t fd = OpenFile(file_path); 5368d75effSDimitry Andric WriteToFile(fd, &Magic, sizeof(Magic)); 5468d75effSDimitry Andric WriteToFile(fd, pcs, len * sizeof(*pcs)); 5568d75effSDimitry Andric CloseFile(fd); 5668d75effSDimitry Andric Printf("SanitizerCoverage: %s: %zd PCs written\n", file_path, len); 5768d75effSDimitry Andric } 5868d75effSDimitry Andric 5968d75effSDimitry Andric static void SanitizerDumpCoverage(const uptr* unsorted_pcs, uptr len) { 6068d75effSDimitry Andric if (!len) return; 6168d75effSDimitry Andric 6268d75effSDimitry Andric char* file_path = static_cast<char*>(InternalAlloc(kMaxPathLength)); 6368d75effSDimitry Andric char* module_name = static_cast<char*>(InternalAlloc(kMaxPathLength)); 6468d75effSDimitry Andric uptr* pcs = static_cast<uptr*>(InternalAlloc(len * sizeof(uptr))); 6568d75effSDimitry Andric 6668d75effSDimitry Andric internal_memcpy(pcs, unsorted_pcs, len * sizeof(uptr)); 6768d75effSDimitry Andric Sort(pcs, len); 6868d75effSDimitry Andric 6968d75effSDimitry Andric bool module_found = false; 7068d75effSDimitry Andric uptr last_base = 0; 7168d75effSDimitry Andric uptr module_start_idx = 0; 7268d75effSDimitry Andric 7368d75effSDimitry Andric for (uptr i = 0; i < len; ++i) { 7468d75effSDimitry Andric const uptr pc = pcs[i]; 7568d75effSDimitry Andric if (!pc) continue; 7668d75effSDimitry Andric 7781ad6265SDimitry Andric if (!GetModuleAndOffsetForPc(pc, nullptr, 0, &pcs[i])) { 78*0fca6ea1SDimitry Andric Printf("ERROR: unknown pc %p (may happen if dlclose is used)\n", 79*0fca6ea1SDimitry Andric (void*)pc); 8068d75effSDimitry Andric continue; 8168d75effSDimitry Andric } 8268d75effSDimitry Andric uptr module_base = pc - pcs[i]; 8368d75effSDimitry Andric 8468d75effSDimitry Andric if (module_base != last_base || !module_found) { 8568d75effSDimitry Andric if (module_found) { 8668d75effSDimitry Andric WriteModuleCoverage(file_path, module_name, &pcs[module_start_idx], 8768d75effSDimitry Andric i - module_start_idx); 8868d75effSDimitry Andric } 8968d75effSDimitry Andric 9068d75effSDimitry Andric last_base = module_base; 9168d75effSDimitry Andric module_start_idx = i; 9268d75effSDimitry Andric module_found = true; 9381ad6265SDimitry Andric GetModuleAndOffsetForPc(pc, module_name, kMaxPathLength, &pcs[i]); 9468d75effSDimitry Andric } 9568d75effSDimitry Andric } 9668d75effSDimitry Andric 9768d75effSDimitry Andric if (module_found) { 9868d75effSDimitry Andric WriteModuleCoverage(file_path, module_name, &pcs[module_start_idx], 9968d75effSDimitry Andric len - module_start_idx); 10068d75effSDimitry Andric } 10168d75effSDimitry Andric 10268d75effSDimitry Andric InternalFree(file_path); 10368d75effSDimitry Andric InternalFree(module_name); 10468d75effSDimitry Andric InternalFree(pcs); 10568d75effSDimitry Andric } 10668d75effSDimitry Andric 10768d75effSDimitry Andric // Collects trace-pc guard coverage. 10868d75effSDimitry Andric // This class relies on zero-initialization. 10968d75effSDimitry Andric class TracePcGuardController { 11068d75effSDimitry Andric public: 11168d75effSDimitry Andric void Initialize() { 11268d75effSDimitry Andric CHECK(!initialized); 11368d75effSDimitry Andric 11468d75effSDimitry Andric initialized = true; 11568d75effSDimitry Andric InitializeSancovFlags(); 11668d75effSDimitry Andric 11768d75effSDimitry Andric pc_vector.Initialize(0); 11868d75effSDimitry Andric } 11968d75effSDimitry Andric 12068d75effSDimitry Andric void InitTracePcGuard(u32* start, u32* end) { 12168d75effSDimitry Andric if (!initialized) Initialize(); 12268d75effSDimitry Andric CHECK(!*start); 12368d75effSDimitry Andric CHECK_NE(start, end); 12468d75effSDimitry Andric 12568d75effSDimitry Andric u32 i = pc_vector.size(); 12668d75effSDimitry Andric for (u32* p = start; p < end; p++) *p = ++i; 12768d75effSDimitry Andric pc_vector.resize(i); 12868d75effSDimitry Andric } 12968d75effSDimitry Andric 13068d75effSDimitry Andric void TracePcGuard(u32* guard, uptr pc) { 13168d75effSDimitry Andric u32 idx = *guard; 13268d75effSDimitry Andric if (!idx) return; 13368d75effSDimitry Andric // we start indices from 1. 13468d75effSDimitry Andric atomic_uintptr_t* pc_ptr = 13568d75effSDimitry Andric reinterpret_cast<atomic_uintptr_t*>(&pc_vector[idx - 1]); 13668d75effSDimitry Andric if (atomic_load(pc_ptr, memory_order_relaxed) == 0) 13768d75effSDimitry Andric atomic_store(pc_ptr, pc, memory_order_relaxed); 13868d75effSDimitry Andric } 13968d75effSDimitry Andric 14068d75effSDimitry Andric void Reset() { 14168d75effSDimitry Andric internal_memset(&pc_vector[0], 0, sizeof(pc_vector[0]) * pc_vector.size()); 14268d75effSDimitry Andric } 14368d75effSDimitry Andric 14468d75effSDimitry Andric void Dump() { 14568d75effSDimitry Andric if (!initialized || !common_flags()->coverage) return; 14668d75effSDimitry Andric __sanitizer_dump_coverage(pc_vector.data(), pc_vector.size()); 14768d75effSDimitry Andric } 14868d75effSDimitry Andric 14968d75effSDimitry Andric private: 15068d75effSDimitry Andric bool initialized; 15168d75effSDimitry Andric InternalMmapVectorNoCtor<uptr> pc_vector; 15268d75effSDimitry Andric }; 15368d75effSDimitry Andric 15468d75effSDimitry Andric static TracePcGuardController pc_guard_controller; 15568d75effSDimitry Andric 156349cc55cSDimitry Andric // A basic default implementation of callbacks for 157349cc55cSDimitry Andric // -fsanitize-coverage=inline-8bit-counters,pc-table. 158349cc55cSDimitry Andric // Use TOOL_OPTIONS (UBSAN_OPTIONS, etc) to dump the coverage data: 159349cc55cSDimitry Andric // * cov_8bit_counters_out=PATH to dump the 8bit counters. 160349cc55cSDimitry Andric // * cov_pcs_out=PATH to dump the pc table. 161349cc55cSDimitry Andric // 162349cc55cSDimitry Andric // Most users will still need to define their own callbacks for greater 163349cc55cSDimitry Andric // flexibility. 164349cc55cSDimitry Andric namespace SingletonCounterCoverage { 165349cc55cSDimitry Andric 166349cc55cSDimitry Andric static char *counters_beg, *counters_end; 167349cc55cSDimitry Andric static const uptr *pcs_beg, *pcs_end; 168349cc55cSDimitry Andric 169349cc55cSDimitry Andric static void DumpCoverage() { 170349cc55cSDimitry Andric const char* file_path = common_flags()->cov_8bit_counters_out; 171349cc55cSDimitry Andric if (file_path && internal_strlen(file_path)) { 172349cc55cSDimitry Andric fd_t fd = OpenFile(file_path); 173349cc55cSDimitry Andric FileCloser file_closer(fd); 174349cc55cSDimitry Andric uptr size = counters_end - counters_beg; 175349cc55cSDimitry Andric WriteToFile(fd, counters_beg, size); 176349cc55cSDimitry Andric if (common_flags()->verbosity) 177349cc55cSDimitry Andric __sanitizer::Printf("cov_8bit_counters_out: written %zd bytes to %s\n", 178349cc55cSDimitry Andric size, file_path); 179349cc55cSDimitry Andric } 180349cc55cSDimitry Andric file_path = common_flags()->cov_pcs_out; 181349cc55cSDimitry Andric if (file_path && internal_strlen(file_path)) { 182349cc55cSDimitry Andric fd_t fd = OpenFile(file_path); 183349cc55cSDimitry Andric FileCloser file_closer(fd); 184349cc55cSDimitry Andric uptr size = (pcs_end - pcs_beg) * sizeof(uptr); 185349cc55cSDimitry Andric WriteToFile(fd, pcs_beg, size); 186349cc55cSDimitry Andric if (common_flags()->verbosity) 187349cc55cSDimitry Andric __sanitizer::Printf("cov_pcs_out: written %zd bytes to %s\n", size, 188349cc55cSDimitry Andric file_path); 189349cc55cSDimitry Andric } 190349cc55cSDimitry Andric } 191349cc55cSDimitry Andric 192349cc55cSDimitry Andric static void Cov8bitCountersInit(char* beg, char* end) { 193349cc55cSDimitry Andric counters_beg = beg; 194349cc55cSDimitry Andric counters_end = end; 195349cc55cSDimitry Andric Atexit(DumpCoverage); 196349cc55cSDimitry Andric } 197349cc55cSDimitry Andric 198349cc55cSDimitry Andric static void CovPcsInit(const uptr* beg, const uptr* end) { 199349cc55cSDimitry Andric pcs_beg = beg; 200349cc55cSDimitry Andric pcs_end = end; 201349cc55cSDimitry Andric } 202349cc55cSDimitry Andric 203349cc55cSDimitry Andric } // namespace SingletonCounterCoverage 204349cc55cSDimitry Andric 20568d75effSDimitry Andric } // namespace 20668d75effSDimitry Andric } // namespace __sancov 20768d75effSDimitry Andric 20868d75effSDimitry Andric namespace __sanitizer { 20968d75effSDimitry Andric void InitializeCoverage(bool enabled, const char *dir) { 21068d75effSDimitry Andric static bool coverage_enabled = false; 21168d75effSDimitry Andric if (coverage_enabled) 21268d75effSDimitry Andric return; // May happen if two sanitizer enable coverage in the same process. 21368d75effSDimitry Andric coverage_enabled = enabled; 21468d75effSDimitry Andric Atexit(__sanitizer_cov_dump); 21568d75effSDimitry Andric AddDieCallback(__sanitizer_cov_dump); 21668d75effSDimitry Andric } 21768d75effSDimitry Andric } // namespace __sanitizer 21868d75effSDimitry Andric 21968d75effSDimitry Andric extern "C" { 22068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_coverage(const uptr* pcs, 22168d75effSDimitry Andric uptr len) { 22268d75effSDimitry Andric return __sancov::SanitizerDumpCoverage(pcs, len); 22368d75effSDimitry Andric } 22468d75effSDimitry Andric 22568d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard, u32* guard) { 22668d75effSDimitry Andric if (!*guard) return; 22781ad6265SDimitry Andric __sancov::pc_guard_controller.TracePcGuard( 22881ad6265SDimitry Andric guard, StackTrace::GetPreviousInstructionPc(GET_CALLER_PC())); 22968d75effSDimitry Andric } 23068d75effSDimitry Andric 23168d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard_init, 23268d75effSDimitry Andric u32* start, u32* end) { 23368d75effSDimitry Andric if (start == end || *start) return; 23468d75effSDimitry Andric __sancov::pc_guard_controller.InitTracePcGuard(start, end); 23568d75effSDimitry Andric } 23668d75effSDimitry Andric 23768d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_trace_pc_guard_coverage() { 23868d75effSDimitry Andric __sancov::pc_guard_controller.Dump(); 23968d75effSDimitry Andric } 24068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { 24168d75effSDimitry Andric __sanitizer_dump_trace_pc_guard_coverage(); 24268d75effSDimitry Andric } 24368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_reset() { 24468d75effSDimitry Andric __sancov::pc_guard_controller.Reset(); 24568d75effSDimitry Andric } 246349cc55cSDimitry Andric // Default implementations (weak). 247349cc55cSDimitry Andric // Either empty or very simple. 248349cc55cSDimitry Andric // Most users should redefine them. 24968d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp, void) {} 25068d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp1, void) {} 25168d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp2, void) {} 25268d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp4, void) {} 25368d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp8, void) {} 25468d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp1, void) {} 25568d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp2, void) {} 25668d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp4, void) {} 25768d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp8, void) {} 25868d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_switch, void) {} 25968d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div4, void) {} 26068d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div8, void) {} 26168d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_gep, void) {} 26268d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {} 263fcaf7f86SDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_load1, void){} 264fcaf7f86SDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_load2, void){} 265fcaf7f86SDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_load4, void){} 266fcaf7f86SDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_load8, void){} 267fcaf7f86SDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_load16, void){} 268fcaf7f86SDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_store1, void){} 269fcaf7f86SDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_store2, void){} 270fcaf7f86SDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_store4, void){} 271fcaf7f86SDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_store8, void){} 272fcaf7f86SDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_store16, void){} 273349cc55cSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_8bit_counters_init, 274349cc55cSDimitry Andric char* start, char* end) { 275349cc55cSDimitry Andric __sancov::SingletonCounterCoverage::Cov8bitCountersInit(start, end); 276349cc55cSDimitry Andric } 2775ffd83dbSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_bool_flag_init, void) {} 278349cc55cSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_pcs_init, const uptr* beg, 279349cc55cSDimitry Andric const uptr* end) { 280349cc55cSDimitry Andric __sancov::SingletonCounterCoverage::CovPcsInit(beg, end); 281349cc55cSDimitry Andric } 28268d75effSDimitry Andric } // extern "C" 28368d75effSDimitry Andric // Weak definition for code instrumented with -fsanitize-coverage=stack-depth 28468d75effSDimitry Andric // and later linked with code containing a strong definition. 28568d75effSDimitry Andric // E.g., -fsanitize=fuzzer-no-link 28606c3fb27SDimitry Andric // FIXME: Update Apple deployment target so that thread_local is always 28706c3fb27SDimitry Andric // supported, and remove the #if. 28806c3fb27SDimitry Andric // FIXME: Figure out how this should work on Windows, exported thread_local 28906c3fb27SDimitry Andric // symbols are not supported: 29006c3fb27SDimitry Andric // "data with thread storage duration may not have dll interface" 29106c3fb27SDimitry Andric #if !SANITIZER_APPLE && !SANITIZER_WINDOWS 29268d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE 29306c3fb27SDimitry Andric thread_local uptr __sancov_lowest_stack; 29406c3fb27SDimitry Andric #endif 29568d75effSDimitry Andric 29668d75effSDimitry Andric #endif // !SANITIZER_FUCHSIA 297