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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Sanitizer statistics gathering. Manages statistics for a process and is
10 // 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_POSIX
18 #include "sanitizer_common/sanitizer_posix.h"
19 #endif
20 #include "sanitizer_common/sanitizer_symbolizer.h"
21 #include "stats/stats.h"
22 #if SANITIZER_POSIX
23 #include <signal.h>
24 #endif
25 
26 using namespace __sanitizer;
27 
28 namespace {
29 
30 InternalMmapVectorNoCtor<StatModule **> modules;
31 StaticSpinMutex modules_mutex;
32 
33 fd_t stats_fd;
34 
WriteLE(fd_t fd,uptr val)35 void 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 
OpenStatsFile(const char * path_env)43 void 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 
WriteModuleReport(StatModule ** smodp)58 void 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 } // namespace
83 
84 extern "C"
85 SANITIZER_INTERFACE_ATTRIBUTE
__sanitizer_stats_register(StatModule ** mod)86 unsigned __sanitizer_stats_register(StatModule **mod) {
87   SpinMutexLock l(&modules_mutex);
88   modules.push_back(mod);
89   return modules.size() - 1;
90 }
91 
92 extern "C"
93 SANITIZER_INTERFACE_ATTRIBUTE
__sanitizer_stats_unregister(unsigned index)94 void __sanitizer_stats_unregister(unsigned index) {
95   SpinMutexLock l(&modules_mutex);
96   WriteModuleReport(modules[index]);
97   modules[index] = 0;
98 }
99 
100 namespace {
101 
WriteFullReport()102 void 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_POSIX
USR2Handler(int sig)116 void USR2Handler(int sig) {
117   WriteFullReport();
118 }
119 #endif
120 
121 struct WriteReportOnExitOrSignal {
WriteReportOnExitOrSignal__anon77a3de380211::WriteReportOnExitOrSignal122   WriteReportOnExitOrSignal() {
123 #if SANITIZER_POSIX
124     struct sigaction sigact;
125     internal_memset(&sigact, 0, sizeof(sigact));
126     sigact.sa_handler = USR2Handler;
127     internal_sigaction(SIGUSR2, &sigact, nullptr);
128 #endif
129   }
130 
~WriteReportOnExitOrSignal__anon77a3de380211::WriteReportOnExitOrSignal131   ~WriteReportOnExitOrSignal() {
132     WriteFullReport();
133   }
134 } wr;
135 
136 } // namespace
137