Updates to Haskell bindings (#667)

* [haskell] Added uc_context_* support

As per issue #662

* [haskell] Updated bindings for commit 4083b87032

Updated for introduction of UC_HOOK_MEM_READ_AFTER.

* [haskell] Style fixes
This commit is contained in:
Adrian Herrera
2016-10-30 03:51:02 +01:00
committed by Nguyen Anh Quynh
parent 4d5738eeb5
commit 19028f41f6
15 changed files with 594 additions and 410 deletions

View File

@@ -17,31 +17,34 @@ import Control.Monad
import Control.Monad.Trans.Either (EitherT)
import Foreign
{# context lib="unicorn" #}
{# context lib = "unicorn" #}
#include <unicorn/unicorn.h>
#include "unicorn_wrapper.h"
-- | The Unicorn engine.
{# pointer *uc_engine as Engine
foreign finalizer uc_close_wrapper as close
newtype #}
foreign finalizer uc_close_wrapper as close
newtype
#}
-- | A pointer to a Unicorn engine.
{# pointer *uc_engine as EnginePtr -> Engine #}
-- | Make a new Unicorn engine out of an engine pointer. The returned Unicorn
-- engine will automatically call 'uc_close_wrapper' when it goes out of scope.
mkEngine :: EnginePtr -> IO Engine
mkEngine :: EnginePtr
-> IO Engine
mkEngine ptr =
liftM Engine (newForeignPtr close ptr)
-- | Errors encountered by the Unicorn API. These values are returned by
-- 'errno'.
{# enum uc_err as Error
{underscoreToCase}
with prefix="UC_"
deriving (Show, Eq, Bounded) #}
{ underscoreToCase }
with prefix = "UC_"
deriving (Show, Eq, Bounded)
#}
-- | The emulator runs in the IO monad and allows for the handling of errors
-- "under the hood".

View File

@@ -11,54 +11,54 @@ Low-level bindings for inserting hook points into the Unicorn emulator engine.
This module should not be directly imported; it is only exposed because of the
way cabal handles ordering of chs files.
-}
module Unicorn.Internal.Hook (
-- * Types
Hook,
HookType(..),
MemoryHookType(..),
MemoryEventHookType(..),
MemoryAccess(..),
module Unicorn.Internal.Hook
( -- * Types
Hook
, HookType(..)
, MemoryHookType(..)
, MemoryEventHookType(..)
, MemoryAccess(..)
-- * Hook callback bindings
CodeHook,
InterruptHook,
BlockHook,
InHook,
OutHook,
SyscallHook,
MemoryHook,
MemoryReadHook,
MemoryWriteHook,
MemoryEventHook,
-- * Hook callback bindings
, CodeHook
, InterruptHook
, BlockHook
, InHook
, OutHook
, SyscallHook
, MemoryHook
, MemoryReadHook
, MemoryWriteHook
, MemoryEventHook
-- * Hook marshalling
marshalCodeHook,
marshalInterruptHook,
marshalBlockHook,
marshalInHook,
marshalOutHook,
marshalSyscallHook,
marshalMemoryHook,
marshalMemoryReadHook,
marshalMemoryWriteHook,
marshalMemoryEventHook,
-- * Hook marshallin
, marshalCodeHook
, marshalInterruptHook
, marshalBlockHook
, marshalInHook
, marshalOutHook
, marshalSyscallHook
, marshalMemoryHook
, marshalMemoryReadHook
, marshalMemoryWriteHook
, marshalMemoryEventHook
-- * Hook registration and deletion bindings
ucHookAdd,
ucInsnHookAdd,
ucHookDel,
) where
-- * Hook registration and deletion bindings
, ucHookAdd
, ucInsnHookAdd
, ucHookDel
) where
import Control.Monad
import Foreign
import Unicorn.Internal.Util
{# context lib="unicorn" #}
{# import Unicorn.Internal.Core #}
{# import Unicorn.CPU.X86 #}
{# context lib = "unicorn" #}
#include <unicorn/unicorn.h>
#include "unicorn_wrapper.h"
@@ -79,7 +79,8 @@ import Unicorn.Internal.Util
foreign import ccall "&uc_close_dummy"
closeDummy :: FunPtr (EnginePtr -> IO ())
mkEngineNC :: EnginePtr -> IO Engine
mkEngineNC :: EnginePtr
-> IO Engine
mkEngineNC ptr =
liftM Engine (newForeignPtr closeDummy ptr)
@@ -92,47 +93,55 @@ type Hook = {# type uc_hook #}
-- Note that the both valid and invalid memory access hooks are omitted from
-- this enum (and are exposed to the user).
{# enum uc_hook_type as HookType
{underscoreToCase}
omit (UC_HOOK_MEM_READ_UNMAPPED,
UC_HOOK_MEM_WRITE_UNMAPPED,
UC_HOOK_MEM_FETCH_UNMAPPED,
UC_HOOK_MEM_READ_PROT,
UC_HOOK_MEM_WRITE_PROT,
UC_HOOK_MEM_FETCH_PROT,
UC_HOOK_MEM_READ,
UC_HOOK_MEM_WRITE,
UC_HOOK_MEM_FETCH)
with prefix="UC_"
deriving (Show, Eq, Bounded) #}
{ underscoreToCase }
omit ( UC_HOOK_MEM_READ_UNMAPPED
, UC_HOOK_MEM_WRITE_UNMAPPED
, UC_HOOK_MEM_FETCH_UNMAPPED
, UC_HOOK_MEM_READ_PROT
, UC_HOOK_MEM_WRITE_PROT
, UC_HOOK_MEM_FETCH_PROT
, UC_HOOK_MEM_READ
, UC_HOOK_MEM_WRITE
, UC_HOOK_MEM_FETCH
, UC_HOOK_MEM_READ_AFTER
)
with prefix = "UC_"
deriving (Show, Eq, Bounded)
#}
-- | Memory hook types (for valid memory accesses).
{# enum uc_hook_type as MemoryHookType
{underscoreToCase}
omit (UC_HOOK_INTR,
UC_HOOK_INSN,
UC_HOOK_CODE,
UC_HOOK_BLOCK,
UC_HOOK_MEM_READ_UNMAPPED,
UC_HOOK_MEM_WRITE_UNMAPPED,
UC_HOOK_MEM_FETCH_UNMAPPED,
UC_HOOK_MEM_READ_PROT,
UC_HOOK_MEM_WRITE_PROT,
UC_HOOK_MEM_FETCH_PROT)
with prefix="UC_"
deriving (Show, Eq, Bounded) #}
{ underscoreToCase }
omit ( UC_HOOK_INTR
, UC_HOOK_INSN
, UC_HOOK_CODE
, UC_HOOK_BLOCK
, UC_HOOK_MEM_READ_UNMAPPED
, UC_HOOK_MEM_WRITE_UNMAPPED
, UC_HOOK_MEM_FETCH_UNMAPPED
, UC_HOOK_MEM_READ_PROT
, UC_HOOK_MEM_WRITE_PROT
, UC_HOOK_MEM_FETCH_PROT
)
with prefix = "UC_"
deriving (Show, Eq, Bounded)
#}
-- | Memory event hook types (for invalid memory accesses).
{# enum uc_hook_type as MemoryEventHookType
{underscoreToCase}
omit (UC_HOOK_INTR,
UC_HOOK_INSN,
UC_HOOK_CODE,
UC_HOOK_BLOCK,
UC_HOOK_MEM_READ,
UC_HOOK_MEM_WRITE,
UC_HOOK_MEM_FETCH)
with prefix="UC_"
deriving (Show, Eq, Bounded) #}
{ underscoreToCase }
omit ( UC_HOOK_INTR
, UC_HOOK_INSN
, UC_HOOK_CODE
, UC_HOOK_BLOCK
, UC_HOOK_MEM_READ
, UC_HOOK_MEM_WRITE
, UC_HOOK_MEM_FETCH
, UC_HOOK_MEM_READ_AFTER
)
with prefix = "UC_"
deriving (Show, Eq, Bounded)
#}
-- | Unify the hook types with a type class
class Enum a => HookTypeC a
@@ -143,9 +152,10 @@ instance HookTypeC MemoryEventHookType
-- | Memory access.
{# enum uc_mem_type as MemoryAccess
{underscoreToCase}
with prefix="UC_"
deriving (Show, Eq, Bounded) #}
{ underscoreToCase }
with prefix = "UC_"
deriving (Show, Eq, Bounded)
#}
-------------------------------------------------------------------------------
-- Hook callbacks
@@ -159,16 +169,18 @@ type CodeHook a = Engine -- ^ 'Unicorn' engine handle
-> a -- ^ User data passed to tracing APIs
-> IO ()
type CCodeHook = EnginePtr -> Word64 -> Word32 -> Ptr () -> IO ()
type CCodeHook = EnginePtr -> Word64 -> Word32 -> Ptr () -> IO ()
foreign import ccall "wrapper"
mkCodeHook :: CCodeHook -> IO {# type uc_cb_hookcode_t #}
mkCodeHook :: CCodeHook
-> IO {# type uc_cb_hookcode_t #}
marshalCodeHook :: Storable a
=> CodeHook a -> IO {# type uc_cb_hookcode_t #}
=> CodeHook a
-> IO {# type uc_cb_hookcode_t #}
marshalCodeHook codeHook =
mkCodeHook $ \ucPtr address size userDataPtr -> do
uc <- mkEngineNC ucPtr
uc <- mkEngineNC ucPtr
userData <- castPtrAndPeek userDataPtr
let maybeSize = if size == 0 then Nothing
else Just $ fromIntegral size
@@ -186,10 +198,11 @@ foreign import ccall "wrapper"
mkInterruptHook :: CInterruptHook -> IO {# type uc_cb_hookintr_t #}
marshalInterruptHook :: Storable a
=> InterruptHook a -> IO {# type uc_cb_hookintr_t #}
=> InterruptHook a
-> IO {# type uc_cb_hookintr_t #}
marshalInterruptHook interruptHook =
mkInterruptHook $ \ucPtr intNo userDataPtr -> do
uc <- mkEngineNC ucPtr
uc <- mkEngineNC ucPtr
userData <- castPtrAndPeek userDataPtr
interruptHook uc (fromIntegral intNo) userData
@@ -197,7 +210,8 @@ marshalInterruptHook interruptHook =
type BlockHook a = CodeHook a
marshalBlockHook :: Storable a
=> BlockHook a -> IO {# type uc_cb_hookcode_t #}
=> BlockHook a
-> IO {# type uc_cb_hookcode_t #}
marshalBlockHook =
marshalCodeHook
@@ -214,10 +228,11 @@ foreign import ccall "wrapper"
mkInHook :: CInHook -> IO {# type uc_cb_insn_in_t #}
marshalInHook :: Storable a
=> InHook a -> IO {# type uc_cb_insn_in_t #}
=> InHook a
-> IO {# type uc_cb_insn_in_t #}
marshalInHook inHook =
mkInHook $ \ucPtr port size userDataPtr -> do
uc <- mkEngineNC ucPtr
uc <- mkEngineNC ucPtr
userData <- castPtrAndPeek userDataPtr
inHook uc (fromIntegral port) (fromIntegral size) userData
@@ -232,13 +247,15 @@ type OutHook a = Engine -- ^ 'Unicorn' engine handle
type COutHook = EnginePtr -> Word32 -> Int32 -> Word32 -> Ptr () -> IO ()
foreign import ccall "wrapper"
mkOutHook :: COutHook -> IO {# type uc_cb_insn_out_t #}
mkOutHook :: COutHook
-> IO {# type uc_cb_insn_out_t #}
marshalOutHook :: Storable a
=> OutHook a -> IO {# type uc_cb_insn_out_t #}
=> OutHook a
-> IO {# type uc_cb_insn_out_t #}
marshalOutHook outHook =
mkOutHook $ \ucPtr port size value userDataPtr -> do
uc <- mkEngineNC ucPtr
uc <- mkEngineNC ucPtr
userData <- castPtrAndPeek userDataPtr
outHook uc (fromIntegral port) (fromIntegral size) (fromIntegral value)
userData
@@ -251,13 +268,15 @@ type SyscallHook a = Engine -- ^ 'Unicorn' engine handle
type CSyscallHook = Ptr () -> Ptr () -> IO ()
foreign import ccall "wrapper"
mkSyscallHook :: CSyscallHook -> IO {# type uc_cb_insn_syscall_t #}
mkSyscallHook :: CSyscallHook
-> IO {# type uc_cb_insn_syscall_t #}
marshalSyscallHook :: Storable a
=> SyscallHook a -> IO {# type uc_cb_insn_syscall_t #}
=> SyscallHook a
-> IO {# type uc_cb_insn_syscall_t #}
marshalSyscallHook syscallHook =
mkSyscallHook $ \ucPtr userDataPtr -> do
uc <- mkEngineNC $ castPtr ucPtr
uc <- mkEngineNC $ castPtr ucPtr
userData <- castPtrAndPeek userDataPtr
syscallHook uc userData
@@ -281,13 +300,15 @@ type CMemoryHook = EnginePtr
-> IO ()
foreign import ccall "wrapper"
mkMemoryHook :: CMemoryHook -> IO {# type uc_cb_hookmem_t #}
mkMemoryHook :: CMemoryHook
-> IO {# type uc_cb_hookmem_t #}
marshalMemoryHook :: Storable a
=> MemoryHook a -> IO {# type uc_cb_hookmem_t #}
=> MemoryHook a
-> IO {# type uc_cb_hookmem_t #}
marshalMemoryHook memoryHook =
mkMemoryHook $ \ucPtr memAccessI address size value userDataPtr -> do
uc <- mkEngineNC ucPtr
uc <- mkEngineNC ucPtr
userData <- castPtrAndPeek userDataPtr
let memAccess = toMemAccess memAccessI
maybeValue = case memAccess of
@@ -304,10 +325,11 @@ type MemoryReadHook a = Engine -- ^ 'Unicorn' engine handle
-> IO ()
marshalMemoryReadHook :: Storable a
=> MemoryReadHook a -> IO {# type uc_cb_hookmem_t #}
=> MemoryReadHook a
-> IO {# type uc_cb_hookmem_t #}
marshalMemoryReadHook memoryReadHook =
mkMemoryHook $ \ucPtr _ address size _ userDataPtr -> do
uc <- mkEngineNC ucPtr
uc <- mkEngineNC ucPtr
userData <- castPtrAndPeek userDataPtr
memoryReadHook uc address (fromIntegral size) userData
@@ -321,10 +343,11 @@ type MemoryWriteHook a = Engine -- ^ 'Unicorn' engine handle
-> IO ()
marshalMemoryWriteHook :: Storable a
=> MemoryWriteHook a -> IO {# type uc_cb_hookmem_t #}
=> MemoryWriteHook a
-> IO {# type uc_cb_hookmem_t #}
marshalMemoryWriteHook memoryWriteHook =
mkMemoryHook $ \ucPtr _ address size value userDataPtr -> do
uc <- mkEngineNC ucPtr
uc <- mkEngineNC ucPtr
userData <- castPtrAndPeek userDataPtr
memoryWriteHook uc address (fromIntegral size) (fromIntegral value)
userData
@@ -351,15 +374,17 @@ type CMemoryEventHook = EnginePtr
-> IO Int32
foreign import ccall "wrapper"
mkMemoryEventHook :: CMemoryEventHook -> IO {# type uc_cb_eventmem_t #}
mkMemoryEventHook :: CMemoryEventHook
-> IO {# type uc_cb_eventmem_t #}
marshalMemoryEventHook :: Storable a
=> MemoryEventHook a -> IO {# type uc_cb_eventmem_t #}
=> MemoryEventHook a
-> IO {# type uc_cb_eventmem_t #}
marshalMemoryEventHook eventMemoryHook =
mkMemoryEventHook $ \ucPtr memAccessI address size value userDataPtr -> do
uc <- mkEngineNC ucPtr
uc <- mkEngineNC ucPtr
userData <- castPtrAndPeek userDataPtr
let memAccess = toMemAccess memAccessI
let memAccess = toMemAccess memAccessI
maybeValue = case memAccess of
MemReadUnmapped -> Nothing
MemReadProt -> Nothing
@@ -369,7 +394,7 @@ marshalMemoryEventHook eventMemoryHook =
res <- eventMemoryHook uc memAccess address (fromIntegral size)
maybeValue userData
return $ boolToInt res
where boolToInt True = 1
where boolToInt True = 1
boolToInt False = 0
@@ -378,38 +403,43 @@ marshalMemoryEventHook eventMemoryHook =
-------------------------------------------------------------------------------
{# fun variadic uc_hook_add as ucHookAdd
`(Storable a, HookTypeC h)' =>
{`Engine',
alloca- `Hook' peek*,
enumToNum `h',
castFunPtrToPtr `FunPtr b',
castPtr `Ptr a',
`Word64',
`Word64'}
-> `Error' #}
`HookTypeC h' =>
{ `Engine'
, alloca- `Hook' peek*
, enumToNum `h'
, castFunPtrToPtr `FunPtr b'
, castPtr `Ptr a'
, `Word64'
, `Word64'
} -> `Error'
#}
{# fun variadic uc_hook_add[int] as ucInsnHookAdd
`(Storable a, HookTypeC h)' =>
{`Engine',
alloca- `Hook' peek*,
enumToNum `h',
castFunPtrToPtr `FunPtr b',
castPtr `Ptr a',
`Word64',
`Word64',
enumToNum `Instruction'}
-> `Error' #}
`HookTypeC h' =>
{ `Engine'
, alloca- `Hook' peek*
, enumToNum `h'
, castFunPtrToPtr `FunPtr b'
, castPtr `Ptr a'
, `Word64'
, `Word64'
, enumToNum `Instruction'
} -> `Error'
#}
-- | Unregister (remove) a hook callback.
{# fun uc_hook_del as ^
{`Engine',
fromIntegral `Hook'}
-> `Error' #}
{ `Engine'
, fromIntegral `Hook'
} -> `Error'
#}
-------------------------------------------------------------------------------
-- Helper functions
-------------------------------------------------------------------------------
toMemAccess :: Integral a => a -> MemoryAccess
toMemAccess :: Integral a
=> a
-> MemoryAccess
toMemAccess =
toEnum . fromIntegral

View File

@@ -12,33 +12,39 @@ Low-level bindings for the Unicorn CPU emulator framework.
This module should not be directly imported; it is only exposed because of the
way cabal handles ordering of chs files.
-}
module Unicorn.Internal.Unicorn (
-- * Types
Architecture(..),
Mode(..),
MemoryPermission(..),
MemoryRegion(..),
QueryType(..),
module Unicorn.Internal.Unicorn
( -- * Types
Architecture(..)
, Mode(..)
, MemoryPermission(..)
, MemoryRegion(..)
, QueryType(..)
, Context
-- * Function bindings
ucOpen,
ucQuery,
ucEmuStart,
ucEmuStop,
ucRegWrite,
ucRegRead,
ucMemWrite,
ucMemRead,
ucMemMap,
ucMemUnmap,
ucMemProtect,
ucMemRegions,
ucVersion,
ucErrno,
ucStrerror,
) where
-- * Function bindings
, ucOpen
, ucQuery
, ucEmuStart
, ucEmuStop
, ucRegWrite
, ucRegRead
, ucMemWrite
, ucMemRead
, ucMemMap
, ucMemUnmap
, ucMemProtect
, ucMemRegions
, mkContext
, ucContextAlloc
, ucContextSave
, ucContextRestore
, ucVersion
, ucErrno
, ucStrerror
) where
import Control.Applicative
import Control.Monad
import Data.ByteString (ByteString, useAsCStringLen)
import Foreign
import Foreign.C
@@ -46,11 +52,12 @@ import Prelude hiding (until)
import Unicorn.Internal.Util
{# context lib="unicorn" #}
{# import Unicorn.Internal.Core #}
{# context lib = "unicorn" #}
#include <unicorn/unicorn.h>
#include "unicorn_wrapper.h"
-------------------------------------------------------------------------------
-- Types
@@ -58,29 +65,33 @@ import Unicorn.Internal.Util
-- | CPU architecture.
{# enum uc_arch as Architecture
{underscoreToCase}
with prefix="UC_"
deriving (Show, Eq, Bounded) #}
{ underscoreToCase }
with prefix = "UC_"
deriving (Show, Eq, Bounded)
#}
-- | CPU hardware mode.
{# enum uc_mode as Mode
{underscoreToCase}
with prefix="UC_"
deriving (Show, Eq, Bounded) #}
{ underscoreToCase }
with prefix = "UC_"
deriving (Show, Eq, Bounded)
#}
-- | Memory permissions.
{# enum uc_prot as MemoryPermission
{underscoreToCase}
with prefix="UC_"
deriving (Show, Eq, Bounded) #}
{ underscoreToCase }
with prefix = "UC_"
deriving (Show, Eq, Bounded)
#}
-- | Memory region mapped by 'memMap'. Retrieve the list of memory regions with
-- 'memRegions'.
data MemoryRegion = MemoryRegion {
mrBegin :: Word64, -- ^ Begin address of the region (inclusive)
mrEnd :: Word64, -- ^ End address of the region (inclusive)
mrPerms :: [MemoryPermission] -- ^ Memory permissions of the region
}
data MemoryRegion = MemoryRegion
{
mrBegin :: Word64 -- ^ Begin address of the region (inclusive)
, mrEnd :: Word64 -- ^ End address of the region (inclusive)
, mrPerms :: [MemoryPermission] -- ^ Memory permissions of the region
}
instance Storable MemoryRegion where
sizeOf _ = {# sizeof uc_mem_region #}
@@ -99,121 +110,174 @@ instance Storable MemoryRegion where
-- | Query types for the 'query' API.
{# enum uc_query_type as QueryType
{underscoreToCase}
with prefix="UC_"
deriving (Show, Eq, Bounded) #}
{ underscoreToCase }
with prefix = "UC_"
deriving (Show, Eq, Bounded)
#}
-- | Opaque storage for CPU context, used with the context functions.
{# pointer *uc_context as Context
foreign finalizer uc_context_free_wrapper as contextFree
newtype
#}
-- | A pointer to a CPU context.
{# pointer *uc_context as ContextPtr -> Context #}
-- | Make a CPU context out of a context pointer. The returned CPU context will
-- automatically call 'uc_context_free' when it goes out of scope.
mkContext :: ContextPtr
-> IO Context
mkContext ptr =
liftM Context (newForeignPtr contextFree ptr)
-------------------------------------------------------------------------------
-- Emulator control
-------------------------------------------------------------------------------
{# fun uc_open as ^
{`Architecture',
combineEnums `[Mode]',
alloca- `EnginePtr' peek*}
-> `Error' #}
{ `Architecture'
, combineEnums `[Mode]'
, alloca- `EnginePtr' peek*
} -> `Error'
#}
{# fun uc_query as ^
{`Engine',
`QueryType',
alloca- `Int' castPtrAndPeek*}
-> `Error' #}
{ `Engine'
, `QueryType'
, alloca- `Int' castPtrAndPeek*
} -> `Error'
#}
{# fun uc_emu_start as ^
{`Engine',
`Word64',
`Word64',
`Int',
`Int'}
-> `Error' #}
{ `Engine'
, `Word64'
, `Word64'
, `Int'
, `Int'} -> `Error'
#}
{# fun uc_emu_stop as ^
{`Engine'}
-> `Error' #}
{ `Engine'
} -> `Error'
#}
-------------------------------------------------------------------------------
-- Register operations
-------------------------------------------------------------------------------
{# fun uc_reg_write as ^
`Reg r' =>
{`Engine',
enumToNum `r',
castPtr `Ptr Int64'}
-> `Error' #}
`Reg r' =>
{ `Engine'
, enumToNum `r'
, castPtr `Ptr Int64'
} -> `Error'
#}
{# fun uc_reg_read as ^
`Reg r' =>
{`Engine',
enumToNum `r',
allocaInt64ToVoid- `Int64' castPtrAndPeek*}
-> `Error' #}
`Reg r' =>
{ `Engine'
, enumToNum `r'
, allocaInt64ToVoid- `Int64' castPtrAndPeek*
} -> `Error'
#}
-------------------------------------------------------------------------------
-- Memory operations
-------------------------------------------------------------------------------
{# fun uc_mem_write as ^
{`Engine',
`Word64',
withByteStringLen* `ByteString'&}
-> `Error' #}
{ `Engine'
, `Word64'
, withByteStringLen* `ByteString'&
} -> `Error'
#}
{# fun uc_mem_read as ^
{`Engine',
`Word64',
castPtr `Ptr Word8',
`Int'}
-> `Error' #}
{ `Engine'
, `Word64'
, castPtr `Ptr Word8'
, `Int'} -> `Error'
#}
{# fun uc_mem_map as ^
{`Engine',
`Word64',
`Int',
combineEnums `[MemoryPermission]'}
-> `Error' #}
{ `Engine'
, `Word64'
, `Int'
, combineEnums `[MemoryPermission]'
} -> `Error' #}
{# fun uc_mem_unmap as ^
{`Engine',
`Word64',
`Int'}
-> `Error' #}
{ `Engine'
, `Word64'
, `Int'
} -> `Error'
#}
{# fun uc_mem_protect as ^
{`Engine',
`Word64',
`Int',
combineEnums `[MemoryPermission]'}
-> `Error' #}
{ `Engine'
, `Word64'
, `Int'
, combineEnums `[MemoryPermission]'
} -> `Error'
#}
{# fun uc_mem_regions as ^
{`Engine',
alloca- `MemoryRegionPtr' peek*,
alloca- `Int' castPtrAndPeek*}
-> `Error' #}
{ `Engine'
, alloca- `MemoryRegionPtr' peek*
, alloca- `Int' castPtrAndPeek*
} -> `Error'
#}
-------------------------------------------------------------------------------
-- Context
-------------------------------------------------------------------------------
{# fun uc_context_alloc as ^
{ `Engine'
, alloca- `ContextPtr' peek*
} -> `Error'
#}
{# fun uc_context_save as ^
{ `Engine'
, `Context'
} -> `Error'
#}
{# fun uc_context_restore as ^
{ `Engine'
, `Context'
} -> `Error'
#}
-------------------------------------------------------------------------------
-- Misc.
-------------------------------------------------------------------------------
{# fun pure unsafe uc_version as ^
{id `Ptr CUInt',
id `Ptr CUInt'}
-> `Int' #}
{ id `Ptr CUInt'
, id `Ptr CUInt'
} -> `Int'
#}
{# fun unsafe uc_errno as ^
{`Engine'}
-> `Error' #}
{ `Engine'
} -> `Error'
#}
{# fun pure unsafe uc_strerror as ^
{`Error'}
-> `String' #}
{ `Error'
} -> `String'
#}
-------------------------------------------------------------------------------
-- Helper functions
-------------------------------------------------------------------------------
expandMemPerms :: (Integral a, Bits a) => a -> [MemoryPermission]
expandMemPerms :: (Integral a, Bits a)
=> a
-> [MemoryPermission]
expandMemPerms perms =
-- Only interested in the 3 least-significant bits
let maskedPerms = fromIntegral $ perms .&. 0x7 in
@@ -232,10 +296,13 @@ expandMemPerms perms =
checkRWE _ [] =
[]
allocaInt64ToVoid :: (Ptr () -> IO b) -> IO b
allocaInt64ToVoid :: (Ptr () -> IO b)
-> IO b
allocaInt64ToVoid f =
alloca $ \(ptr :: Ptr Int64) -> poke ptr 0 >> f (castPtr ptr)
withByteStringLen :: ByteString -> ((Ptr (), CULong) -> IO a) -> IO a
withByteStringLen :: ByteString
-> ((Ptr (), CULong) -> IO a)
-> IO a
withByteStringLen bs f =
useAsCStringLen bs $ \(ptr, len) -> f (castPtr ptr, fromIntegral len)

View File

@@ -10,16 +10,22 @@ import Data.Bits
import Foreign
-- | Combine a list of Enums by performing a bitwise-OR.
combineEnums :: (Enum a, Num b, Bits b) => [a] -> b
combineEnums :: (Enum a, Num b, Bits b)
=> [a]
-> b
combineEnums =
foldr ((.|.) <$> enumToNum) 0
-- | Cast a pointer and then peek inside it.
castPtrAndPeek :: Storable a => Ptr b -> IO a
castPtrAndPeek :: Storable a
=> Ptr b
-> IO a
castPtrAndPeek =
peek . castPtr
-- | Convert an 'Eum' to a 'Num'.
enumToNum :: (Enum a, Num b) => a -> b
enumToNum :: (Enum a, Num b)
=> a
-> b
enumToNum =
fromIntegral . fromEnum