//===-- stats.cc ----------------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Sanitizer statistics gathering. Manages statistics for a process and is // responsible for writing the report file. // //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_internal_defs.h" #if SANITIZER_POSIX #include "sanitizer_common/sanitizer_posix.h" #endif #include "sanitizer_common/sanitizer_symbolizer.h" #include "stats/stats.h" #if SANITIZER_POSIX #include <signal.h> #endif using namespace __sanitizer; namespace { InternalMmapVectorNoCtor<StatModule **> modules; StaticSpinMutex modules_mutex; fd_t stats_fd; void WriteLE(fd_t fd, uptr val) { char chars[sizeof(uptr)]; for (unsigned i = 0; i != sizeof(uptr); ++i) { chars[i] = val >> (i * 8); } WriteToFile(fd, chars, sizeof(uptr)); } void OpenStatsFile(const char *path_env) { InternalScopedBuffer<char> path(kMaxPathLength); SubstituteForFlagValue(path_env, path.data(), kMaxPathLength); error_t err; stats_fd = OpenFile(path.data(), WrOnly, &err); if (stats_fd == kInvalidFd) { Report("stats: failed to open %s for writing (reason: %d)\n", path.data(), err); return; } char sizeof_uptr = sizeof(uptr); WriteToFile(stats_fd, &sizeof_uptr, 1); } void WriteModuleReport(StatModule **smodp) { CHECK(smodp); const char *path_env = GetEnv("SANITIZER_STATS_PATH"); if (!path_env || stats_fd == kInvalidFd) return; if (!stats_fd) OpenStatsFile(path_env); const LoadedModule *mod = Symbolizer::GetOrInit()->FindModuleForAddress( reinterpret_cast<uptr>(smodp)); WriteToFile(stats_fd, mod->full_name(), internal_strlen(mod->full_name()) + 1); for (StatModule *smod = *smodp; smod; smod = smod->next) { for (u32 i = 0; i != smod->size; ++i) { StatInfo *s = &smod->infos[i]; if (!s->addr) continue; WriteLE(stats_fd, s->addr - mod->base_address()); WriteLE(stats_fd, s->data); } } WriteLE(stats_fd, 0); WriteLE(stats_fd, 0); } } // namespace extern "C" SANITIZER_INTERFACE_ATTRIBUTE unsigned __sanitizer_stats_register(StatModule **mod) { SpinMutexLock l(&modules_mutex); modules.push_back(mod); return modules.size() - 1; } extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_stats_unregister(unsigned index) { SpinMutexLock l(&modules_mutex); WriteModuleReport(modules[index]); modules[index] = 0; } namespace { void WriteFullReport() { SpinMutexLock l(&modules_mutex); for (StatModule **mod : modules) { if (!mod) continue; WriteModuleReport(mod); } if (stats_fd != 0 && stats_fd != kInvalidFd) { CloseFile(stats_fd); stats_fd = kInvalidFd; } } #if SANITIZER_POSIX void USR2Handler(int sig) { WriteFullReport(); } #endif struct WriteReportOnExitOrSignal { WriteReportOnExitOrSignal() { #if SANITIZER_POSIX struct sigaction sigact; internal_memset(&sigact, 0, sizeof(sigact)); sigact.sa_handler = USR2Handler; internal_sigaction(SIGUSR2, &sigact, nullptr); #endif } ~WriteReportOnExitOrSignal() { WriteFullReport(); } } wr; } // namespace