|  | //===-- stats.cpp ---------------------------------------------------------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // 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_file.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) { | 
|  | InternalMmapVector<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 |