blob: 3b40e2ebe1da61d442ca215ea7ee53d3f9d234d3 [file] [log] [blame]
Chris Lattnerbd199fb2002-12-24 00:01:05 +00001//===-- Callback.cpp - Trap handler for function resolution ---------------===//
2//
3// This file defines the SIGSEGV handler which is invoked when a reference to a
4// non-codegen'd function is found.
5//
6//===----------------------------------------------------------------------===//
7
8#include "VM.h"
9#include "Support/Statistic.h"
10#include <signal.h>
11#include <ucontext.h>
12#include <iostream>
13
14static VM *TheVM = 0;
15
16static void TrapHandler(int TN, siginfo_t *SI, ucontext_t *ucp) {
17 assert(TN == SIGSEGV && "Should be SIGSEGV!");
18
19#ifdef REG_EIP /* this code does not compile on Sparc! */
20 if (SI->si_code != SEGV_MAPERR || SI->si_addr != 0 ||
21 ucp->uc_mcontext.gregs[REG_EIP] != 0) {
Chris Lattner61253a92003-01-13 01:00:02 +000022 std::cerr << "Bad SEGV encountered EIP = 0x" << std::hex
23 << ucp->uc_mcontext.gregs[REG_EIP] << " addr = "
24 << SI->si_addr << "!\n";
25
26 struct sigaction SA; // Restore old SEGV handler...
27 SA.sa_handler = SIG_DFL;
28 SA.sa_flags = SA_NOMASK;
29 sigaction(SIGSEGV, &SA, 0);
30 return; // Should core dump now...
Chris Lattnerbd199fb2002-12-24 00:01:05 +000031 }
32
33 // The call instruction should have pushed the return value onto the stack...
34 unsigned RefAddr = *(unsigned*)ucp->uc_mcontext.gregs[REG_ESP];
35 RefAddr -= 4; // Backtrack to the reference itself...
36
37 DEBUG(std::cerr << "In SEGV handler! Addr=0x" << std::hex << RefAddr
38 << " ESP=0x" << ucp->uc_mcontext.gregs[REG_ESP] << std::dec
39 << ": Resolving call to function: "
40 << TheVM->getFunctionReferencedName((void*)RefAddr) << "\n");
41
42 // Sanity check to make sure this really is a call instruction...
43 assert(((unsigned char*)RefAddr)[-1] == 0xE8 && "Not a call instr!");
44
45 unsigned NewVal = (unsigned)TheVM->resolveFunctionReference((void*)RefAddr);
46
47 // Rewrite the call target... so that we don't fault every time we execute
48 // the call.
49 *(unsigned*)RefAddr = NewVal-RefAddr-4;
50
51 // Change the instruction pointer to be the real target of the call...
52 ucp->uc_mcontext.gregs[REG_EIP] = NewVal;
53
54#endif
55}
56
57
58void VM::registerCallback() {
59 TheVM = this;
60
61 // Register the signal handler...
62 struct sigaction SA;
63 SA.sa_sigaction = (void (*)(int, siginfo_t*, void*))TrapHandler;
64 sigfillset(&SA.sa_mask); // Block all signals while codegen'ing
65 SA.sa_flags = SA_NOCLDSTOP|SA_SIGINFO; // Get siginfo
66 sigaction(SIGSEGV, &SA, 0); // Install the handler
67}
68
69