From 7f54316f216f6508e8d6d5b37bed49350fc0d14e Mon Sep 17 00:00:00 2001 From: Bernhard Urban Date: Sat, 19 May 2012 11:52:33 +0200 Subject: [PATCH] traps: do more things in haskell world --- Mate.hs | 2 +- Mate/ClassPool.hs | 1 - Mate/MethodPool.hs | 18 +------- Mate/X86CodeGen.hs | 7 +-- Mate/X86TrapHandling.hs | 98 +++++++++++++++++++++++++++++++++++++++++ ffi/trap.c | 90 ++++--------------------------------- 6 files changed, 111 insertions(+), 105 deletions(-) create mode 100644 Mate/X86TrapHandling.hs diff --git a/Mate.hs b/Mate.hs index 02c9969..d60df06 100644 --- a/Mate.hs +++ b/Mate.hs @@ -14,10 +14,10 @@ import Text.Printf 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 diff --git a/Mate/ClassPool.hs b/Mate/ClassPool.hs index 5260063..2161947 100644 --- a/Mate/ClassPool.hs +++ b/Mate/ClassPool.hs @@ -84,7 +84,6 @@ getObjectSize path = 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 diff --git a/Mate/MethodPool.hs b/Mate/MethodPool.hs index 16890c8..216a287 100644 --- a/Mate/MethodPool.hs +++ b/Mate/MethodPool.hs @@ -34,23 +34,7 @@ import Mate.Debug 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 diff --git a/Mate/X86CodeGen.hs b/Mate/X86CodeGen.hs index 893a397..1b4ef95 100644 --- a/Mate/X86CodeGen.hs +++ b/Mate/X86CodeGen.hs @@ -36,10 +36,6 @@ foreign import ccall "dynamic" 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) @@ -110,7 +106,8 @@ emitFromBB method cls hmap = do 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 diff --git a/Mate/X86TrapHandling.hs b/Mate/X86TrapHandling.hs new file mode 100644 index 0000000..2972cac --- /dev/null +++ b/Mate/X86TrapHandling.hs @@ -0,0 +1,98 @@ +{-# 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)) diff --git a/ffi/trap.c b/ffi/trap.c index 157358b..e0878b2 100644 --- a/ffi/trap.c +++ b/ffi/trap.c @@ -21,10 +21,8 @@ #include -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); @@ -37,98 +35,28 @@ void mainresult(unsigned int a) 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); -- 2.25.1