Index: include/sanitizer/coverage_interface.h =================================================================== --- include/sanitizer/coverage_interface.h +++ include/sanitizer/coverage_interface.h @@ -23,6 +23,11 @@ void __sanitizer_cov_init(); // Record and dump coverage info. void __sanitizer_cov_dump(); + + // Dump collected coverage info. Sorts pcs by module into individual + // .sancov files. + void __sanitizer_dump_coverage(const uintptr_t *pcs, uintptr_t len); + // Open .sancov.packed in the coverage directory and return the file // descriptor. Returns -1 on failure, or if coverage dumping is disabled. // This is intended for use by sandboxing code. Index: lib/sanitizer_common/CMakeLists.txt =================================================================== --- lib/sanitizer_common/CMakeLists.txt +++ lib/sanitizer_common/CMakeLists.txt @@ -53,6 +53,7 @@ set(SANITIZER_LIBCDEP_SOURCES sanitizer_common_libcdep.cc sanitizer_coverage_libcdep.cc + sanitizer_coverage_libcdep_new.cc sanitizer_coverage_mapping_libcdep.cc sanitizer_linux_libcdep.cc sanitizer_posix_libcdep.cc Index: lib/sanitizer_common/sanitizer_addrhashmap.h =================================================================== --- lib/sanitizer_common/sanitizer_addrhashmap.h +++ lib/sanitizer_common/sanitizer_addrhashmap.h @@ -73,6 +73,8 @@ ~Handle(); T *operator->(); + T &operator*(); + const T &operator*() const; bool created() const; bool exists() const; @@ -136,6 +138,16 @@ return &cell_->val; } +template +const T &AddrHashMap::Handle::operator*() const { + return cell_->val; +} + +template +T &AddrHashMap::Handle::operator*() { + return cell_->val; +} + template bool AddrHashMap::Handle::created() const { return created_; Index: lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc =================================================================== --- /dev/null +++ lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc @@ -0,0 +1,128 @@ +//===-- sanitizer_coverage.cc ---------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Sanitizer Coverage. + +#include "sanitizer_addrhashmap.h" +#include "sanitizer_common.h" +#include "sanitizer_symbolizer.h" + +using namespace __sanitizer; + +using AddressRange = LoadedModule::AddressRange; + +namespace { + +static const u64 Magic64 = 0xC0BFFFFFFFFFFF64ULL; +static const u64 Magic32 = 0xC0BFFFFFFFFFFF32ULL; +static const u64 Magic = SANITIZER_WORDSIZE == 64 ? Magic64 : Magic32; + +struct ModuleAndRange { + const LoadedModule* module; + const AddressRange* range; +}; + +struct CovFile { + CovFile() : fd(-1), num_offsets(0), file_path(0) {} + + fd_t fd; + uptr num_offsets; + char* file_path; +}; + +}; // namespace + +static fd_t OpenFile(const char* path) { + error_t err; + fd_t fd = OpenFile(path, WrOnly, &err); + if (fd == kInvalidFd) + Report("SanitizerCoverage: failed to open %s for writing (reason: %d)\n", + path, err); + return fd; +} + +static void GetCoverageFilename(char* path, const char* name, + const char* extension) { + CHECK(name); + internal_snprintf(path, kMaxPathLength, "%s/%s.%zd.%s", + common_flags()->coverage_dir, name, internal_getpid(), + extension); +} + +static void SanitizerDumpCoverage(const uptr* pcs, uptr len) { + auto symbolizer = Symbolizer::GetOrInit(); + if (!symbolizer) return; + + InternalMmapVector open_files(0); + using CovFilesMap = AddrHashMap; + CovFilesMap cov_files; + + ListOfModules modules; + modules.init(); + InternalMmapVector ranges(modules.size()); + for (const LoadedModule& module : modules) { + for (const AddressRange& r : module.ranges()) { + ranges.push_back(ModuleAndRange {&module, &r}); + } + } + InternalSort(&ranges, ranges.size(), + [](const ModuleAndRange& m1, const ModuleAndRange& m2) { + return m1.range->end < m2.range->end; + }); + + for (uptr i = 0; i < len; ++i) { + const uptr pc = pcs[i]; + if (!pc) + continue; + + uptr idx = InternalBinarySearch( + ranges, 0, ranges.size(), pc, + [](const ModuleAndRange& m, uptr pc) { return pc >= m.range->end; }); + if (idx >= ranges.size()) { + Printf("ERROR: bad pc %x\n", pc); + continue; + } + + const ModuleAndRange& module_and_range = ranges[idx]; + auto module = module_and_range.module; + auto range = module_and_range.range; + + if (range->beg > pc || range->end <= pc) { + Printf("ERROR: bad pc %x\n", pc); + continue; + } + + CovFilesMap::Handle h(&cov_files, (uptr)&module); + if (h.created()) { + h->file_path = static_cast(InternalAlloc(kMaxPathLength)); + GetCoverageFilename(h->file_path, StripModuleName(module->full_name()), + "sancov"); + h->fd = OpenFile(h->file_path); + WriteToFile(h->fd, &Magic, sizeof(Magic)); + } + + const uptr offset = pc - module->base_address(); + h->num_offsets++; + WriteToFile(h->fd, &offset, sizeof(offset)); + } + + for (const LoadedModule& module : modules) { + CovFilesMap::Handle h(&cov_files, (uptr)&module); + if (h.created()) continue; + CloseFile(h->fd); + VReport(1, " CovDump: %s: %zd PCs written\n", h->file_path, h->num_offsets); + InternalFree(h->file_path); + } +} + +// clang-format off +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_coverage( // NOLINT + const uptr* pcs, uptr len) { + return SanitizerDumpCoverage(pcs, len); +} +// clang-format on Index: lib/sanitizer_common/sanitizer_interface_internal.h =================================================================== --- lib/sanitizer_common/sanitizer_interface_internal.h +++ lib/sanitizer_common/sanitizer_interface_internal.h @@ -46,8 +46,11 @@ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void __sanitizer_report_error_summary(const char *error_summary); - SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump(); SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_init(); + SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump(); + SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_coverage( + const __sanitizer::uptr *pcs, const __sanitizer::uptr len); + SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov(__sanitizer::u32 *guard); SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_annotate_contiguous_container(const void *beg,