import JVM.ClassFile
import Mate.BasicBlocks
-import Mate.X86CodeGen
import Mate.MethodPool
import Mate.Types
import Mate.ClassPool
+import Mate.X86TrapHandling
main :: IO ()
main = do
-- one slot for "method-table-ptr"
return $ (1 + fsize) * 4
-foreign export ccall getStaticFieldAddr :: CUInt -> IO CUInt
getStaticFieldAddr :: CUInt -> IO CUInt
getStaticFieldAddr from = do
trapmap <- getTrapMap
foreign import ccall "dynamic"
code_void :: FunPtr (IO ()) -> IO ()
-foreign export ccall getTrapType :: CUInt -> CUInt -> IO CUInt
-getTrapType :: CUInt -> CUInt -> IO CUInt
-getTrapType signal_from from2 = do
- tmap <- getTrapMap
- case M.lookup (fromIntegral signal_from) tmap of
- (Just (MI _)) -> return 0
- (Just (VI _)) -> return 1
- (Just (SFI _)) -> return 2
- (Just (II _)) -> return 4
- -- maybe we've a hit on the second `from' value
- Nothing -> case M.lookup (fromIntegral from2) tmap of
- (Just (VI _)) -> return 1
- (Just (II _)) -> return 4
- (Just _) -> error "getTrapType: abort #1 :-("
- Nothing -> error "getTrapType: abort #2 :-("
-
-foreign export ccall getMethodEntry :: CUInt -> CUInt -> IO CUInt
+
getMethodEntry :: CUInt -> CUInt -> IO CUInt
getMethodEntry signal_from methodtable = do
mmap <- getMethodMap
foreign import ccall "getMallocObjectAddr"
getMallocObjectAddr :: CUInt
-foreign import ccall "register_signal"
- register_signal :: IO ()
-
-
type EntryPoint = Ptr Word8
type EntryPointOffset = Int
type PatchInfo = (BlockID, EntryPointOffset)
when (argcnt > 0) (add esp argcnt)
-- push result on stack if method has a return value
when (methodHaveReturnValue cls cpidx) (push eax)
- return $ Just (calladdr, MI l)
+ -- +2 is for correcting eip in trap context
+ return $ Just (calladdr + 2, MI l)
emit' :: J.Instruction -> CodeGen e s (Maybe (Word32, TrapInfo))
emit' (INVOKESPECIAL cpidx) = emitInvoke cpidx True
--- /dev/null
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ForeignFunctionInterface #-}
+#include "debug.h"
+module Mate.X86TrapHandling where
+
+import qualified Data.Map as M
+
+import Foreign
+import Foreign.C.Types
+
+import Mate.Types
+import Mate.MethodPool
+import Mate.ClassPool
+
+
+foreign import ccall "register_signal"
+ register_signal :: IO ()
+
+
+getTrapType :: CUInt -> CUInt -> IO CUInt
+getTrapType signal_from from2 = do
+ tmap <- getTrapMap
+ case M.lookup (fromIntegral signal_from) tmap of
+ (Just (MI _)) -> return 0
+ (Just (SFI _)) -> return 2
+ (Just _) -> error "getTrapMap: doesn't happen"
+ -- maybe we've a hit on the second `from' value
+ Nothing -> case M.lookup (fromIntegral from2) tmap of
+ (Just (VI _)) -> return 1
+ (Just (II _)) -> return 4
+ (Just _) -> error "getTrapType: abort #1 :-("
+ Nothing -> error "getTrapType: abort #2 :-("
+
+foreign export ccall mateHandler :: CUInt -> CUInt -> CUInt -> CUInt -> IO CUInt
+mateHandler :: CUInt -> CUInt -> CUInt -> CUInt -> IO CUInt
+mateHandler eip eax ebx esp = do
+ callerAddr <- callerAddrFromStack esp
+ blah <- getTrapType eip (callerAddr - 3)
+ case blah of
+ 0 -> staticCallHandler eip
+ 1 -> invokeHandler eax eax esp
+ 4 -> invokeHandler eax ebx esp
+ 2 -> staticFieldHandler eip
+ x -> error $ "wtf: " ++ (show x)
+
+staticCallHandler :: CUInt -> IO CUInt
+staticCallHandler eip = do
+ -- the actual insn to patch is displaced by two bytes
+ let insn_ptr = intPtrToPtr (fromIntegral (eip - 2)) :: Ptr CUChar
+ -- call offset is displaced by one byte
+ let imm_ptr = intPtrToPtr (fromIntegral (eip - 1)) :: Ptr CUInt
+ -- in codegen we set the immediate to some magic value
+ -- in order to produce a SIGILL signal. we also do a safety
+ -- check here, if we're really the "owner" of this signal.
+ checkMe <- peek imm_ptr
+ case checkMe == 0x90ffff90 of
+ True -> do
+ entryAddr <- getMethodEntry eip 0
+ poke insn_ptr 0xe8 -- call opcode
+ -- it's a relative call, so we have to calculate the offset. why "+ 3"?
+ -- (1) the whole insn is 5 bytes long
+ -- (2) begin of insn is displaced by 2 bytes
+ -- (3) offset is calculated wrt to the beginning of the next insn
+ poke imm_ptr (entryAddr - (eip + 3))
+ return (eip - 2)
+ False -> error "staticCallHandler: something is wrong here. abort\n"
+
+staticFieldHandler :: CUInt -> IO CUInt
+staticFieldHandler eip = do
+ -- patch the offset here, first two bytes are part of the insn (opcode + reg)
+ let imm_ptr = intPtrToPtr (fromIntegral (eip + 2)) :: Ptr CUInt
+ checkMe <- peek imm_ptr
+ case checkMe == 0x00000000 of
+ True -> do
+ getStaticFieldAddr eip >>= poke imm_ptr
+ return eip
+ False -> error "staticFieldHandler: something is wrong here. abort.\n"
+
+invokeHandler :: CUInt -> CUInt -> CUInt -> IO CUInt
+invokeHandler method_table table2patch esp = do
+ -- table2patch: note, that can be a method-table or a interface-table
+ callerAddr <- callerAddrFromStack esp
+ offset <- offsetOfCallInsn esp
+ entryAddr <- getMethodEntry (callerAddr - 3) method_table
+ let call_insn = intPtrToPtr (fromIntegral $ table2patch + (fromIntegral offset))
+ poke call_insn entryAddr
+ return entryAddr
+
+
+callerAddrFromStack :: CUInt -> IO CUInt
+callerAddrFromStack = peek . intPtrToPtr . fromIntegral
+
+offsetOfCallInsn :: CUInt -> IO CUChar
+offsetOfCallInsn esp = do
+ let ret_ptr = intPtrToPtr (fromIntegral esp) :: Ptr CUInt
+ ret <- peek ret_ptr
+ peek (intPtrToPtr $ fromIntegral (ret - 1))
#include <sys/ucontext.h>
-unsigned int getMethodEntry(unsigned int, unsigned int);
-unsigned int getStaticFieldAddr(unsigned int);
-unsigned int getTrapType(unsigned int, unsigned int);
unsigned int mallocObject(int);
+unsigned int mateHandler(unsigned int, unsigned int, unsigned int, unsigned int);
#ifdef DBG_TRAP
#define dprintf(args...) do { printf (args); } while (0);
dprintf("mainresult: 0x%08x\n", a);
}
-void staticcalltrap(int nSignal, siginfo_t *info, void *ctx)
+void chandler(int nSignal, siginfo_t *info, void *ctx)
{
mcontext_t *mctx = &((ucontext_t *) ctx)->uc_mcontext;
- unsigned int from = (unsigned int) mctx->gregs[REG_EIP] - 2;
- unsigned int *to_patch = (unsigned int *) (from + 1);
- dprintf("callertrap(mctx) by 0x%08x\n", from);
- if (*to_patch != 0x90ffff90) {
- dprintf("callertrap: something is wrong here. abort\n");
- exit(0);
- }
- unsigned int patchme = getMethodEntry(from, 0);
- unsigned char *insn = (unsigned char *) from;
- *insn = 0xe8; // call opcode
- dprintf(" to_patch: 0x%08x\n", (unsigned int) to_patch);
- dprintf("*to_patch: 0x%08x\n", *to_patch);
- *to_patch = patchme - (from + 5);
- dprintf("*to_patch: 0x%08x\n", *to_patch);
- mctx->gregs[REG_EIP] = (unsigned long) insn;
-}
-
-void sigsegvtrap(int nSignal, siginfo_t *info, void *ctx)
-{
- mcontext_t *mctx = &((ucontext_t *) ctx)->uc_mcontext;
- unsigned int from = (unsigned int) mctx->gregs[REG_EIP];
- unsigned int *esp = (unsigned int *) mctx->gregs[REG_ESP];
-
- /* if from is not *the* eip: get actual eip from stack storage */
- unsigned int from_stack = (*esp) - 3;
- switch(getTrapType(from, from_stack)) {
- default: case 0: {
- dprintf("something is wrong here: abort\n");
- exit(1);
- } break;
- case 1: { // invokevirtual
- if (from > 0) {
- dprintf("from: 0x%08x but should be 0 :-(\n", from);
- }
- unsigned int method_table_ptr = (unsigned int) mctx->gregs[REG_EAX];
- unsigned char offset = *((unsigned char *) (*esp) - 1);
- /* method entry to patch */
- unsigned int *to_patch = (unsigned int*) (method_table_ptr + offset);
- dprintf("invokevirtual by 0x%08x with offset 0x%08x\n", from_stack, offset);
- dprintf(" to_patch: 0x%08x\n", (unsigned int) to_patch);
- dprintf("*to_patch: 0x%08x\n", *to_patch);
- *to_patch = getMethodEntry(from_stack, method_table_ptr);
- mctx->gregs[REG_EIP] = *to_patch;
- dprintf("*to_patch: 0x%08x\n", *to_patch);
- } break;
- case 4: { // invokeinterface
- if (from > 0) {
- dprintf("from: 0x%08x but should be 0 :-(\n", from);
- }
- unsigned int method_table_ptr = (unsigned int) mctx->gregs[REG_EAX];
- unsigned int interface_table_ptr = (unsigned int) mctx->gregs[REG_EBX];
- unsigned char offset = *((unsigned char *) (*esp) - 1);
- /* interface entry to patch */
- unsigned int *to_patch = (unsigned int*) (interface_table_ptr + offset);
- dprintf("invokeinterface by 0x%08x with offset 0x%08x\n", from_stack, offset);
- dprintf(" to_patch: 0x%08x\n", (unsigned int) to_patch);
- dprintf("*to_patch: 0x%08x\n", *to_patch);
- *to_patch = getMethodEntry(from_stack, method_table_ptr);
- mctx->gregs[REG_EIP] = *to_patch;
- dprintf("*to_patch: 0x%08x\n", *to_patch);
- } break;
- case 2: { // static field patch
- unsigned int *to_patch = (unsigned int *) (from + 2);
- dprintf("staticfieldtrap by 0x%08x\n", from);
- if (*to_patch != 0x00000000) {
- dprintf("staticfieldtrap: something is wrong here. abort\n");
- exit(0);
- }
- unsigned int patchme = getStaticFieldAddr(from);
+ unsigned int eip = (unsigned int) mctx->gregs[REG_EIP];
+ unsigned int eax = (unsigned int) mctx->gregs[REG_EAX];
+ unsigned int ebx = (unsigned int) mctx->gregs[REG_EBX];
+ unsigned int esp = (unsigned int) mctx->gregs[REG_ESP];
- dprintf(" to_patch: 0x%08x\n", (unsigned int) to_patch);
- dprintf("*to_patch: 0x%08x\n", *to_patch);
- *to_patch = patchme;
- dprintf("*to_patch: 0x%08x\n", *to_patch);
- } break;
- }
+ mctx->gregs[REG_EIP] = mateHandler(eip, eax, ebx, esp);
}
void register_signal(void)
{
struct sigaction illaction;
- illaction.sa_sigaction = staticcalltrap;
+ illaction.sa_sigaction = chandler;
sigemptyset(&illaction.sa_mask);
illaction.sa_flags = SA_SIGINFO | SA_RESTART | SA_NODEFER;
sigaction(SIGILL, &illaction, NULL);
struct sigaction segvaction;
- segvaction.sa_sigaction = sigsegvtrap;
+ segvaction.sa_sigaction = chandler;
sigemptyset(&segvaction.sa_mask);
segvaction.sa_flags = SA_SIGINFO | SA_RESTART | SA_NODEFER;
sigaction(SIGSEGV, &segvaction, NULL);