unicorn/bindings/haskell/samples/SampleMips.hs
Adrian Herrera 74aaf3b321 Haskell bindings
These Haskell bindings make large use of c2hs to generate much of the code, so
Unicorn's const_generator is not used.

The emulator is based on the Either monad transformer. The IO monad is used to
run the underlying Unicorn library, while the Either monad is used to handle
errors.

Instructions on how to build the bindings are located in
bindings/haskell/README.TXT. The same samples found in samples/ can be found
in bindings/haskell/samples. They should produce the same output, with slight
differences in their error handling and messaging.
2016-04-06 09:21:36 +10:00

130 lines
3.8 KiB
Haskell

-- Sample code to demonstrate how to emulate Mips code (big endian)
import Unicorn
import Unicorn.Hook
import qualified Unicorn.CPU.Mips as Mips
import qualified Data.ByteString as BS
import Data.Word
import qualified Numeric as N (showHex)
-- Code to be emulated
--
-- ori $at, $at, 0x3456
mipsCodeEb :: BS.ByteString
mipsCodeEb = BS.pack [0x34, 0x21, 0x34, 0x56]
-- ori $at, $at, 0x3456
mipsCodeEl :: BS.ByteString
mipsCodeEl = BS.pack [0x56, 0x34, 0x21, 0x34]
-- Memory address where emulation starts
address :: Word64
address = 0x10000
-- Pretty-print integral as hex
showHex :: (Integral a, Show a) => a -> String
showHex =
flip N.showHex ""
-- Calculate code length
codeLength :: Num a => BS.ByteString -> a
codeLength =
fromIntegral . BS.length
hookBlock :: BlockHook ()
hookBlock _ addr size _ =
putStrLn $ ">>> Tracing basic block at 0x" ++ showHex addr ++
", block size = 0x" ++ (maybe "0" showHex size)
hookCode :: CodeHook ()
hookCode _ addr size _ =
putStrLn $ ">>> Tracing instruction at 0x" ++ showHex addr ++
", instruction size = 0x" ++ (maybe "0" showHex size)
testMipsEb :: IO ()
testMipsEb = do
putStrLn "Emulate MIPS code (big-endian)"
result <- runEmulator $ do
-- Initialize emulator in MIPS mode
uc <- open ArchMips [ModeMips32, ModeBigEndian]
-- Map 2MB memory for this emulation
memMap uc address (2 * 1024 * 1024) [ProtAll]
-- Write machine code to be emulated to memory
memWrite uc address mipsCodeEb
-- Initialise machine registers
regWrite uc Mips.Reg1 0x6789
-- Tracing all basic blocks with customized callback
blockHookAdd uc hookBlock () 1 0
-- Tracing one instruction at address with customized callback
codeHookAdd uc hookCode () address address
-- Emulate machine code in infinite time (last param = Nothing), or
-- when finishing all the code
let codeLen = codeLength mipsCodeEb
start uc address (address + codeLen) Nothing Nothing
-- Return the results
r1 <- regRead uc Mips.Reg1
return r1
case result of
Right r1 -> do
-- Now print out some registers
putStrLn ">>> Emulation done. Below is the CPU context"
putStrLn $ ">>> R1 = 0x" ++ showHex r1
Left err -> putStrLn $ "Failed with error: " ++ show err ++ " (" ++
strerror err ++ ")"
testMipsEl :: IO ()
testMipsEl = do
putStrLn "==========================="
putStrLn "Emulate MIPS code (little-endian)"
result <- runEmulator $ do
-- Initialize emulator in MIPS mode
uc <- open ArchMips [ModeMips32, ModeLittleEndian]
-- Map 2MB memory for this emulation
memMap uc address (2 * 1024 * 1024) [ProtAll]
-- Write machine code to be emulated to memory
memWrite uc address mipsCodeEl
-- Initialize machine registers
regWrite uc Mips.Reg1 0x6789
-- Tracing all basic blocks with customized callback
blockHookAdd uc hookBlock () 1 0
-- Tracing one instruction at address with customized callback
codeHookAdd uc hookCode () address address
-- Emulate machine code in infinite time (last param = Nothing), or
-- when finishing all the code
let codeLen = codeLength mipsCodeEl
start uc address (address + codeLen) Nothing Nothing
-- Return the results
r1 <- regRead uc Mips.Reg1
return r1
case result of
Right r1 -> do
-- Now print out some registers
putStrLn ">>> Emulation done. Below is the CPU context"
putStrLn $ ">>> R1 = 0x" ++ showHex r1
Left err -> putStrLn $ "Failed with error: " ++ show err ++ " (" ++
strerror err ++ ")"
main :: IO ()
main = do
testMipsEb
testMipsEl