Home | History | Annotate | Download | only in esan
      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 = (void (*)(int, void*, void*))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 = (void (*)(int, void*, void*)) 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, void *Info, void *Ctx) {
     85   if (SigNum == SIGSEGV) {
     86     // We rely on si_addr being filled in (thus we do not support old kernels).
     87     siginfo_t *SigInfo = (siginfo_t *)Info;
     88     uptr Addr = (uptr)SigInfo->si_addr;
     89     if (isShadowMem(Addr)) {
     90       VPrintf(3, "Shadow fault @%p\n", Addr);
     91       uptr PageSize = GetPageSizeCached();
     92       int Res = internal_mprotect((void *)RoundDownTo(Addr, PageSize),
     93                                   PageSize, PROT_READ|PROT_WRITE);
     94       CHECK(Res == 0);
     95     } else if (AppSigAct.sigaction) {
     96       // FIXME: For simplicity we ignore app options including its signal stack
     97       // (we just use ours) and all the delivery flags.
     98       AppSigAct.sigaction(SigNum, Info, Ctx);
     99     } else {
    100       // Crash instead of spinning with infinite faults.
    101       reinstateDefaultHandler(SigNum);
    102     }
    103   } else
    104     UNREACHABLE("signal not registered");
    105 }
    106 
    107 void registerMemoryFaultHandler() {
    108   // We do not use an alternate signal stack, as doing so would require
    109   // setting it up for each app thread.
    110   // FIXME: This could result in problems with emulating the app's signal
    111   // handling if the app relies on an alternate stack for SIGSEGV.
    112 
    113   // We require that SIGSEGV is not blocked.  We use a sigprocmask
    114   // interceptor to ensure that in the future.  Here we ensure it for
    115   // the current thread.  We assume there are no other threads at this
    116   // point during initialization, or that at least they do not block
    117   // SIGSEGV.
    118   __sanitizer_sigset_t SigSet;
    119   internal_sigemptyset(&SigSet);
    120   internal_sigprocmask(SIG_BLOCK, &SigSet, nullptr);
    121 
    122   __sanitizer_sigaction SigAct;
    123   internal_memset(&SigAct, 0, sizeof(SigAct));
    124   SigAct.sigaction = handleMemoryFault;
    125   // We want to handle nested signals b/c we need to handle a
    126   // shadow fault in an app signal handler.
    127   SigAct.sa_flags = SA_SIGINFO | SA_NODEFER;
    128   int Res = internal_sigaction(SIGSEGV, &SigAct, &AppSigAct);
    129   CHECK(Res == 0);
    130   VPrintf(1, "Registered for SIGSEGV handler\n");
    131 }
    132 
    133 } // namespace __esan
    134