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