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