1//===-- stats.cpp ---------------------------------------------------------===// 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===// 8// 9// Sanitizer statistics gathering. Manages statistics for a process and is 10// responsible for writing the report file. 11// 12//===----------------------------------------------------------------------===// 13 14#include "sanitizer_common/sanitizer_common.h" 15#include "sanitizer_common/sanitizer_file.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 26using namespace __sanitizer; 27 28namespace { 29 30InternalMmapVectorNoCtor<StatModule **> modules; 31StaticSpinMutex modules_mutex; 32 33fd_t stats_fd; 34 35void 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 43void OpenStatsFile(const char *path_env) { 44 InternalMmapVector<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 58void 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 const 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 84extern "C" 85SANITIZER_INTERFACE_ATTRIBUTE 86unsigned __sanitizer_stats_register(StatModule **mod) { 87 SpinMutexLock l(&modules_mutex); 88 modules.push_back(mod); 89 return modules.size() - 1; 90} 91 92extern "C" 93SANITIZER_INTERFACE_ATTRIBUTE 94void __sanitizer_stats_unregister(unsigned index) { 95 SpinMutexLock l(&modules_mutex); 96 WriteModuleReport(modules[index]); 97 modules[index] = 0; 98} 99 100namespace { 101 102void 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 116void USR2Handler(int sig) { 117 WriteFullReport(); 118} 119#endif 120 121struct 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