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