summaryrefslogtreecommitdiff
path: root/lib/esan/working_set_posix.cpp
blob: f0191766bb9acb8c33c7a5707a88e7d78461f5af (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
//===-- working_set_posix.cpp -----------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of EfficiencySanitizer, a family of performance tuners.
//
// POSIX-specific working set tool code.
//===----------------------------------------------------------------------===//

#include "working_set.h"
#include "esan_flags.h"
#include "esan_shadow.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_linux.h"
#include <signal.h>
#include <sys/mman.h>

namespace __esan {

// We only support regular POSIX threads with a single signal handler
// for the whole process == thread group.
// Thus we only need to store one app signal handler.
// FIXME: Store and use any alternate stack and signal flags set by
// the app.  For now we just call the app handler from our handler.
static __sanitizer_sigaction AppSigAct;

bool processWorkingSetSignal(int SigNum, void (*Handler)(int),
                             void (**Result)(int)) {
  VPrintf(2, "%s: %d\n", __FUNCTION__, SigNum);
  if (SigNum == SIGSEGV) {
    *Result = AppSigAct.handler;
    AppSigAct.sigaction = (void (*)(int, void*, void*))Handler;
    return false; // Skip real call.
  }
  return true;
}

bool processWorkingSetSigaction(int SigNum, const void *ActVoid,
                                void *OldActVoid) {
  VPrintf(2, "%s: %d\n", __FUNCTION__, SigNum);
  if (SigNum == SIGSEGV) {
    const struct sigaction *Act = (const struct sigaction *) ActVoid;
    struct sigaction *OldAct = (struct sigaction *) OldActVoid;
    if (OldAct)
      internal_memcpy(OldAct, &AppSigAct, sizeof(OldAct));
    if (Act)
      internal_memcpy(&AppSigAct, Act, sizeof(AppSigAct));
    return false; // Skip real call.
  }
  return true;
}

static void reinstateDefaultHandler(int SigNum) {
  __sanitizer_sigaction SigAct;
  internal_memset(&SigAct, 0, sizeof(SigAct));
  SigAct.sigaction = (void (*)(int, void*, void*)) SIG_DFL;
  int Res = internal_sigaction(SigNum, &SigAct, nullptr);
  CHECK(Res == 0);
  VPrintf(1, "Unregistered for %d handler\n", SigNum);
}

// If this is a shadow fault, we handle it here; otherwise, we pass it to the
// app to handle it just as the app would do without our tool in place.
static void handleMemoryFault(int SigNum, void *Info, void *Ctx) {
  if (SigNum == SIGSEGV) {

    // TODO: Add shadow memory fault detection and handling.

    if (AppSigAct.sigaction) {
      // FIXME: For simplicity we ignore app options including its signal stack
      // (we just use ours) and all the delivery flags.
      AppSigAct.sigaction(SigNum, Info, Ctx);
    } else {
      // Crash instead of spinning with infinite faults.
      reinstateDefaultHandler(SigNum);
    }
  } else
    UNREACHABLE("signal not registered");
}

void registerMemoryFaultHandler() {
  // We do not use an alternate signal stack, as doing so would require
  // setting it up for each app thread.
  // FIXME: This could result in problems with emulating the app's signal
  // handling if the app relies on an alternate stack for SIGSEGV.

  // We assume SIGSEGV is not blocked and won't be blocked by the app, so
  // we leave the mask alone.

  __sanitizer_sigaction SigAct;
  internal_memset(&SigAct, 0, sizeof(SigAct));
  SigAct.sigaction = handleMemoryFault;
  // We want to handle nested signals b/c we need to handle a
  // shadow fault in an app signal handler.
  SigAct.sa_flags = SA_SIGINFO | SA_NODEFER;
  int Res = internal_sigaction(SIGSEGV, &SigAct, &AppSigAct);
  CHECK(Res == 0);
  VPrintf(1, "Registered for SIGSEGV handler\n");
}

} // namespace __esan