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