content: -- Sample code to demonstrate how to emulate ARM code
  
  import Unicorn
  import Unicorn.Hook
  import qualified Unicorn.CPU.Arm as Arm
  
  import Data.Bits
  import qualified Data.ByteString as BS
  import Data.Word
  import qualified Numeric as N (showHex)
  
  -- Code to be emulated
  --
  -- mov r0, #0x37; sub r1, r2, r3
  armCode :: BS.ByteString
  armCode = BS.pack [0x37, 0x00, 0xa0, 0xe3, 0x03, 0x10, 0x42, 0xe0]
  
  -- sub sp, #0xc
  thumbCode :: BS.ByteString
  thumbCode = BS.pack [0x83, 0xb0]
  
  -- 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)
  
  testArm :: IO ()
  testArm = do
      putStrLn "Emulate ARM code"
  
      result <- runEmulator $ do
          -- Initialize emulator in ARM mode
          uc <- open ArchArm [ModeArm]
  
          -- Map 2MB memory for this emulation
          memMap uc address (2 * 1024 * 1024) [ProtAll]
  
          -- Write machine code to be emulated to memory
          memWrite uc address armCode
  
          -- Initialize machine registers
          regWrite uc Arm.R0 0x1234
          regWrite uc Arm.R2 0x6789
          regWrite uc Arm.R3 0x3333
  
          -- 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 armCode
          start uc address (address + codeLen) Nothing Nothing
  
          -- Return the results
          r0 <- regRead uc Arm.R0
          r1 <- regRead uc Arm.R1
  
          return (r0, r1)
      case result of
          Right (r0, r1) -> do
              -- Now print out some registers
              putStrLn ">>> Emulation done. Below is the CPU context"
              putStrLn $ ">>> R0 = 0x" ++ showHex r0
              putStrLn $ ">>> R1 = 0x" ++ showHex r1
          Left err -> putStrLn $ "Failed with error: " ++ show err ++ " (" ++
                                  strerror err ++ ")"
  
  testThumb :: IO ()
  testThumb = do
      putStrLn "Emulate THUMB code"
  
      result <- runEmulator $ do
          -- Initialize emulator in ARM mode
          uc <- open ArchArm [ModeThumb]
  
          -- Map 2MB memory for this emulation
          memMap uc address (2 * 1024 * 1024) [ProtAll]
  
          -- Write machine code to be emulated to memory
          memWrite uc address thumbCode
  
          -- Initialize machine registers
          regWrite uc Arm.Sp 0x1234
  
          -- 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 thumbCode
          start uc (address .|. 1) (address + codeLen) Nothing Nothing
  
          -- Return the results
          sp <- regRead uc Arm.Sp
  
          return sp
      case result of
          Right sp -> do
              -- Now print out some registers
              putStrLn ">>> Emulation done. Below is the CPU context"
              putStrLn $ ">>> SP = 0x" ++ showHex sp
          Left err -> putStrLn $ "Failed with error: " ++ show err ++ " (" ++
                                 strerror err ++ ")"
  
  main :: IO ()
  main = do
      testArm
      putStrLn "=========================="
      testThumb
  