inHookAdd :: Storable a
          => Engine         -- ^ 'Unicorn' engine handle
          -> InHook a       -- ^ IN instruction callback
          -> a              -- ^ User-defined data. This will be passed to the
                            -- callback function
          -> Word64         -- ^ Start address
          -> Word64         -- ^ End address
          -> Emulator Hook  -- ^ The hook handle on success, or an 'Error' on
                            -- failure
inHookAdd uc callback userData begin end = do
    result <- lift . alloca $ \userDataPtr -> do
        poke userDataPtr userData
        funPtr <- marshalInHook callback
        getResult $ ucInsnHookAdd uc HookInsn funPtr userDataPtr begin end
                                  X86.In
    hoistEither result

-- | Register a callback for an OUT instruction hook event (X86).
inHookAdd :: Storable a
          => Engine         -- ^ 'Unicorn' engine handle
          -> InHook a       -- ^ IN instruction callback
          -> a              -- ^ User-defined data. This will be passed to the
                            -- callback function
          -> Word64         -- ^ Start address
          -> Word64         -- ^ End address
          -> Emulator Hook
inHookAdd uc callback userData begin end = do
    result <- lift . alloca $ \userDataPtr -> do
        poke userDataPtr userData
        funPtr <- marshalInHook callback
        getResult $ ucInsnHookAdd uc HookInsn funPtr userDataPtr begin end
                                  X86.In
    hoistEither result

-- | Register a callback for an OUT instruction hook event (X86).
inHookAdd uc callback userData begin end = do
    result <- lift . alloca $ \userDataPtr -> do
        poke userDataPtr userData
        funPtr <- marshalInHook callback
        getResult $ ucInsnHookAdd uc HookInsn funPtr userDataPtr begin end
                                  X86.In
    hoistEither result

-- | Register a callback for an OUT instruction hook event (X86).