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 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 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 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 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 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 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 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 { 122*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 131*68d75effSDimitry Andric ~WriteReportOnExitOrSignal() { 132*68d75effSDimitry Andric WriteFullReport(); 133*68d75effSDimitry Andric } 134*68d75effSDimitry Andric } wr; 135*68d75effSDimitry Andric 136*68d75effSDimitry Andric } // namespace 137