137 lines · cpp
1//===-- stats.cpp ---------------------------------------------------------===//2//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-exception6//7//===----------------------------------------------------------------------===//8//9// Sanitizer statistics gathering. Manages statistics for a process and is10// responsible for writing the report file.11//12//===----------------------------------------------------------------------===//13 14#include "sanitizer_common/sanitizer_common.h"15#include "sanitizer_common/sanitizer_file.h"16#include "sanitizer_common/sanitizer_internal_defs.h"17#if SANITIZER_POSIX18#include "sanitizer_common/sanitizer_posix.h"19#endif20#include "sanitizer_common/sanitizer_symbolizer.h"21#include "stats/stats.h"22#if SANITIZER_POSIX23#include <signal.h>24#endif25 26using namespace __sanitizer;27 28namespace {29 30InternalMmapVectorNoCtor<StatModule **> modules;31StaticSpinMutex modules_mutex;32 33fd_t stats_fd;34 35void WriteLE(fd_t fd, uptr val) {36 char chars[sizeof(uptr)];37 for (unsigned i = 0; i != sizeof(uptr); ++i) {38 chars[i] = val >> (i * 8);39 }40 WriteToFile(fd, chars, sizeof(uptr));41}42 43void OpenStatsFile(const char *path_env) {44 InternalMmapVector<char> path(kMaxPathLength);45 SubstituteForFlagValue(path_env, path.data(), kMaxPathLength);46 47 error_t err;48 stats_fd = OpenFile(path.data(), WrOnly, &err);49 if (stats_fd == kInvalidFd) {50 Report("stats: failed to open %s for writing (reason: %d)\n", path.data(),51 err);52 return;53 }54 char sizeof_uptr = sizeof(uptr);55 WriteToFile(stats_fd, &sizeof_uptr, 1);56}57 58void WriteModuleReport(StatModule **smodp) {59 CHECK(smodp);60 const char *path_env = GetEnv("SANITIZER_STATS_PATH");61 if (!path_env || stats_fd == kInvalidFd)62 return;63 if (!stats_fd)64 OpenStatsFile(path_env);65 const LoadedModule *mod = Symbolizer::GetOrInit()->FindModuleForAddress(66 reinterpret_cast<uptr>(smodp));67 WriteToFile(stats_fd, mod->full_name(),68 internal_strlen(mod->full_name()) + 1);69 for (StatModule *smod = *smodp; smod; smod = smod->next) {70 for (u32 i = 0; i != smod->size; ++i) {71 StatInfo *s = &smod->infos[i];72 if (!s->addr)73 continue;74 WriteLE(stats_fd, s->addr - mod->base_address());75 WriteLE(stats_fd, s->data);76 }77 }78 WriteLE(stats_fd, 0);79 WriteLE(stats_fd, 0);80}81 82} // namespace83 84extern "C"85SANITIZER_INTERFACE_ATTRIBUTE86unsigned __sanitizer_stats_register(StatModule **mod) {87 SpinMutexLock l(&modules_mutex);88 modules.push_back(mod);89 return modules.size() - 1;90}91 92extern "C"93SANITIZER_INTERFACE_ATTRIBUTE94void __sanitizer_stats_unregister(unsigned index) {95 SpinMutexLock l(&modules_mutex);96 WriteModuleReport(modules[index]);97 modules[index] = 0;98}99 100namespace {101 102void WriteFullReport() {103 SpinMutexLock l(&modules_mutex);104 for (StatModule **mod : modules) {105 if (!mod)106 continue;107 WriteModuleReport(mod);108 }109 if (stats_fd != 0 && stats_fd != kInvalidFd) {110 CloseFile(stats_fd);111 stats_fd = kInvalidFd;112 }113}114 115#if SANITIZER_POSIX116void USR2Handler(int sig) {117 WriteFullReport();118}119#endif120 121struct WriteReportOnExitOrSignal {122 WriteReportOnExitOrSignal() {123#if SANITIZER_POSIX124 struct sigaction sigact;125 internal_memset(&sigact, 0, sizeof(sigact));126 sigact.sa_handler = USR2Handler;127 internal_sigaction(SIGUSR2, &sigact, nullptr);128#endif129 }130 131 ~WriteReportOnExitOrSignal() {132 WriteFullReport();133 }134} wr;135 136} // namespace137