traps: do more things in haskell world
authorBernhard Urban <lewurm@gmail.com>
Sat, 19 May 2012 09:52:33 +0000 (11:52 +0200)
committerBernhard Urban <lewurm@gmail.com>
Sat, 19 May 2012 09:52:33 +0000 (11:52 +0200)
Mate.hs
Mate/ClassPool.hs
Mate/MethodPool.hs
Mate/X86CodeGen.hs
Mate/X86TrapHandling.hs [new file with mode: 0644]
ffi/trap.c

diff --git a/Mate.hs b/Mate.hs
index 02c9969ae55274aef67e84397e2b0d686b57a28f..d60df06367cd69bc5c6e85d00bff3940acef3c26 100644 (file)
--- 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
index 52600630a285c9a0eb62664cfb989a99960db865..216194709978fc72a8107c284629a0a9e4aa2e69 100644 (file)
@@ -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
index 16890c85f7bca01d6842a52dd3198c58fe34c583..216a287daa15c1683a857b5aee7ffc2620428c1f 100644 (file)
@@ -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
index 893a397e8e084f897d83f924eaf7be333a5a0f6d..1b4ef954ce9def82da78439b50be1e3c5fa27352 100644 (file)
@@ -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 (file)
index 0000000..2972cac
--- /dev/null
@@ -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))
index 157358b6227ed2ddd994598a4deba7c2edc97b72..e0878b2bb0a296989934bf48b9314c355fb0d0df 100644 (file)
 
 #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);
@@ -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);