1 //===-- working_set_posix.cpp -----------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file is a part of EfficiencySanitizer, a family of performance tuners. 11 // 12 // POSIX-specific working set tool code. 13 //===----------------------------------------------------------------------===// 14 15 #include "working_set.h" 16 #include "esan_flags.h" 17 #include "esan_shadow.h" 18 #include "sanitizer_common/sanitizer_common.h" 19 #include "sanitizer_common/sanitizer_linux.h" 20 #include <signal.h> 21 #include <sys/mman.h> 22 23 namespace __esan { 24 25 // We only support regular POSIX threads with a single signal handler 26 // for the whole process == thread group. 27 // Thus we only need to store one app signal handler. 28 // FIXME: Store and use any alternate stack and signal flags set by 29 // the app. For now we just call the app handler from our handler. 30 static __sanitizer_sigaction AppSigAct; 31 32 bool processWorkingSetSignal(int SigNum, void (*Handler)(int), 33 void (**Result)(int)) { 34 VPrintf(2, "%s: %d\n", __FUNCTION__, SigNum); 35 if (SigNum == SIGSEGV) { 36 *Result = AppSigAct.handler; 37 AppSigAct.sigaction = (decltype(AppSigAct.sigaction))Handler; 38 return false; // Skip real call. 39 } 40 return true; 41 } 42 43 bool processWorkingSetSigaction(int SigNum, const void *ActVoid, 44 void *OldActVoid) { 45 VPrintf(2, "%s: %d\n", __FUNCTION__, SigNum); 46 if (SigNum == SIGSEGV) { 47 const struct sigaction *Act = (const struct sigaction *) ActVoid; 48 struct sigaction *OldAct = (struct sigaction *) OldActVoid; 49 if (OldAct) 50 internal_memcpy(OldAct, &AppSigAct, sizeof(OldAct)); 51 if (Act) 52 internal_memcpy(&AppSigAct, Act, sizeof(AppSigAct)); 53 return false; // Skip real call. 54 } 55 return true; 56 } 57 58 bool processWorkingSetSigprocmask(int How, void *Set, void *OldSet) { 59 VPrintf(2, "%s\n", __FUNCTION__); 60 // All we need to do is ensure that SIGSEGV is not blocked. 61 // FIXME: we are not fully transparent as we do not pretend that 62 // SIGSEGV is still blocked on app queries: that would require 63 // per-thread mask tracking. 64 if (Set && (How == SIG_BLOCK || How == SIG_SETMASK)) { 65 if (internal_sigismember((__sanitizer_sigset_t *)Set, SIGSEGV)) { 66 VPrintf(1, "%s: removing SIGSEGV from the blocked set\n", __FUNCTION__); 67 internal_sigdelset((__sanitizer_sigset_t *)Set, SIGSEGV); 68 } 69 } 70 return true; 71 } 72 73 static void reinstateDefaultHandler(int SigNum) { 74 __sanitizer_sigaction SigAct; 75 internal_memset(&SigAct, 0, sizeof(SigAct)); 76 SigAct.sigaction = (decltype(SigAct.sigaction))SIG_DFL; 77 int Res = internal_sigaction(SigNum, &SigAct, nullptr); 78 CHECK(Res == 0); 79 VPrintf(1, "Unregistered for %d handler\n", SigNum); 80 } 81 82 // If this is a shadow fault, we handle it here; otherwise, we pass it to the 83 // app to handle it just as the app would do without our tool in place. 84 static void handleMemoryFault(int SigNum, __sanitizer_siginfo *Info, 85 void *Ctx) { 86 if (SigNum == SIGSEGV) { 87 // We rely on si_addr being filled in (thus we do not support old kernels). 88 siginfo_t *SigInfo = (siginfo_t *)Info; 89 uptr Addr = (uptr)SigInfo->si_addr; 90 if (isShadowMem(Addr)) { 91 VPrintf(3, "Shadow fault @%p\n", Addr); 92 uptr PageSize = GetPageSizeCached(); 93 int Res = internal_mprotect((void *)RoundDownTo(Addr, PageSize), 94 PageSize, PROT_READ|PROT_WRITE); 95 CHECK(Res == 0); 96 } else if (AppSigAct.sigaction) { 97 // FIXME: For simplicity we ignore app options including its signal stack 98 // (we just use ours) and all the delivery flags. 99 AppSigAct.sigaction(SigNum, Info, Ctx); 100 } else { 101 // Crash instead of spinning with infinite faults. 102 reinstateDefaultHandler(SigNum); 103 } 104 } else 105 UNREACHABLE("signal not registered"); 106 } 107 108 void registerMemoryFaultHandler() { 109 // We do not use an alternate signal stack, as doing so would require 110 // setting it up for each app thread. 111 // FIXME: This could result in problems with emulating the app's signal 112 // handling if the app relies on an alternate stack for SIGSEGV. 113 114 // We require that SIGSEGV is not blocked. We use a sigprocmask 115 // interceptor to ensure that in the future. Here we ensure it for 116 // the current thread. We assume there are no other threads at this 117 // point during initialization, or that at least they do not block 118 // SIGSEGV. 119 __sanitizer_sigset_t SigSet; 120 internal_sigemptyset(&SigSet); 121 internal_sigprocmask(SIG_BLOCK, &SigSet, nullptr); 122 123 __sanitizer_sigaction SigAct; 124 internal_memset(&SigAct, 0, sizeof(SigAct)); 125 SigAct.sigaction = handleMemoryFault; 126 // We want to handle nested signals b/c we need to handle a 127 // shadow fault in an app signal handler. 128 SigAct.sa_flags = SA_SIGINFO | SA_NODEFER; 129 int Res = internal_sigaction(SIGSEGV, &SigAct, &AppSigAct); 130 CHECK(Res == 0); 131 VPrintf(1, "Registered for SIGSEGV handler\n"); 132 } 133 134 } // namespace __esan 135