blob: c7a9a38a612a49f21c3801cf11300493166640ac [file] [log] [blame]
Peter Collingbourne5788e122016-01-16 00:31:29 +00001//===-- 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"
Vitaly Bukad4abe9e2017-07-22 01:46:40 +000016#include "sanitizer_common/sanitizer_file.h"
Peter Collingbourne5788e122016-01-16 00:31:29 +000017#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
27using namespace __sanitizer;
28
29namespace {
30
31InternalMmapVectorNoCtor<StatModule **> modules;
32StaticSpinMutex modules_mutex;
33
34fd_t stats_fd;
35
36void 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
44void OpenStatsFile(const char *path_env) {
Vitaly Buka2a209552018-05-07 05:56:36 +000045 InternalMmapVector<char> path(kMaxPathLength);
Peter Collingbourne5788e122016-01-16 00:31:29 +000046 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
59void 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);
Alexey Samsonov8e3cbde2016-02-22 18:52:51 +000066 const LoadedModule *mod = Symbolizer::GetOrInit()->FindModuleForAddress(
Peter Collingbourne5788e122016-01-16 00:31:29 +000067 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
85extern "C"
86SANITIZER_INTERFACE_ATTRIBUTE
87unsigned __sanitizer_stats_register(StatModule **mod) {
88 SpinMutexLock l(&modules_mutex);
89 modules.push_back(mod);
90 return modules.size() - 1;
91}
92
93extern "C"
94SANITIZER_INTERFACE_ATTRIBUTE
95void __sanitizer_stats_unregister(unsigned index) {
96 SpinMutexLock l(&modules_mutex);
97 WriteModuleReport(modules[index]);
98 modules[index] = 0;
99}
100
101namespace {
102
103void 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
117void USR2Handler(int sig) {
118 WriteFullReport();
119}
120#endif
121
122struct 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