2 {-# LANGUAGE OverloadedStrings #-}
3 {-# LANGUAGE ForeignFunctionInterface #-}
5 module Mate.X86TrapHandling where
7 import qualified Data.Map as M
10 import Foreign.C.Types
13 import Mate.MethodPool
16 foreign import ccall "register_signal"
17 register_signal :: IO ()
20 getTrapType :: CUInt -> CUInt -> IO CUInt
21 getTrapType signal_from from2 = do
23 case M.lookup (fromIntegral signal_from) tmap of
24 (Just (StaticMethod _)) -> return 0
25 (Just (StaticField _)) -> return 2
26 (Just _) -> error "getTrapMap: doesn't happen"
27 -- maybe we've a hit on the second `from' value
28 Nothing -> case M.lookup (fromIntegral from2) tmap of
29 (Just (VirtualMethod True _)) -> return 1
30 (Just (VirtualMethod False _)) -> return 5
31 (Just (InterfaceMethod True _)) -> return 4
32 (Just (InterfaceMethod False _)) -> return 8
33 (Just _) -> error "getTrapType: abort #1 :-("
34 Nothing -> error $ "getTrapType: abort #2 :-(" ++ show signal_from ++ ", " ++ show from2 ++ ", " ++ show tmap
36 foreign export ccall mateHandler :: CUInt -> CUInt -> CUInt -> CUInt -> IO CUInt
37 mateHandler :: CUInt -> CUInt -> CUInt -> CUInt -> IO CUInt
38 mateHandler eip eax ebx esp = do
39 callerAddr <- callerAddrFromStack esp
40 blah <- getTrapType eip callerAddr
42 0 -> staticCallHandler eip
43 1 -> invokeHandler eax eax esp True
44 5 -> invokeHandler eax eax esp False
45 4 -> invokeHandler eax ebx esp True
46 8 -> invokeHandler eax ebx esp False
47 2 -> staticFieldHandler eip
48 x -> error $ "wtf: " ++ show x
50 staticCallHandler :: CUInt -> IO CUInt
51 staticCallHandler eip = do
52 -- the actual insn to patch is displaced by two bytes
53 let insn_ptr = intPtrToPtr (fromIntegral (eip - 2)) :: Ptr CUChar
54 -- call offset is displaced by one byte
55 let imm_ptr = intPtrToPtr (fromIntegral (eip - 1)) :: Ptr CUInt
56 -- in codegen we set the immediate to some magic value
57 -- in order to produce a SIGILL signal. we also do a safety
58 -- check here, if we're really the "owner" of this signal.
59 checkMe <- peek imm_ptr
60 case checkMe == 0x90ffff90 of
62 entryAddr <- getMethodEntry eip 0
63 poke insn_ptr 0xe8 -- call opcode
64 -- it's a relative call, so we have to calculate the offset. why "+ 3"?
65 -- (1) the whole insn is 5 bytes long
66 -- (2) begin of insn is displaced by 2 bytes
67 -- (3) offset is calculated wrt to the beginning of the next insn
68 poke imm_ptr (entryAddr - (eip + 3))
70 False -> error "staticCallHandler: something is wrong here. abort\n"
72 staticFieldHandler :: CUInt -> IO CUInt
73 staticFieldHandler eip = do
74 -- patch the offset here, first two bytes are part of the insn (opcode + reg)
75 let imm_ptr = intPtrToPtr (fromIntegral (eip + 2)) :: Ptr CUInt
76 checkMe <- peek imm_ptr
77 case checkMe == 0x00000000 of
79 getStaticFieldAddr eip >>= poke imm_ptr
81 False -> error "staticFieldHandler: something is wrong here. abort.\n"
83 invokeHandler :: CUInt -> CUInt -> CUInt -> Bool -> IO CUInt
84 invokeHandler method_table table2patch esp imm8 = do
85 -- table2patch: note, that can be a method-table or a interface-table
86 callerAddr <- callerAddrFromStack esp
87 offset <- if imm8 then offsetOfCallInsn8 esp else offsetOfCallInsn32 esp
88 entryAddr <- getMethodEntry callerAddr method_table
89 let call_insn = intPtrToPtr (fromIntegral $ table2patch + fromIntegral offset)
90 poke call_insn entryAddr
94 callerAddrFromStack :: CUInt -> IO CUInt
95 callerAddrFromStack = peek . intPtrToPtr . fromIntegral
97 offsetOfCallInsn8 :: CUInt -> IO CUInt
98 offsetOfCallInsn8 esp = do
99 let ret_ptr = intPtrToPtr (fromIntegral esp) :: Ptr CUInt
101 retval <- peek (intPtrToPtr (fromIntegral (ret - 1)) :: Ptr CUChar)
102 return $ fromIntegral retval
104 offsetOfCallInsn32 :: CUInt -> IO CUInt
105 offsetOfCallInsn32 esp = do
106 let ret_ptr = intPtrToPtr (fromIntegral esp) :: Ptr CUInt
108 peek (intPtrToPtr $ fromIntegral (ret - 4))