1*7c3d14c8STreehugger Robot //===-- stats.cc ----------------------------------------------------------===//
2*7c3d14c8STreehugger Robot //
3*7c3d14c8STreehugger Robot // The LLVM Compiler Infrastructure
4*7c3d14c8STreehugger Robot //
5*7c3d14c8STreehugger Robot // This file is distributed under the University of Illinois Open Source
6*7c3d14c8STreehugger Robot // License. See LICENSE.TXT for details.
7*7c3d14c8STreehugger Robot //
8*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===//
9*7c3d14c8STreehugger Robot //
10*7c3d14c8STreehugger Robot // Sanitizer statistics gathering. Manages statistics for a process and is
11*7c3d14c8STreehugger Robot // responsible for writing the report file.
12*7c3d14c8STreehugger Robot //
13*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===//
14*7c3d14c8STreehugger Robot
15*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_common.h"
16*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_internal_defs.h"
17*7c3d14c8STreehugger Robot #if SANITIZER_POSIX
18*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_posix.h"
19*7c3d14c8STreehugger Robot #endif
20*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_symbolizer.h"
21*7c3d14c8STreehugger Robot #include "stats/stats.h"
22*7c3d14c8STreehugger Robot #if SANITIZER_POSIX
23*7c3d14c8STreehugger Robot #include <signal.h>
24*7c3d14c8STreehugger Robot #endif
25*7c3d14c8STreehugger Robot
26*7c3d14c8STreehugger Robot using namespace __sanitizer;
27*7c3d14c8STreehugger Robot
28*7c3d14c8STreehugger Robot namespace {
29*7c3d14c8STreehugger Robot
30*7c3d14c8STreehugger Robot InternalMmapVectorNoCtor<StatModule **> modules;
31*7c3d14c8STreehugger Robot StaticSpinMutex modules_mutex;
32*7c3d14c8STreehugger Robot
33*7c3d14c8STreehugger Robot fd_t stats_fd;
34*7c3d14c8STreehugger Robot
WriteLE(fd_t fd,uptr val)35*7c3d14c8STreehugger Robot void WriteLE(fd_t fd, uptr val) {
36*7c3d14c8STreehugger Robot char chars[sizeof(uptr)];
37*7c3d14c8STreehugger Robot for (unsigned i = 0; i != sizeof(uptr); ++i) {
38*7c3d14c8STreehugger Robot chars[i] = val >> (i * 8);
39*7c3d14c8STreehugger Robot }
40*7c3d14c8STreehugger Robot WriteToFile(fd, chars, sizeof(uptr));
41*7c3d14c8STreehugger Robot }
42*7c3d14c8STreehugger Robot
OpenStatsFile(const char * path_env)43*7c3d14c8STreehugger Robot void OpenStatsFile(const char *path_env) {
44*7c3d14c8STreehugger Robot InternalScopedBuffer<char> path(kMaxPathLength);
45*7c3d14c8STreehugger Robot SubstituteForFlagValue(path_env, path.data(), kMaxPathLength);
46*7c3d14c8STreehugger Robot
47*7c3d14c8STreehugger Robot error_t err;
48*7c3d14c8STreehugger Robot stats_fd = OpenFile(path.data(), WrOnly, &err);
49*7c3d14c8STreehugger Robot if (stats_fd == kInvalidFd) {
50*7c3d14c8STreehugger Robot Report("stats: failed to open %s for writing (reason: %d)\n", path.data(),
51*7c3d14c8STreehugger Robot err);
52*7c3d14c8STreehugger Robot return;
53*7c3d14c8STreehugger Robot }
54*7c3d14c8STreehugger Robot char sizeof_uptr = sizeof(uptr);
55*7c3d14c8STreehugger Robot WriteToFile(stats_fd, &sizeof_uptr, 1);
56*7c3d14c8STreehugger Robot }
57*7c3d14c8STreehugger Robot
WriteModuleReport(StatModule ** smodp)58*7c3d14c8STreehugger Robot void WriteModuleReport(StatModule **smodp) {
59*7c3d14c8STreehugger Robot CHECK(smodp);
60*7c3d14c8STreehugger Robot const char *path_env = GetEnv("SANITIZER_STATS_PATH");
61*7c3d14c8STreehugger Robot if (!path_env || stats_fd == kInvalidFd)
62*7c3d14c8STreehugger Robot return;
63*7c3d14c8STreehugger Robot if (!stats_fd)
64*7c3d14c8STreehugger Robot OpenStatsFile(path_env);
65*7c3d14c8STreehugger Robot const LoadedModule *mod = Symbolizer::GetOrInit()->FindModuleForAddress(
66*7c3d14c8STreehugger Robot reinterpret_cast<uptr>(smodp));
67*7c3d14c8STreehugger Robot WriteToFile(stats_fd, mod->full_name(),
68*7c3d14c8STreehugger Robot internal_strlen(mod->full_name()) + 1);
69*7c3d14c8STreehugger Robot for (StatModule *smod = *smodp; smod; smod = smod->next) {
70*7c3d14c8STreehugger Robot for (u32 i = 0; i != smod->size; ++i) {
71*7c3d14c8STreehugger Robot StatInfo *s = &smod->infos[i];
72*7c3d14c8STreehugger Robot if (!s->addr)
73*7c3d14c8STreehugger Robot continue;
74*7c3d14c8STreehugger Robot WriteLE(stats_fd, s->addr - mod->base_address());
75*7c3d14c8STreehugger Robot WriteLE(stats_fd, s->data);
76*7c3d14c8STreehugger Robot }
77*7c3d14c8STreehugger Robot }
78*7c3d14c8STreehugger Robot WriteLE(stats_fd, 0);
79*7c3d14c8STreehugger Robot WriteLE(stats_fd, 0);
80*7c3d14c8STreehugger Robot }
81*7c3d14c8STreehugger Robot
82*7c3d14c8STreehugger Robot } // namespace
83*7c3d14c8STreehugger Robot
84*7c3d14c8STreehugger Robot extern "C"
85*7c3d14c8STreehugger Robot SANITIZER_INTERFACE_ATTRIBUTE
__sanitizer_stats_register(StatModule ** mod)86*7c3d14c8STreehugger Robot unsigned __sanitizer_stats_register(StatModule **mod) {
87*7c3d14c8STreehugger Robot SpinMutexLock l(&modules_mutex);
88*7c3d14c8STreehugger Robot modules.push_back(mod);
89*7c3d14c8STreehugger Robot return modules.size() - 1;
90*7c3d14c8STreehugger Robot }
91*7c3d14c8STreehugger Robot
92*7c3d14c8STreehugger Robot extern "C"
93*7c3d14c8STreehugger Robot SANITIZER_INTERFACE_ATTRIBUTE
__sanitizer_stats_unregister(unsigned index)94*7c3d14c8STreehugger Robot void __sanitizer_stats_unregister(unsigned index) {
95*7c3d14c8STreehugger Robot SpinMutexLock l(&modules_mutex);
96*7c3d14c8STreehugger Robot WriteModuleReport(modules[index]);
97*7c3d14c8STreehugger Robot modules[index] = 0;
98*7c3d14c8STreehugger Robot }
99*7c3d14c8STreehugger Robot
100*7c3d14c8STreehugger Robot namespace {
101*7c3d14c8STreehugger Robot
WriteFullReport()102*7c3d14c8STreehugger Robot void WriteFullReport() {
103*7c3d14c8STreehugger Robot SpinMutexLock l(&modules_mutex);
104*7c3d14c8STreehugger Robot for (StatModule **mod : modules) {
105*7c3d14c8STreehugger Robot if (!mod)
106*7c3d14c8STreehugger Robot continue;
107*7c3d14c8STreehugger Robot WriteModuleReport(mod);
108*7c3d14c8STreehugger Robot }
109*7c3d14c8STreehugger Robot if (stats_fd != 0 && stats_fd != kInvalidFd) {
110*7c3d14c8STreehugger Robot CloseFile(stats_fd);
111*7c3d14c8STreehugger Robot stats_fd = kInvalidFd;
112*7c3d14c8STreehugger Robot }
113*7c3d14c8STreehugger Robot }
114*7c3d14c8STreehugger Robot
115*7c3d14c8STreehugger Robot #if SANITIZER_POSIX
USR2Handler(int sig)116*7c3d14c8STreehugger Robot void USR2Handler(int sig) {
117*7c3d14c8STreehugger Robot WriteFullReport();
118*7c3d14c8STreehugger Robot }
119*7c3d14c8STreehugger Robot #endif
120*7c3d14c8STreehugger Robot
121*7c3d14c8STreehugger Robot struct WriteReportOnExitOrSignal {
WriteReportOnExitOrSignal__anondee20c8b0211::WriteReportOnExitOrSignal122*7c3d14c8STreehugger Robot WriteReportOnExitOrSignal() {
123*7c3d14c8STreehugger Robot #if SANITIZER_POSIX
124*7c3d14c8STreehugger Robot struct sigaction sigact;
125*7c3d14c8STreehugger Robot internal_memset(&sigact, 0, sizeof(sigact));
126*7c3d14c8STreehugger Robot sigact.sa_handler = USR2Handler;
127*7c3d14c8STreehugger Robot internal_sigaction(SIGUSR2, &sigact, nullptr);
128*7c3d14c8STreehugger Robot #endif
129*7c3d14c8STreehugger Robot }
130*7c3d14c8STreehugger Robot
~WriteReportOnExitOrSignal__anondee20c8b0211::WriteReportOnExitOrSignal131*7c3d14c8STreehugger Robot ~WriteReportOnExitOrSignal() {
132*7c3d14c8STreehugger Robot WriteFullReport();
133*7c3d14c8STreehugger Robot }
134*7c3d14c8STreehugger Robot } wr;
135*7c3d14c8STreehugger Robot
136*7c3d14c8STreehugger Robot } // namespace
137