forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			137 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			137 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===-- 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
 |