memoryHookAdd :: Storable a
              => Engine         -- ^ 'Unicorn' engine handle
              -> MemoryHookType -- ^ A valid memory access (e.g. read, write,
                                -- etc.) to trigger the callback on
              -> MemoryHook a   -- ^ Memory access 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
memoryHookAdd uc memHookType callback userData begin end = do
    result <- lift . alloca $ \userDataPtr -> do
        poke userDataPtr userData
        funPtr <- marshalMemoryHook callback
        getResult $ ucHookAdd uc memHookType funPtr userDataPtr begin end
    hoistEither result

-- | Register a callback for an invalid memory access event.
memoryHookAdd :: Storable a
              => Engine         -- ^ 'Unicorn' engine handle
              -> MemoryHookType -- ^ A valid memory access (e.g. read, write,
                                -- etc.) to trigger the callback on
              -> MemoryHook a   -- ^ Memory access callback
              -> a              -- ^ User-defined data. This will be passed to
                                -- the callback function
              -> Word64         -- ^ Start address
              -> Word64         -- ^ End address
              -> Emulator Hook
memoryHookAdd uc memHookType callback userData begin end = do
    result <- lift . alloca $ \userDataPtr -> do
        poke userDataPtr userData
        funPtr <- marshalMemoryHook callback
        getResult $ ucHookAdd uc memHookType funPtr userDataPtr begin end
    hoistEither result

-- | Register a callback for an invalid memory access event.
memoryHookAdd uc memHookType callback userData begin end = do
    result <- lift . alloca $ \userDataPtr -> do
        poke userDataPtr userData
        funPtr <- marshalMemoryHook callback
        getResult $ ucHookAdd uc memHookType funPtr userDataPtr begin end
    hoistEither result

-- | Register a callback for an invalid memory access event.