1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
|
//===-- 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
|