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