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