content: -- Sample code to demonstrate how to emulate ARM64 code
  
  import Unicorn
  import Unicorn.Hook
  import qualified Unicorn.CPU.Arm64 as Arm64
  
  import qualified Data.ByteString as BS
  import Data.Word
  import qualified Numeric as N (showHex)
  
  -- Code to be emulated
  --
  -- add x11, x13, x15
  armCode :: BS.ByteString
  armCode = BS.pack [0xab, 0x01, 0x0f, 0x8b]
  
  -- 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)
  
  testArm64 :: IO ()
  testArm64 = do
      putStrLn "Emulate ARM64 code"
  
      result <- runEmulator $ do
          -- Initialize emulator in ARM mode
          uc <- open ArchArm64 [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 Arm64.X11 0x1234
          regWrite uc Arm64.X13 0x6789
          regWrite uc Arm64.X15 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
          x11 <- regRead uc Arm64.X11
  
          return x11
      case result of
          Right x11 -> do
              -- Now print out some registers
              putStrLn $ ">>> Emulation done. Below is the CPU context"
              putStrLn $ ">>> X11 = 0x" ++ showHex x11
          Left err -> putStrLn $ "Failed with error: " ++ show err ++ " (" ++
                                 strerror err ++ ")"
  
  main :: IO ()
  main =
      testArm64
  