new insn: fix wrong behaviour on lazy class init
[mate.git] / Mate / X86TrapHandling.hs
index f89e2b8f77493ac5b6d3df60b802aaac5688220f..493a3ceaf1b1a3a4a45c2d29bcacbeb6034a7a2e 100644 (file)
@@ -8,6 +8,7 @@ module Mate.X86TrapHandling (
   ) where
 
 import qualified Data.Map as M
+import qualified Data.ByteString.Lazy as B
 
 import Foreign
 import Foreign.C.Types
@@ -24,30 +25,41 @@ data TrapType =
   | StaticFieldAccess
   | VirtualMethodCall Bool
   | InterfaceMethodCall Bool
+  | InstanceOfMiss B.ByteString
+  | NewObjectTrap B.ByteString
+  | NoKnownTrap String
 
 getTrapType :: TrapMap -> CPtrdiff -> CPtrdiff -> TrapType
 getTrapType tmap signal_from from2 =
   case M.lookup (fromIntegral signal_from) tmap of
     (Just (StaticMethod _)) -> StaticMethodCall
     (Just (StaticField _)) -> StaticFieldAccess
-    (Just _) -> error "getTrapMap: doesn't happen"
+    (Just (InstanceOf cn)) -> InstanceOfMiss cn
+    (Just (NewObject cn)) -> NewObjectTrap cn
+    (Just _) -> NoKnownTrap "getTrapMap: doesn't happen"
     -- maybe we've a hit on the second `from' value
     Nothing -> case M.lookup (fromIntegral from2) tmap of
       (Just (VirtualMethod imm8 _)) -> VirtualMethodCall imm8
       (Just (InterfaceMethod imm8 _)) -> InterfaceMethodCall imm8
-      (Just _) -> error "getTrapType: abort #1 :-("
-      Nothing -> error $ "getTrapType: abort #2 :-(" ++ show signal_from ++ ", " ++ show from2 ++ ", " ++ show tmap
+      (Just _) -> NoKnownTrap "getTrapType: abort #1 :-("
+      Nothing -> NoKnownTrap $ "getTrapType: abort #2 :-(" ++ show signal_from ++ ", " ++ show from2 ++ ", " ++ show tmap
 
-foreign export ccall mateHandler :: CPtrdiff -> CPtrdiff -> CPtrdiff -> CPtrdiff -> IO CPtrdiff
-mateHandler :: CPtrdiff -> CPtrdiff -> CPtrdiff -> CPtrdiff -> IO CPtrdiff
-mateHandler eip eax ebx esp = do
+foreign export ccall mateHandler :: CPtrdiff -> CPtrdiff -> CPtrdiff -> CPtrdiff -> CPtrdiff -> IO CPtrdiff
+mateHandler :: CPtrdiff -> CPtrdiff -> CPtrdiff -> CPtrdiff -> CPtrdiff -> IO CPtrdiff
+mateHandler eip eax ebx esp esi = do
   callerAddr <- callerAddrFromStack esp
   tmap <- getTrapMap
   case getTrapType tmap eip callerAddr of
     StaticMethodCall  -> staticCallHandler eip
     StaticFieldAccess -> staticFieldHandler eip
+    (InstanceOfMiss cn) -> instanceOfMissHandler eip cn
+    (NewObjectTrap cn) -> newObjectHandler eip cn
     VirtualMethodCall imm8   -> invokeHandler eax eax esp imm8
     InterfaceMethodCall imm8 -> invokeHandler eax ebx esp imm8
+    NoKnownTrap err ->
+      case esi of
+        0x13371234 -> return (-1)
+        _ -> error err
 
 staticCallHandler :: CPtrdiff -> IO CPtrdiff
 staticCallHandler eip = do
@@ -81,6 +93,37 @@ staticFieldHandler eip = do
       return eip
     else error "staticFieldHandler: something is wrong here. abort.\n"
 
+instanceOfMissHandler :: CPtrdiff -> B.ByteString -> IO CPtrdiff
+instanceOfMissHandler eip classname = do
+  -- first byte is going to be the opcode
+  let insn_ptr = intPtrToPtr (fromIntegral eip) :: Ptr CUChar
+  -- the next four bytes are the immediate
+  let imm_ptr = intPtrToPtr (fromIntegral (eip + 1)) :: Ptr CPtrdiff
+  checkMe <- peek imm_ptr
+  if checkMe == 0x909090ff then -- safety check...
+    do
+      mtable <- getMethodTable classname
+      poke imm_ptr (fromIntegral mtable)
+      poke insn_ptr 0xba -- `mov edx' opcode
+      return eip
+    else error "instanceOfMissHandler: something is wrong here. abort.\n"
+
+newObjectHandler :: CPtrdiff -> B.ByteString -> IO CPtrdiff
+newObjectHandler eip classname = do
+  let push_insn_ptr = intPtrToPtr (fromIntegral eip) :: Ptr CUChar
+  let push_imm_ptr = intPtrToPtr (fromIntegral (eip + 1)) :: Ptr CPtrdiff
+  let mov_imm_ptr = intPtrToPtr (fromIntegral (eip + 16)) :: Ptr CPtrdiff
+  checkMe <- peek mov_imm_ptr
+  if checkMe == 0x13371337
+    then do
+      objsize <- getObjectSize classname
+      mtable <- getMethodTable classname
+      poke push_insn_ptr 0x68 -- push_imm insn
+      poke push_imm_ptr (fromIntegral objsize)
+      poke mov_imm_ptr (fromIntegral mtable)
+      return eip
+    else error "newObjectHandler: something is wrong here. abort.\n"
+
 invokeHandler :: CPtrdiff -> CPtrdiff -> CPtrdiff -> Bool -> IO CPtrdiff
 invokeHandler method_table table2patch esp imm8 = do
   -- table2patch: note, that can be a method-table or a interface-table