]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/compiler-rt/lib/stats/stats.cc
Merge clang 7.0.1 and several follow-up changes
[FreeBSD/FreeBSD.git] / contrib / compiler-rt / lib / stats / stats.cc
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
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
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
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
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
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
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
117 void USR2Handler(int sig) {
118   WriteFullReport();
119 }
120 #endif
121
122 struct WriteReportOnExitOrSignal {
123   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
132   ~WriteReportOnExitOrSignal() {
133     WriteFullReport();
134   }
135 } wr;
136
137 } // namespace