interruptHookAdd :: Storable a
                 => Engine          -- ^ 'Unicorn' engine handle
                 -> InterruptHook a -- ^ Interrupt 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 'Error'
                                    -- on failure
interruptHookAdd uc callback userData begin end = do
    result <- lift . alloca $ \userDataPtr -> do
        poke userDataPtr userData
        funPtr <- marshalInterruptHook callback
        getResult $ ucHookAdd uc HookIntr funPtr userDataPtr begin end
    hoistEither result

-- | Register a callback for a block hook event.
interruptHookAdd :: Storable a
                 => Engine          -- ^ 'Unicorn' engine handle
                 -> InterruptHook a -- ^ Interrupt callback
                 -> a               -- ^ User-defined data. This will be passed
                                    -- to the callback function
                 -> Word64          -- ^ Start address
                 -> Word64          -- ^ End address
                 -> Emulator Hook
interruptHookAdd uc callback userData begin end = do
    result <- lift . alloca $ \userDataPtr -> do
        poke userDataPtr userData
        funPtr <- marshalInterruptHook callback
        getResult $ ucHookAdd uc HookIntr funPtr userDataPtr begin end
    hoistEither result

-- | Register a callback for a block hook event.
interruptHookAdd uc callback userData begin end = do
    result <- lift . alloca $ \userDataPtr -> do
        poke userDataPtr userData
        funPtr <- marshalInterruptHook callback
        getResult $ ucHookAdd uc HookIntr funPtr userDataPtr begin end
    hoistEither result

-- | Register a callback for a block hook event.