summaryrefslogtreecommitdiff
path: root/lib/ExecutionEngine/JIT/Callback.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ExecutionEngine/JIT/Callback.cpp')
-rw-r--r--lib/ExecutionEngine/JIT/Callback.cpp62
1 files changed, 62 insertions, 0 deletions
diff --git a/lib/ExecutionEngine/JIT/Callback.cpp b/lib/ExecutionEngine/JIT/Callback.cpp
new file mode 100644
index 0000000000..b843e10689
--- /dev/null
+++ b/lib/ExecutionEngine/JIT/Callback.cpp
@@ -0,0 +1,62 @@
+//===-- 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 "Support/Statistic.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!");
+
+#ifdef REG_EIP /* this code does not compile on Sparc! */
+ 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...
+
+ DEBUG(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;
+
+#endif
+}
+
+
+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
+}
+
+