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 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 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 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 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 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