aboutsummaryrefslogtreecommitdiffstats
path: root/tools/jello/Callback.cpp
blob: 173657daba0a848904091845409ba90b2bc8df1d (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
//===-- Callback.cpp - Trap handler for function resolution ---------------===//
//
// This file defines the SIGSEGV handler which is invoked when a reference to a
// non-codegen'd function is found.
//
//===----------------------------------------------------------------------===//

#include "VM.h"
#include <signal.h>
#include <ucontext.h>
#include <iostream>

static VM *TheVM = 0;

static void TrapHandler(int TN, siginfo_t *SI, ucontext_t *ucp) {
  assert(TN == SIGSEGV && "Should be SIGSEGV!");

  if (SI->si_code != SEGV_MAPERR || SI->si_addr != 0 ||
      ucp->uc_mcontext.gregs[REG_EIP] != 0) {
    std::cerr << "Bad SEGV encountered!\n";
    abort();
  }

  // The call instruction should have pushed the return value onto the stack...
  unsigned RefAddr = *(unsigned*)ucp->uc_mcontext.gregs[REG_ESP];
  RefAddr -= 4;  // Backtrack to the reference itself...

  std::cerr << "In SEGV handler! Addr=0x" << std::hex << RefAddr
            << " ESP=0x" << ucp->uc_mcontext.gregs[REG_ESP] << std::dec
            << ": Resolving call to function: "
            << TheVM->getFunctionReferencedName((void*)RefAddr) << "\n";

  // Sanity check to make sure this really is a call instruction...
  assert(((unsigned char*)RefAddr)[-1] == 0xE8 && "Not a call instr!");
  
  unsigned NewVal = (unsigned)TheVM->resolveFunctionReference((void*)RefAddr);

  // Rewrite the call target... so that we don't fault every time we execute
  // the call.
  *(unsigned*)RefAddr = NewVal-RefAddr-4;    

  // Change the instruction pointer to be the real target of the call...
  ucp->uc_mcontext.gregs[REG_EIP] = NewVal;
}


void VM::registerCallback() {
  TheVM = this;

  // Register the signal handler...
  struct sigaction SA;
  SA.sa_sigaction = (void (*)(int, siginfo_t*, void*))TrapHandler;
  sigfillset(&SA.sa_mask);               // Block all signals while codegen'ing
  SA.sa_flags = SA_NOCLDSTOP|SA_SIGINFO; // Get siginfo
  sigaction(SIGSEGV, &SA, 0);            // Install the handler
}