2 {-# LANGUAGE OverloadedStrings #-}
3 {-# LANGUAGE ForeignFunctionInterface #-}
5 module Mate.X86TrapHandling (
11 import qualified Data.Map as M
12 import qualified Data.ByteString.Lazy as B
15 import Foreign.C.Types
18 import Mate.NativeSizes
19 import {-# SOURCE #-} Mate.MethodPool
22 foreign import ccall "register_signal"
23 register_signal :: IO ()
25 foreign export ccall mateHandler :: CPtrdiff -> CPtrdiff -> CPtrdiff -> CPtrdiff -> IO CPtrdiff
26 mateHandler :: CPtrdiff -> CPtrdiff -> CPtrdiff -> CPtrdiff -> IO CPtrdiff
27 mateHandler eip eax ebx esi = do
29 case M.lookup (fromIntegral eip) tmap of
30 (Just (StaticMethod _)) -> staticCallHandler eip
31 (Just (StaticField _)) -> staticFieldHandler eip
32 (Just (InstanceOf cn)) -> instanceOfMissHandler eip cn
33 (Just (NewObject cn)) -> newObjectHandler eip cn
34 (Just (VirtualCall False _ io_offset)) -> invokeHandler eax eax eip io_offset
35 (Just (VirtualCall True _ io_offset)) -> invokeHandler ebx eax eip io_offset
36 Nothing -> case esi of
37 0x13371234 -> return (-1)
38 _ -> error $ "getTrapType: abort :-(" ++ (showHex eip "") ++ ", " ++ show (M.keys tmap)
40 staticCallHandler :: CPtrdiff -> IO CPtrdiff
41 staticCallHandler eip = do
42 -- the actual insn to patch as pointer
43 let insn_ptr = intPtrToPtr (fromIntegral eip) :: Ptr CUChar
44 -- call offset is displaced by one byte (as the first byte is the opcode)
45 let imm_ptr = intPtrToPtr (fromIntegral (eip + 1)) :: Ptr CPtrdiff
46 -- in codegen we set the immediate to some magic value
47 -- in order to produce a SIGILL signal. we also do a safety
48 -- check here, if we're really the "owner" of this signal.
49 checkMe <- peek imm_ptr
50 if checkMe == 0x909090ff then
52 entryAddr <- getMethodEntry eip 0
53 poke insn_ptr 0xe8 -- `call' opcode
54 -- it's a relative call, so we have to calculate the offset. why "+ 5"?
55 -- (1) the whole insn is 5 bytes long
56 -- (2) offset is calculated wrt to the beginning of the next insn
57 poke imm_ptr (entryAddr - (eip + 5))
59 else error "staticCallHandler: something is wrong here. abort\n"
61 staticFieldHandler :: CPtrdiff -> IO CPtrdiff
62 staticFieldHandler eip = do
63 -- patch the offset here, first two bytes are part of the insn (opcode + reg)
64 let imm_ptr = intPtrToPtr (fromIntegral (eip + 2)) :: Ptr CPtrdiff
65 checkMe <- peek imm_ptr
66 if checkMe == 0x00000000 then
68 getStaticFieldAddr eip >>= poke imm_ptr
70 else error "staticFieldHandler: something is wrong here. abort.\n"
72 instanceOfMissHandler :: CPtrdiff -> B.ByteString -> IO CPtrdiff
73 instanceOfMissHandler eip classname = do
74 -- first byte is going to be the opcode
75 let insn_ptr = intPtrToPtr (fromIntegral eip) :: Ptr CUChar
76 -- the next four bytes are the immediate
77 let imm_ptr = intPtrToPtr (fromIntegral (eip + 1)) :: Ptr CPtrdiff
78 checkMe <- peek imm_ptr
79 if checkMe == 0x909090ff then -- safety check...
81 mtable <- getMethodTable classname
82 poke imm_ptr (fromIntegral mtable)
83 poke insn_ptr 0xba -- `mov edx' opcode
85 else error "instanceOfMissHandler: something is wrong here. abort.\n"
87 newObjectHandler :: CPtrdiff -> B.ByteString -> IO CPtrdiff
88 newObjectHandler eip classname = do
89 let push_insn_ptr = intPtrToPtr (fromIntegral eip) :: Ptr CUChar
90 let push_imm_ptr = intPtrToPtr (fromIntegral (eip + 1)) :: Ptr CPtrdiff
91 let mov_imm_ptr = intPtrToPtr (fromIntegral (eip + 16)) :: Ptr CPtrdiff
92 checkMe <- peek mov_imm_ptr
93 if checkMe == 0x13371337
95 objsize <- getObjectSize classname
96 mtable <- getMethodTable classname
97 poke push_insn_ptr 0x68 -- push_imm insn
98 poke push_imm_ptr (fromIntegral objsize)
99 poke mov_imm_ptr (fromIntegral mtable)
101 else error "newObjectHandler: something is wrong here. abort.\n"
103 invokeHandler :: CPtrdiff -> CPtrdiff -> CPtrdiff -> IO NativeWord -> IO CPtrdiff
104 invokeHandler method_table table2patch eip io_offset = do
105 let call0_insn_ptr = intPtrToPtr (fromIntegral eip) :: Ptr CUChar
106 let call1_insn_ptr = intPtrToPtr (fromIntegral (eip + 1)) :: Ptr CUChar
107 let call_imm_ptr = intPtrToPtr (fromIntegral (eip + 2)) :: Ptr CPtrdiff
109 -- @table2patch: note, that can be a method-table or a interface-table
110 entryAddr <- getMethodEntry eip method_table
113 let call_insn = intPtrToPtr . fromIntegral $ table2patch + fromIntegral offset
114 poke call_insn entryAddr
117 checkMe <- peek call_imm_ptr
118 if checkMe == 0x90909090
120 poke call0_insn_ptr 0xff -- indirect call op[0]
121 poke call1_insn_ptr 0x90 -- indirect call op[1]
122 poke call_imm_ptr (fromIntegral offset)
124 else error "invokeHandler: something is wrong here. abort\n"