1353944Sdim//===-- stats.cpp ---------------------------------------------------------===//
2353944Sdim//
3353944Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353944Sdim// See https://llvm.org/LICENSE.txt for license information.
5353944Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6353944Sdim//
7353944Sdim//===----------------------------------------------------------------------===//
8353944Sdim//
9353944Sdim// Sanitizer statistics gathering. Manages statistics for a process and is
10353944Sdim// responsible for writing the report file.
11353944Sdim//
12353944Sdim//===----------------------------------------------------------------------===//
13353944Sdim
14353944Sdim#include "sanitizer_common/sanitizer_common.h"
15353944Sdim#include "sanitizer_common/sanitizer_file.h"
16353944Sdim#include "sanitizer_common/sanitizer_internal_defs.h"
17353944Sdim#if SANITIZER_POSIX
18353944Sdim#include "sanitizer_common/sanitizer_posix.h"
19353944Sdim#endif
20353944Sdim#include "sanitizer_common/sanitizer_symbolizer.h"
21353944Sdim#include "stats/stats.h"
22353944Sdim#if SANITIZER_POSIX
23353944Sdim#include <signal.h>
24353944Sdim#endif
25353944Sdim
26353944Sdimusing namespace __sanitizer;
27353944Sdim
28353944Sdimnamespace {
29353944Sdim
30353944SdimInternalMmapVectorNoCtor<StatModule **> modules;
31353944SdimStaticSpinMutex modules_mutex;
32353944Sdim
33353944Sdimfd_t stats_fd;
34353944Sdim
35353944Sdimvoid WriteLE(fd_t fd, uptr val) {
36353944Sdim  char chars[sizeof(uptr)];
37353944Sdim  for (unsigned i = 0; i != sizeof(uptr); ++i) {
38353944Sdim    chars[i] = val >> (i * 8);
39353944Sdim  }
40353944Sdim  WriteToFile(fd, chars, sizeof(uptr));
41353944Sdim}
42353944Sdim
43353944Sdimvoid OpenStatsFile(const char *path_env) {
44353944Sdim  InternalMmapVector<char> path(kMaxPathLength);
45353944Sdim  SubstituteForFlagValue(path_env, path.data(), kMaxPathLength);
46353944Sdim
47353944Sdim  error_t err;
48353944Sdim  stats_fd = OpenFile(path.data(), WrOnly, &err);
49353944Sdim  if (stats_fd == kInvalidFd) {
50353944Sdim    Report("stats: failed to open %s for writing (reason: %d)\n", path.data(),
51353944Sdim           err);
52353944Sdim    return;
53353944Sdim  }
54353944Sdim  char sizeof_uptr = sizeof(uptr);
55353944Sdim  WriteToFile(stats_fd, &sizeof_uptr, 1);
56353944Sdim}
57353944Sdim
58353944Sdimvoid WriteModuleReport(StatModule **smodp) {
59353944Sdim  CHECK(smodp);
60353944Sdim  const char *path_env = GetEnv("SANITIZER_STATS_PATH");
61353944Sdim  if (!path_env || stats_fd == kInvalidFd)
62353944Sdim    return;
63353944Sdim  if (!stats_fd)
64353944Sdim    OpenStatsFile(path_env);
65353944Sdim  const LoadedModule *mod = Symbolizer::GetOrInit()->FindModuleForAddress(
66353944Sdim      reinterpret_cast<uptr>(smodp));
67353944Sdim  WriteToFile(stats_fd, mod->full_name(),
68353944Sdim              internal_strlen(mod->full_name()) + 1);
69353944Sdim  for (StatModule *smod = *smodp; smod; smod = smod->next) {
70353944Sdim    for (u32 i = 0; i != smod->size; ++i) {
71353944Sdim      StatInfo *s = &smod->infos[i];
72353944Sdim      if (!s->addr)
73353944Sdim        continue;
74353944Sdim      WriteLE(stats_fd, s->addr - mod->base_address());
75353944Sdim      WriteLE(stats_fd, s->data);
76353944Sdim    }
77353944Sdim  }
78353944Sdim  WriteLE(stats_fd, 0);
79353944Sdim  WriteLE(stats_fd, 0);
80353944Sdim}
81353944Sdim
82353944Sdim} // namespace
83353944Sdim
84353944Sdimextern "C"
85353944SdimSANITIZER_INTERFACE_ATTRIBUTE
86353944Sdimunsigned __sanitizer_stats_register(StatModule **mod) {
87353944Sdim  SpinMutexLock l(&modules_mutex);
88353944Sdim  modules.push_back(mod);
89353944Sdim  return modules.size() - 1;
90353944Sdim}
91353944Sdim
92353944Sdimextern "C"
93353944SdimSANITIZER_INTERFACE_ATTRIBUTE
94353944Sdimvoid __sanitizer_stats_unregister(unsigned index) {
95353944Sdim  SpinMutexLock l(&modules_mutex);
96353944Sdim  WriteModuleReport(modules[index]);
97353944Sdim  modules[index] = 0;
98353944Sdim}
99353944Sdim
100353944Sdimnamespace {
101353944Sdim
102353944Sdimvoid WriteFullReport() {
103353944Sdim  SpinMutexLock l(&modules_mutex);
104353944Sdim  for (StatModule **mod : modules) {
105353944Sdim    if (!mod)
106353944Sdim      continue;
107353944Sdim    WriteModuleReport(mod);
108353944Sdim  }
109353944Sdim  if (stats_fd != 0 && stats_fd != kInvalidFd) {
110353944Sdim    CloseFile(stats_fd);
111353944Sdim    stats_fd = kInvalidFd;
112353944Sdim  }
113353944Sdim}
114353944Sdim
115353944Sdim#if SANITIZER_POSIX
116353944Sdimvoid USR2Handler(int sig) {
117353944Sdim  WriteFullReport();
118353944Sdim}
119353944Sdim#endif
120353944Sdim
121353944Sdimstruct WriteReportOnExitOrSignal {
122353944Sdim  WriteReportOnExitOrSignal() {
123353944Sdim#if SANITIZER_POSIX
124353944Sdim    struct sigaction sigact;
125353944Sdim    internal_memset(&sigact, 0, sizeof(sigact));
126353944Sdim    sigact.sa_handler = USR2Handler;
127353944Sdim    internal_sigaction(SIGUSR2, &sigact, nullptr);
128353944Sdim#endif
129353944Sdim  }
130353944Sdim
131353944Sdim  ~WriteReportOnExitOrSignal() {
132353944Sdim    WriteFullReport();
133353944Sdim  }
134353944Sdim} wr;
135353944Sdim
136353944Sdim} // namespace
137