You've already forked linux-packaging-mono
							
							
		
			
				
	
	
		
			135 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			135 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| //===-- working_set_posix.cpp -----------------------------------*- C++ -*-===//
 | |
| //
 | |
| //                     The LLVM Compiler Infrastructure
 | |
| //
 | |
| // This file is distributed under the University of Illinois Open Source
 | |
| // License. See LICENSE.TXT for details.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| //
 | |
| // This file is a part of EfficiencySanitizer, a family of performance tuners.
 | |
| //
 | |
| // POSIX-specific working set tool code.
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #include "working_set.h"
 | |
| #include "esan_flags.h"
 | |
| #include "esan_shadow.h"
 | |
| #include "sanitizer_common/sanitizer_common.h"
 | |
| #include "sanitizer_common/sanitizer_linux.h"
 | |
| #include <signal.h>
 | |
| #include <sys/mman.h>
 | |
| 
 | |
| namespace __esan {
 | |
| 
 | |
| // We only support regular POSIX threads with a single signal handler
 | |
| // for the whole process == thread group.
 | |
| // Thus we only need to store one app signal handler.
 | |
| // FIXME: Store and use any alternate stack and signal flags set by
 | |
| // the app.  For now we just call the app handler from our handler.
 | |
| static __sanitizer_sigaction AppSigAct;
 | |
| 
 | |
| bool processWorkingSetSignal(int SigNum, void (*Handler)(int),
 | |
|                              void (**Result)(int)) {
 | |
|   VPrintf(2, "%s: %d\n", __FUNCTION__, SigNum);
 | |
|   if (SigNum == SIGSEGV) {
 | |
|     *Result = AppSigAct.handler;
 | |
|     AppSigAct.sigaction = (decltype(AppSigAct.sigaction))Handler;
 | |
|     return false; // Skip real call.
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool processWorkingSetSigaction(int SigNum, const void *ActVoid,
 | |
|                                 void *OldActVoid) {
 | |
|   VPrintf(2, "%s: %d\n", __FUNCTION__, SigNum);
 | |
|   if (SigNum == SIGSEGV) {
 | |
|     const struct sigaction *Act = (const struct sigaction *) ActVoid;
 | |
|     struct sigaction *OldAct = (struct sigaction *) OldActVoid;
 | |
|     if (OldAct)
 | |
|       internal_memcpy(OldAct, &AppSigAct, sizeof(OldAct));
 | |
|     if (Act)
 | |
|       internal_memcpy(&AppSigAct, Act, sizeof(AppSigAct));
 | |
|     return false; // Skip real call.
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool processWorkingSetSigprocmask(int How, void *Set, void *OldSet) {
 | |
|   VPrintf(2, "%s\n", __FUNCTION__);
 | |
|   // All we need to do is ensure that SIGSEGV is not blocked.
 | |
|   // FIXME: we are not fully transparent as we do not pretend that
 | |
|   // SIGSEGV is still blocked on app queries: that would require
 | |
|   // per-thread mask tracking.
 | |
|   if (Set && (How == SIG_BLOCK || How == SIG_SETMASK)) {
 | |
|     if (internal_sigismember((__sanitizer_sigset_t *)Set, SIGSEGV)) {
 | |
|       VPrintf(1, "%s: removing SIGSEGV from the blocked set\n", __FUNCTION__);
 | |
|       internal_sigdelset((__sanitizer_sigset_t *)Set, SIGSEGV);
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| static void reinstateDefaultHandler(int SigNum) {
 | |
|   __sanitizer_sigaction SigAct;
 | |
|   internal_memset(&SigAct, 0, sizeof(SigAct));
 | |
|   SigAct.sigaction = (decltype(SigAct.sigaction))SIG_DFL;
 | |
|   int Res = internal_sigaction(SigNum, &SigAct, nullptr);
 | |
|   CHECK(Res == 0);
 | |
|   VPrintf(1, "Unregistered for %d handler\n", SigNum);
 | |
| }
 | |
| 
 | |
| // If this is a shadow fault, we handle it here; otherwise, we pass it to the
 | |
| // app to handle it just as the app would do without our tool in place.
 | |
| static void handleMemoryFault(int SigNum, __sanitizer_siginfo *Info,
 | |
|                               void *Ctx) {
 | |
|   if (SigNum == SIGSEGV) {
 | |
|     // We rely on si_addr being filled in (thus we do not support old kernels).
 | |
|     siginfo_t *SigInfo = (siginfo_t *)Info;
 | |
|     uptr Addr = (uptr)SigInfo->si_addr;
 | |
|     if (isShadowMem(Addr)) {
 | |
|       VPrintf(3, "Shadow fault @%p\n", Addr);
 | |
|       uptr PageSize = GetPageSizeCached();
 | |
|       int Res = internal_mprotect((void *)RoundDownTo(Addr, PageSize),
 | |
|                                   PageSize, PROT_READ|PROT_WRITE);
 | |
|       CHECK(Res == 0);
 | |
|     } else if (AppSigAct.sigaction) {
 | |
|       // FIXME: For simplicity we ignore app options including its signal stack
 | |
|       // (we just use ours) and all the delivery flags.
 | |
|       AppSigAct.sigaction(SigNum, Info, Ctx);
 | |
|     } else {
 | |
|       // Crash instead of spinning with infinite faults.
 | |
|       reinstateDefaultHandler(SigNum);
 | |
|     }
 | |
|   } else
 | |
|     UNREACHABLE("signal not registered");
 | |
| }
 | |
| 
 | |
| void registerMemoryFaultHandler() {
 | |
|   // We do not use an alternate signal stack, as doing so would require
 | |
|   // setting it up for each app thread.
 | |
|   // FIXME: This could result in problems with emulating the app's signal
 | |
|   // handling if the app relies on an alternate stack for SIGSEGV.
 | |
| 
 | |
|   // We require that SIGSEGV is not blocked.  We use a sigprocmask
 | |
|   // interceptor to ensure that in the future.  Here we ensure it for
 | |
|   // the current thread.  We assume there are no other threads at this
 | |
|   // point during initialization, or that at least they do not block
 | |
|   // SIGSEGV.
 | |
|   __sanitizer_sigset_t SigSet;
 | |
|   internal_sigemptyset(&SigSet);
 | |
|   internal_sigprocmask(SIG_BLOCK, &SigSet, nullptr);
 | |
| 
 | |
|   __sanitizer_sigaction SigAct;
 | |
|   internal_memset(&SigAct, 0, sizeof(SigAct));
 | |
|   SigAct.sigaction = handleMemoryFault;
 | |
|   // We want to handle nested signals b/c we need to handle a
 | |
|   // shadow fault in an app signal handler.
 | |
|   SigAct.sa_flags = SA_SIGINFO | SA_NODEFER;
 | |
|   int Res = internal_sigaction(SIGSEGV, &SigAct, &AppSigAct);
 | |
|   CHECK(Res == 0);
 | |
|   VPrintf(1, "Registered for SIGSEGV handler\n");
 | |
| }
 | |
| 
 | |
| } // namespace __esan
 |