reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
//===-- stats.cpp ---------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Sanitizer statistics gathering. Manages statistics for a process and is
// responsible for writing the report file.
//
//===----------------------------------------------------------------------===//

#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_file.h"
#include "sanitizer_common/sanitizer_internal_defs.h"
#if SANITIZER_POSIX
#include "sanitizer_common/sanitizer_posix.h"
#endif
#include "sanitizer_common/sanitizer_symbolizer.h"
#include "stats/stats.h"
#if SANITIZER_POSIX
#include <signal.h>
#endif

using namespace __sanitizer;

namespace {

InternalMmapVectorNoCtor<StatModule **> modules;
StaticSpinMutex modules_mutex;

fd_t stats_fd;

void WriteLE(fd_t fd, uptr val) {
  char chars[sizeof(uptr)];
  for (unsigned i = 0; i != sizeof(uptr); ++i) {
    chars[i] = val >> (i * 8);
  }
  WriteToFile(fd, chars, sizeof(uptr));
}

void OpenStatsFile(const char *path_env) {
  InternalMmapVector<char> path(kMaxPathLength);
  SubstituteForFlagValue(path_env, path.data(), kMaxPathLength);

  error_t err;
  stats_fd = OpenFile(path.data(), WrOnly, &err);
  if (stats_fd == kInvalidFd) {
    Report("stats: failed to open %s for writing (reason: %d)\n", path.data(),
           err);
    return;
  }
  char sizeof_uptr = sizeof(uptr);
  WriteToFile(stats_fd, &sizeof_uptr, 1);
}

void WriteModuleReport(StatModule **smodp) {
  CHECK(smodp);
  const char *path_env = GetEnv("SANITIZER_STATS_PATH");
  if (!path_env || stats_fd == kInvalidFd)
    return;
  if (!stats_fd)
    OpenStatsFile(path_env);
  const LoadedModule *mod = Symbolizer::GetOrInit()->FindModuleForAddress(
      reinterpret_cast<uptr>(smodp));
  WriteToFile(stats_fd, mod->full_name(),
              internal_strlen(mod->full_name()) + 1);
  for (StatModule *smod = *smodp; smod; smod = smod->next) {
    for (u32 i = 0; i != smod->size; ++i) {
      StatInfo *s = &smod->infos[i];
      if (!s->addr)
        continue;
      WriteLE(stats_fd, s->addr - mod->base_address());
      WriteLE(stats_fd, s->data);
    }
  }
  WriteLE(stats_fd, 0);
  WriteLE(stats_fd, 0);
}

} // namespace

extern "C"
SANITIZER_INTERFACE_ATTRIBUTE
unsigned __sanitizer_stats_register(StatModule **mod) {
  SpinMutexLock l(&modules_mutex);
  modules.push_back(mod);
  return modules.size() - 1;
}

extern "C"
SANITIZER_INTERFACE_ATTRIBUTE
void __sanitizer_stats_unregister(unsigned index) {
  SpinMutexLock l(&modules_mutex);
  WriteModuleReport(modules[index]);
  modules[index] = 0;
}

namespace {

void WriteFullReport() {
  SpinMutexLock l(&modules_mutex);
  for (StatModule **mod : modules) {
    if (!mod)
      continue;
    WriteModuleReport(mod);
  }
  if (stats_fd != 0 && stats_fd != kInvalidFd) {
    CloseFile(stats_fd);
    stats_fd = kInvalidFd;
  }
}

#if SANITIZER_POSIX
void USR2Handler(int sig) {
  WriteFullReport();
}
#endif

struct WriteReportOnExitOrSignal {
  WriteReportOnExitOrSignal() {
#if SANITIZER_POSIX
    struct sigaction sigact;
    internal_memset(&sigact, 0, sizeof(sigact));
    sigact.sa_handler = USR2Handler;
    internal_sigaction(SIGUSR2, &sigact, nullptr);
#endif
  }

  ~WriteReportOnExitOrSignal() {
    WriteFullReport();
  }
} wr;

} // namespace