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