- case getTrapType tmap eip callerAddr of
- StaticMethodCall -> staticCallHandler eip
- StaticFieldAccess -> staticFieldHandler eip
- (InstanceOfMiss cn) -> instanceOfMissHandler 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
- -- the actual insn to patch as pointer
- let insn_ptr = intPtrToPtr (fromIntegral eip) :: Ptr CUChar
- -- call offset is displaced by one byte (as the first byte is the opcode)
- let imm_ptr = intPtrToPtr (fromIntegral (eip + 1)) :: Ptr CPtrdiff
- -- 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
- if checkMe == 0x909090ff then
- do
- entryAddr <- getMethodEntry eip 0
- poke insn_ptr 0xe8 -- `call' opcode
- -- it's a relative call, so we have to calculate the offset. why "+ 5"?
- -- (1) the whole insn is 5 bytes long
- -- (2) offset is calculated wrt to the beginning of the next insn
- poke imm_ptr (entryAddr - (eip + 5))
- return eip
- else error "staticCallHandler: something is wrong here. abort\n"
+ let reipw32 = fromIntegral reip
+ (deleteMe, ret_nreip) <- case M.lookup reipw32 tmap of
+ (Just (StaticMethod _)) ->
+ patchWithHarpy patchStaticCall reip >>= delTrue
+ (Just (StaticField _)) ->
+ staticFieldHandler reip >>= delTrue
+ (Just (InstanceOf cn)) ->
+ patchWithHarpy (`patchInstanceOf` cn) reip >>= delFalse
+ (Just (NewObject cn)) ->
+ patchWithHarpy (`patchNewObject` cn) reip >>= delTrue
+ (Just (VirtualCall False _ io_offset)) ->
+ patchWithHarpy (patchInvoke reax reax io_offset) reip
+ >>= delTrue
+ (Just (VirtualCall True _ io_offset)) ->
+ patchWithHarpy (patchInvoke rebx reax io_offset) reip
+ >>= delTrue
+ Nothing -> case resi of
+ 0x13371234 -> return (-1) >>= delFalse
+ _ -> error $ "getTrapType: abort :-( " ++ (showHex reip ". ")
+ ++ (concatMap (`showHex` ", ") (M.keys tmap))
+ if deleteMe
+ then setTrapMap $ M.delete reipw32 tmap
+ else return ()
+ return ret_nreip
+ where
+ delTrue = (\nreip -> return (False, nreip))
+ delFalse = (\nreip -> return (False, nreip))
+
+
+patchWithHarpy :: (CPtrdiff -> CodeGen () () CPtrdiff) -> CPtrdiff -> IO CPtrdiff
+patchWithHarpy patcher reip = do
+ -- this is just an upperbound. if the value is to low, patching fails. find
+ -- something better?
+ let fixme = 1024
+ let entry = Just (intPtrToPtr (fromIntegral reip), fixme)
+ let cgconfig = defaultCodeGenConfig { customCodeBuffer = entry }
+ (_, Right right) <- runCodeGenWithConfig (withDisasm $ patcher reip) () () cgconfig
+ if mateDEBUG
+ then mapM_ (printfJit . printf "patched: %s\n" . showAtt) $ snd right
+ else return ()
+ return reip
+
+withDisasm :: CodeGen e s CPtrdiff -> CodeGen e s (CPtrdiff, [Instruction])
+withDisasm patcher = do
+ reip <- patcher
+ d <- disassemble
+ return (reip, d)
+
+patchStaticCall :: CPtrdiff -> CodeGen e s CPtrdiff
+patchStaticCall reip = do
+ entryAddr <- liftIO $ getMethodEntry reip 0
+ call (fromIntegral (entryAddr - (reip + 5)) :: NativeWord)
+ return reip
+