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