1 //===-- working_set_posix.cpp -----------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file is a part of EfficiencySanitizer, a family of performance tuners.
12 // POSIX-specific working set tool code.
13 //===----------------------------------------------------------------------===//
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"
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;
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.
43 bool processWorkingSetSigaction(int SigNum, const void *ActVoid,
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;
50 internal_memcpy(OldAct, &AppSigAct, sizeof(OldAct));
52 internal_memcpy(&AppSigAct, Act, sizeof(AppSigAct));
53 return false; // Skip real call.
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);
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);
79 VPrintf(1, "Unregistered for %d handler\n", SigNum);
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,
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);
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);
101 // Crash instead of spinning with infinite faults.
102 reinstateDefaultHandler(SigNum);
105 UNREACHABLE("signal not registered");
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.
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
119 __sanitizer_sigset_t SigSet;
120 internal_sigemptyset(&SigSet);
121 internal_sigprocmask(SIG_BLOCK, &SigSet, nullptr);
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);
131 VPrintf(1, "Registered for SIGSEGV handler\n");
134 } // namespace __esan