blockHookAdd :: Storable a
             => Engine          -- ^ 'Unicorn' engine handle
             -> BlockHook a     -- ^ Block 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
blockHookAdd uc callback userData begin end = do
    result <- lift . alloca $ \userDataPtr -> do
        poke userDataPtr userData
        funPtr <- marshalBlockHook callback
        getResult $ ucHookAdd uc HookBlock funPtr userDataPtr begin end
    hoistEither result

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

-- | Register a callback for an IN instruction hook event (X86).
blockHookAdd uc callback userData begin end = do
    result <- lift . alloca $ \userDataPtr -> do
        poke userDataPtr userData
        funPtr <- marshalBlockHook callback
        getResult $ ucHookAdd uc HookBlock funPtr userDataPtr begin end
    hoistEither result

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