Home | History | Annotate | Line # | Download | only in stats
      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_internal_defs.h"
     17 #if SANITIZER_POSIX
     18 #include "sanitizer_common/sanitizer_posix.h"
     19 #endif
     20 #include "sanitizer_common/sanitizer_symbolizer.h"
     21 #include "stats/stats.h"
     22 #if SANITIZER_POSIX
     23 #include <signal.h>
     24 #endif
     25 
     26 using namespace __sanitizer;
     27 
     28 namespace {
     29 
     30 InternalMmapVectorNoCtor<StatModule **> modules;
     31 StaticSpinMutex modules_mutex;
     32 
     33 fd_t stats_fd;
     34 
     35 void WriteLE(fd_t fd, uptr val) {
     36   char chars[sizeof(uptr)];
     37   for (unsigned i = 0; i != sizeof(uptr); ++i) {
     38     chars[i] = val >> (i * 8);
     39   }
     40   WriteToFile(fd, chars, sizeof(uptr));
     41 }
     42 
     43 void OpenStatsFile(const char *path_env) {
     44   InternalScopedBuffer<char> path(kMaxPathLength);
     45   SubstituteForFlagValue(path_env, path.data(), kMaxPathLength);
     46 
     47   error_t err;
     48   stats_fd = OpenFile(path.data(), WrOnly, &err);
     49   if (stats_fd == kInvalidFd) {
     50     Report("stats: failed to open %s for writing (reason: %d)\n", path.data(),
     51            err);
     52     return;
     53   }
     54   char sizeof_uptr = sizeof(uptr);
     55   WriteToFile(stats_fd, &sizeof_uptr, 1);
     56 }
     57 
     58 void WriteModuleReport(StatModule **smodp) {
     59   CHECK(smodp);
     60   const char *path_env = GetEnv("SANITIZER_STATS_PATH");
     61   if (!path_env || stats_fd == kInvalidFd)
     62     return;
     63   if (!stats_fd)
     64     OpenStatsFile(path_env);
     65   LoadedModule *mod = Symbolizer::GetOrInit()->FindModuleForAddress(
     66       reinterpret_cast<uptr>(smodp));
     67   WriteToFile(stats_fd, mod->full_name(),
     68               internal_strlen(mod->full_name()) + 1);
     69   for (StatModule *smod = *smodp; smod; smod = smod->next) {
     70     for (u32 i = 0; i != smod->size; ++i) {
     71       StatInfo *s = &smod->infos[i];
     72       if (!s->addr)
     73         continue;
     74       WriteLE(stats_fd, s->addr - mod->base_address());
     75       WriteLE(stats_fd, s->data);
     76     }
     77   }
     78   WriteLE(stats_fd, 0);
     79   WriteLE(stats_fd, 0);
     80 }
     81 
     82 } // namespace
     83 
     84 extern "C"
     85 SANITIZER_INTERFACE_ATTRIBUTE
     86 unsigned __sanitizer_stats_register(StatModule **mod) {
     87   SpinMutexLock l(&modules_mutex);
     88   modules.push_back(mod);
     89   return modules.size() - 1;
     90 }
     91 
     92 extern "C"
     93 SANITIZER_INTERFACE_ATTRIBUTE
     94 void __sanitizer_stats_unregister(unsigned index) {
     95   SpinMutexLock l(&modules_mutex);
     96   WriteModuleReport(modules[index]);
     97   modules[index] = 0;
     98 }
     99 
    100 namespace {
    101 
    102 void WriteFullReport() {
    103   SpinMutexLock l(&modules_mutex);
    104   for (StatModule **mod : modules) {
    105     if (!mod)
    106       continue;
    107     WriteModuleReport(mod);
    108   }
    109   if (stats_fd != 0 && stats_fd != kInvalidFd) {
    110     CloseFile(stats_fd);
    111     stats_fd = kInvalidFd;
    112   }
    113 }
    114 
    115 #if SANITIZER_POSIX
    116 void USR2Handler(int sig) {
    117   WriteFullReport();
    118 }
    119 #endif
    120 
    121 struct WriteReportOnExitOrSignal {
    122   WriteReportOnExitOrSignal() {
    123 #if SANITIZER_POSIX
    124     struct sigaction sigact;
    125     internal_memset(&sigact, 0, sizeof(sigact));
    126     sigact.sa_handler = USR2Handler;
    127     internal_sigaction(SIGUSR2, &sigact, nullptr);
    128 #endif
    129   }
    130 
    131   ~WriteReportOnExitOrSignal() {
    132     WriteFullReport();
    133   }
    134 } wr;
    135 
    136 } // namespace
    137