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

@ -9,41 +9,47 @@ framework based on QEMU.
Further information is available at <http://www.unicorn-engine.org>. Further information is available at <http://www.unicorn-engine.org>.
-} -}
module Unicorn ( module Unicorn
-- * Emulator control ( -- * Emulator control
Emulator, Emulator
Engine, , Engine
Architecture(..), , Architecture(..)
Mode(..), , Mode(..)
QueryType(..), , QueryType(..)
runEmulator, , runEmulator
open, , open
query, , query
start, , start
stop, , stop
-- * Register operations -- * Register operations
regWrite, , regWrite
regRead, , regRead
-- * Memory operations -- * Memory operations
MemoryPermission(..), , MemoryPermission(..)
MemoryRegion(..), , MemoryRegion(..)
memWrite, , memWrite
memRead, , memRead
memMap, , memMap
memUnmap, , memUnmap
memProtect, , memProtect
memRegions, , memRegions
-- * Error handling -- * Context operations
Error(..), , Context
errno, , contextAlloc
strerror, , contextSave
, contextRestore
-- * Misc. -- * Error handling
version, , Error(..)
) where , errno
, strerror
-- * Misc.
, version
) where
import Control.Monad (liftM) import Control.Monad (liftM)
import Control.Monad.Trans.Class (lift) import Control.Monad.Trans.Class (lift)
@ -132,8 +138,8 @@ stop uc = do
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
-- | Write to register. -- | Write to register.
regWrite :: Reg r => regWrite :: Reg r
Engine -- ^ 'Unicorn' engine handle => Engine -- ^ 'Unicorn' engine handle
-> r -- ^ Register ID to write to -> r -- ^ Register ID to write to
-> Int64 -- ^ Value to write to register -> Int64 -- ^ Value to write to register
-> Emulator () -- ^ An 'Error' on failure -> Emulator () -- ^ An 'Error' on failure
@ -147,8 +153,8 @@ regWrite uc regId value = do
left err left err
-- | Read register value. -- | Read register value.
regRead :: Reg r => regRead :: Reg r
Engine -- ^ 'Unicorn' engine handle => Engine -- ^ 'Unicorn' engine handle
-> r -- ^ Register ID to read from -> r -- ^ Register ID to read from
-> Emulator Int64 -- ^ The value read from the register on success, -> Emulator Int64 -- ^ The value read from the register on success,
-- or an 'Error' on failure -- or an 'Error' on failure
@ -259,6 +265,46 @@ memRegions uc = do
else else
left err left err
-------------------------------------------------------------------------------
-- Context operations
-------------------------------------------------------------------------------
-- | Allocate a region that can be used to perform quick save/rollback of the
-- CPU context, which includes registers and some internal metadata. Contexts
-- may not be shared across engine instances with differing architectures or
-- modes.
contextAlloc :: Engine -- ^ 'Unicon' engine handle
-> Emulator Context -- ^ A CPU context
contextAlloc uc = do
(err, contextPtr) <- lift $ ucContextAlloc uc
if err == ErrOk then
-- Return a CPU context if ucContextAlloc completed successfully
lift $ mkContext contextPtr
else
left err
-- | Save a copy of the internal CPU context.
contextSave :: Engine -- ^ 'Unicorn' engine handle
-> Context -- ^ A CPU context
-> Emulator () -- ^ An error on failure
contextSave uc context = do
err <- lift $ ucContextSave uc context
if err == ErrOk then
right ()
else
left err
-- | Restore the current CPU context from a saved copy.
contextRestore :: Engine -- ^ 'Unicorn' engine handle
-> Context -- ^ A CPU context
-> Emulator () -- ^ An error on failure
contextRestore uc context = do
err <- lift $ ucContextRestore uc context
if err == ErrOk then
right ()
else
left err
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
-- Misc. -- Misc.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------

View File

@ -8,22 +8,25 @@ License : GPL-2
Definitions for the ARM architecture. Definitions for the ARM architecture.
-} -}
module Unicorn.CPU.Arm ( module Unicorn.CPU.Arm
Register(..), (
) where Register(..)
) where
import Unicorn.Internal.Core (Reg) import Unicorn.Internal.Core (Reg)
{# context lib="unicorn" #} {# context lib = "unicorn" #}
#include <unicorn/arm.h> #include <unicorn/arm.h>
-- | ARM registers. -- | ARM registers.
{# enum uc_arm_reg as Register {# enum uc_arm_reg as Register
{underscoreToCase} { underscoreToCase }
omit (UC_ARM_REG_INVALID, omit ( UC_ARM_REG_INVALID
UC_ARM_REG_ENDING) , UC_ARM_REG_ENDING
with prefix="UC_ARM_REG_" )
deriving (Show, Eq, Bounded) #} with prefix = "UC_ARM_REG_"
deriving (Show, Eq, Bounded)
#}
instance Reg Register instance Reg Register

View File

@ -8,22 +8,25 @@ License : GPL-2
Definitions for the ARM64 (ARMv8) architecture. Definitions for the ARM64 (ARMv8) architecture.
-} -}
module Unicorn.CPU.Arm64 ( module Unicorn.CPU.Arm64
Register(..), (
) where Register(..)
) where
import Unicorn.Internal.Core (Reg) import Unicorn.Internal.Core (Reg)
{# context lib="unicorn" #} {# context lib = "unicorn" #}
#include <unicorn/arm64.h> #include <unicorn/arm64.h>
-- | ARM64 registers. -- | ARM64 registers.
{# enum uc_arm64_reg as Register {# enum uc_arm64_reg as Register
{underscoreToCase} { underscoreToCase }
omit (UC_ARM64_REG_INVALID, omit ( UC_ARM64_REG_INVALID
UC_ARM64_REG_ENDING) , UC_ARM64_REG_ENDING
with prefix="UC_ARM64_REG_" )
deriving (Show, Eq, Bounded) #} with prefix = "UC_ARM64_REG_"
deriving (Show, Eq, Bounded)
#}
instance Reg Register instance Reg Register

View File

@ -8,22 +8,25 @@ License : GPL-2
Definitions for the MK68K architecture. Definitions for the MK68K architecture.
-} -}
module Unicorn.CPU.M68k ( module Unicorn.CPU.M68k
Register(..), (
) where Register(..)
) where
import Unicorn.Internal.Core (Reg) import Unicorn.Internal.Core (Reg)
{# context lib="unicorn" #} {# context lib = "unicorn" #}
#include <unicorn/m68k.h> #include <unicorn/m68k.h>
-- | M68K registers. -- | M68K registers.
{# enum uc_m68k_reg as Register {# enum uc_m68k_reg as Register
{underscoreToCase} { underscoreToCase }
omit (UC_M68K_REG_INVALID, omit ( UC_M68K_REG_INVALID
UC_M68K_REG_ENDING) , UC_M68K_REG_ENDING
with prefix="UC_M68K_REG_" )
deriving (Show, Eq, Bounded) #} with prefix = "UC_M68K_REG_"
deriving (Show, Eq, Bounded)
#}
instance Reg Register instance Reg Register

View File

@ -8,54 +8,58 @@ License : GPL-2
Definitions for the MIPS architecture. Definitions for the MIPS architecture.
-} -}
module Unicorn.CPU.Mips ( module Unicorn.CPU.Mips
Register(..), (
) where Register(..)
) where
import Unicorn.Internal.Core (Reg) import Unicorn.Internal.Core (Reg)
{# context lib="unicorn" #} {# context lib = "unicorn" #}
#include <unicorn/mips.h> #include <unicorn/mips.h>
-- | MIPS registers. -- | MIPS registers.
{# enum UC_MIPS_REG as Register {# enum UC_MIPS_REG as Register
{underscoreToCase, { underscoreToCase
UC_MIPS_REG_0 as Reg0, , UC_MIPS_REG_0 as Reg0g
UC_MIPS_REG_1 as Reg1, , UC_MIPS_REG_1 as Reg1g
UC_MIPS_REG_2 as Reg2, , UC_MIPS_REG_2 as Reg2g
UC_MIPS_REG_3 as Reg3, , UC_MIPS_REG_3 as Reg3g
UC_MIPS_REG_4 as Reg4, , UC_MIPS_REG_4 as Reg4g
UC_MIPS_REG_5 as Reg5, , UC_MIPS_REG_5 as Reg5g
UC_MIPS_REG_6 as Reg6, , UC_MIPS_REG_6 as Reg6g
UC_MIPS_REG_7 as Reg7, , UC_MIPS_REG_7 as Reg7g
UC_MIPS_REG_8 as Reg8, , UC_MIPS_REG_8 as Reg8g
UC_MIPS_REG_9 as Reg9, , UC_MIPS_REG_9 as Reg9g
UC_MIPS_REG_10 as Reg10, , UC_MIPS_REG_10 as Reg10g
UC_MIPS_REG_11 as Reg11, , UC_MIPS_REG_11 as Reg11g
UC_MIPS_REG_12 as Reg12, , UC_MIPS_REG_12 as Reg12g
UC_MIPS_REG_13 as Reg13, , UC_MIPS_REG_13 as Reg13g
UC_MIPS_REG_14 as Reg14, , UC_MIPS_REG_14 as Reg14g
UC_MIPS_REG_15 as Reg15, , UC_MIPS_REG_15 as Reg15g
UC_MIPS_REG_16 as Reg16, , UC_MIPS_REG_16 as Reg16g
UC_MIPS_REG_17 as Reg17, , UC_MIPS_REG_17 as Reg17g
UC_MIPS_REG_18 as Reg18, , UC_MIPS_REG_18 as Reg18g
UC_MIPS_REG_19 as Reg19, , UC_MIPS_REG_19 as Reg19g
UC_MIPS_REG_20 as Reg20, , UC_MIPS_REG_20 as Reg20g
UC_MIPS_REG_21 as Reg21, , UC_MIPS_REG_21 as Reg21g
UC_MIPS_REG_22 as Reg22, , UC_MIPS_REG_22 as Reg22g
UC_MIPS_REG_23 as Reg23, , UC_MIPS_REG_23 as Reg23g
UC_MIPS_REG_24 as Reg24, , UC_MIPS_REG_24 as Reg24g
UC_MIPS_REG_25 as Reg25, , UC_MIPS_REG_25 as Reg25g
UC_MIPS_REG_26 as Reg26, , UC_MIPS_REG_26 as Reg26g
UC_MIPS_REG_27 as Reg27, , UC_MIPS_REG_27 as Reg27g
UC_MIPS_REG_28 as Reg28, , UC_MIPS_REG_28 as Reg28g
UC_MIPS_REG_29 as Reg29, , UC_MIPS_REG_29 as Reg29g
UC_MIPS_REG_30 as Reg30, , UC_MIPS_REG_30 as Reg30g
UC_MIPS_REG_31 as Reg31} , UC_MIPS_REG_31 as Reg31
omit (UC_MIPS_REG_INVALID, }
UC_MIPS_REG_ENDING) omit ( UC_MIPS_REG_INVALID
with prefix="UC_MIPS_REG_" , UC_MIPS_REG_ENDING
deriving (Show, Eq, Bounded) #} )
with prefix = "UC_MIPS_REG_"
deriving (Show, Eq, Bounded)
#}
instance Reg Register instance Reg Register

View File

@ -8,22 +8,25 @@ License : GPL-2
Definitions for the SPARC architecture. Definitions for the SPARC architecture.
-} -}
module Unicorn.CPU.Sparc ( module Unicorn.CPU.Sparc
Register(..), (
) where Register(..)
) where
import Unicorn.Internal.Core (Reg) import Unicorn.Internal.Core (Reg)
{# context lib="unicorn" #} {# context lib = "unicorn" #}
#include <unicorn/sparc.h> #include <unicorn/sparc.h>
-- | SPARC registers. -- | SPARC registers.
{# enum uc_sparc_reg as Register {# enum uc_sparc_reg as Register
{underscoreToCase} { underscoreToCase }
omit (UC_SPARC_REG_INVALID, omit (UC_SPARC_REG_INVALID
UC_SPARC_REG_ENDING) , UC_SPARC_REG_ENDING
with prefix="UC_SPARC_REG_" )
deriving (Show, Eq, Bounded) #} with prefix = "UC_SPARC_REG_"
deriving (Show, Eq, Bounded)
#}
instance Reg Register instance Reg Register

View File

@ -8,11 +8,12 @@ License : GPL-2
Definitions for the X86 architecture. Definitions for the X86 architecture.
-} -}
module Unicorn.CPU.X86 ( module Unicorn.CPU.X86
Mmr(..), (
Register(..), Mmr(..)
Instruction(..), , Register(..)
) where , Instruction(..)
) where
import Control.Applicative import Control.Applicative
import Data.Word import Data.Word
@ -20,18 +21,18 @@ import Foreign
import Unicorn.Internal.Core (Reg) import Unicorn.Internal.Core (Reg)
{# context lib="unicorn" #} {# context lib = "unicorn" #}
#include <unicorn/x86.h> #include <unicorn/x86.h>
-- | Memory-managemen Register for instructions IDTR, GDTR, LDTR, TR. -- | Memory-managemen Register for instructions IDTR, GDTR, LDTR, TR.
-- Borrow from SegmentCache in qemu/target-i386/cpu.h -- Borrow from SegmentCache in qemu/target-i386/cpu.h
data Mmr = Mmr { data Mmr = Mmr
mmrSelector :: Word16, -- ^ Not used by GDTR and IDTR { mmrSelector :: Word16 -- ^ Not used by GDTR and IDTR
mmrBase :: Word64, -- ^ Handle 32 or 64 bit CPUs , mmrBase :: Word64 -- ^ Handle 32 or 64 bit CPUs
mmrLimit :: Word32, , mmrLimit :: Word32
mmrFlags :: Word32 -- ^ Not used by GDTR and IDTR , mmrFlags :: Word32 -- ^ Not used by GDTR and IDTR
} }
instance Storable Mmr where instance Storable Mmr where
sizeOf _ = {# sizeof uc_x86_mmr #} sizeOf _ = {# sizeof uc_x86_mmr #}
@ -48,18 +49,22 @@ instance Storable Mmr where
-- | X86 registers. -- | X86 registers.
{# enum uc_x86_reg as Register {# enum uc_x86_reg as Register
{underscoreToCase} { underscoreToCase }
omit (UC_X86_REG_INVALID, omit ( UC_X86_REG_INVALID
UC_X86_REG_ENDING) , UC_X86_REG_ENDING
with prefix="UC_X86_REG_" )
deriving (Show, Eq, Bounded) #} with prefix = "UC_X86_REG_"
deriving (Show, Eq, Bounded)
#}
instance Reg Register instance Reg Register
-- | X86 instructions. -- | X86 instructions.
{# enum uc_x86_insn as Instruction {# enum uc_x86_insn as Instruction
{underscoreToCase} { underscoreToCase }
omit (UC_X86_INS_INVALID, omit ( UC_X86_INS_INVALID
UC_X86_INS_ENDING) , UC_X86_INS_ENDING
with prefix="UC_X86_INS_" )
deriving (Show, Eq, Bounded) #} with prefix = "UC_X86_INS_"
deriving (Show, Eq, Bounded)
#}

View File

@ -6,36 +6,36 @@ License : GPL-2
Insert hook points into the Unicorn emulator engine. Insert hook points into the Unicorn emulator engine.
-} -}
module Unicorn.Hook ( module Unicorn.Hook
-- * Hook types ( -- * Hook types
Hook, Hook
MemoryHookType(..), , MemoryHookType(..)
MemoryEventHookType(..), , MemoryEventHookType(..)
MemoryAccess(..), , MemoryAccess(..)
-- * Hook callbacks -- * Hook callbacks
CodeHook, , CodeHook
InterruptHook, , InterruptHook
BlockHook, , BlockHook
InHook, , InHook
OutHook, , OutHook
SyscallHook, , SyscallHook
MemoryHook, , MemoryHook
MemoryReadHook, , MemoryReadHook
MemoryWriteHook, , MemoryWriteHook
MemoryEventHook, , MemoryEventHook
-- * Hook callback management -- * Hook callback management
codeHookAdd, , codeHookAdd
interruptHookAdd, , interruptHookAdd
blockHookAdd, , blockHookAdd
inHookAdd, , inHookAdd
outHookAdd, , outHookAdd
syscallHookAdd, , syscallHookAdd
memoryHookAdd, , memoryHookAdd
memoryEventHookAdd, , memoryEventHookAdd
hookDel, , hookDel
) where ) where
import Control.Monad import Control.Monad
import Control.Monad.Trans.Class import Control.Monad.Trans.Class
@ -213,7 +213,8 @@ hookDel uc hook = do
-- Takes the tuple returned by `ucHookAdd`, an IO (Error, Hook), and -- Takes the tuple returned by `ucHookAdd`, an IO (Error, Hook), and
-- returns either a `Right Hook` if no error occurred or a `Left Error` if an -- returns either a `Right Hook` if no error occurred or a `Left Error` if an
-- error occurred -- error occurred
getResult :: IO (Error, Hook) -> IO (Either Error Hook) getResult :: IO (Error, Hook)
-> IO (Either Error Hook)
getResult = getResult =
liftM (uncurry checkResult) liftM (uncurry checkResult)
where checkResult err hook = where checkResult err hook =

View File

@ -17,31 +17,34 @@ import Control.Monad
import Control.Monad.Trans.Either (EitherT) import Control.Monad.Trans.Either (EitherT)
import Foreign import Foreign
{# context lib="unicorn" #} {# context lib = "unicorn" #}
#include <unicorn/unicorn.h> #include <unicorn/unicorn.h>
#include "unicorn_wrapper.h" #include "unicorn_wrapper.h"
-- | The Unicorn engine. -- | The Unicorn engine.
{# pointer *uc_engine as Engine {# pointer *uc_engine as Engine
foreign finalizer uc_close_wrapper as close foreign finalizer uc_close_wrapper as close
newtype #} newtype
#}
-- | A pointer to a Unicorn engine. -- | A pointer to a Unicorn engine.
{# pointer *uc_engine as EnginePtr -> Engine #} {# pointer *uc_engine as EnginePtr -> Engine #}
-- | Make a new Unicorn engine out of an engine pointer. The returned Unicorn -- | 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. -- engine will automatically call 'uc_close_wrapper' when it goes out of scope.
mkEngine :: EnginePtr -> IO Engine mkEngine :: EnginePtr
-> IO Engine
mkEngine ptr = mkEngine ptr =
liftM Engine (newForeignPtr close ptr) liftM Engine (newForeignPtr close ptr)
-- | Errors encountered by the Unicorn API. These values are returned by -- | Errors encountered by the Unicorn API. These values are returned by
-- 'errno'. -- 'errno'.
{# enum uc_err as Error {# enum uc_err as Error
{underscoreToCase} { underscoreToCase }
with prefix="UC_" with prefix = "UC_"
deriving (Show, Eq, Bounded) #} deriving (Show, Eq, Bounded)
#}
-- | The emulator runs in the IO monad and allows for the handling of errors -- | The emulator runs in the IO monad and allows for the handling of errors
-- "under the hood". -- "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 This module should not be directly imported; it is only exposed because of the
way cabal handles ordering of chs files. way cabal handles ordering of chs files.
-} -}
module Unicorn.Internal.Hook ( module Unicorn.Internal.Hook
-- * Types ( -- * Types
Hook, Hook
HookType(..), , HookType(..)
MemoryHookType(..), , MemoryHookType(..)
MemoryEventHookType(..), , MemoryEventHookType(..)
MemoryAccess(..), , MemoryAccess(..)
-- * Hook callback bindings -- * Hook callback bindings
CodeHook, , CodeHook
InterruptHook, , InterruptHook
BlockHook, , BlockHook
InHook, , InHook
OutHook, , OutHook
SyscallHook, , SyscallHook
MemoryHook, , MemoryHook
MemoryReadHook, , MemoryReadHook
MemoryWriteHook, , MemoryWriteHook
MemoryEventHook, , MemoryEventHook
-- * Hook marshalling -- * Hook marshallin
marshalCodeHook, , marshalCodeHook
marshalInterruptHook, , marshalInterruptHook
marshalBlockHook, , marshalBlockHook
marshalInHook, , marshalInHook
marshalOutHook, , marshalOutHook
marshalSyscallHook, , marshalSyscallHook
marshalMemoryHook, , marshalMemoryHook
marshalMemoryReadHook, , marshalMemoryReadHook
marshalMemoryWriteHook, , marshalMemoryWriteHook
marshalMemoryEventHook, , marshalMemoryEventHook
-- * Hook registration and deletion bindings -- * Hook registration and deletion bindings
ucHookAdd, , ucHookAdd
ucInsnHookAdd, , ucInsnHookAdd
ucHookDel, , ucHookDel
) where ) where
import Control.Monad import Control.Monad
import Foreign import Foreign
import Unicorn.Internal.Util import Unicorn.Internal.Util
{# context lib="unicorn" #}
{# import Unicorn.Internal.Core #} {# import Unicorn.Internal.Core #}
{# import Unicorn.CPU.X86 #} {# import Unicorn.CPU.X86 #}
{# context lib = "unicorn" #}
#include <unicorn/unicorn.h> #include <unicorn/unicorn.h>
#include "unicorn_wrapper.h" #include "unicorn_wrapper.h"
@ -79,7 +79,8 @@ import Unicorn.Internal.Util
foreign import ccall "&uc_close_dummy" foreign import ccall "&uc_close_dummy"
closeDummy :: FunPtr (EnginePtr -> IO ()) closeDummy :: FunPtr (EnginePtr -> IO ())
mkEngineNC :: EnginePtr -> IO Engine mkEngineNC :: EnginePtr
-> IO Engine
mkEngineNC ptr = mkEngineNC ptr =
liftM Engine (newForeignPtr closeDummy 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 -- Note that the both valid and invalid memory access hooks are omitted from
-- this enum (and are exposed to the user). -- this enum (and are exposed to the user).
{# enum uc_hook_type as HookType {# enum uc_hook_type as HookType
{underscoreToCase} { underscoreToCase }
omit (UC_HOOK_MEM_READ_UNMAPPED, omit ( UC_HOOK_MEM_READ_UNMAPPED
UC_HOOK_MEM_WRITE_UNMAPPED, , UC_HOOK_MEM_WRITE_UNMAPPED
UC_HOOK_MEM_FETCH_UNMAPPED, , UC_HOOK_MEM_FETCH_UNMAPPED
UC_HOOK_MEM_READ_PROT, , UC_HOOK_MEM_READ_PROT
UC_HOOK_MEM_WRITE_PROT, , UC_HOOK_MEM_WRITE_PROT
UC_HOOK_MEM_FETCH_PROT, , UC_HOOK_MEM_FETCH_PROT
UC_HOOK_MEM_READ, , UC_HOOK_MEM_READ
UC_HOOK_MEM_WRITE, , UC_HOOK_MEM_WRITE
UC_HOOK_MEM_FETCH) , UC_HOOK_MEM_FETCH
with prefix="UC_" , UC_HOOK_MEM_READ_AFTER
deriving (Show, Eq, Bounded) #} )
with prefix = "UC_"
deriving (Show, Eq, Bounded)
#}
-- | Memory hook types (for valid memory accesses). -- | Memory hook types (for valid memory accesses).
{# enum uc_hook_type as MemoryHookType {# enum uc_hook_type as MemoryHookType
{underscoreToCase} { underscoreToCase }
omit (UC_HOOK_INTR, omit ( UC_HOOK_INTR
UC_HOOK_INSN, , UC_HOOK_INSN
UC_HOOK_CODE, , UC_HOOK_CODE
UC_HOOK_BLOCK, , UC_HOOK_BLOCK
UC_HOOK_MEM_READ_UNMAPPED, , UC_HOOK_MEM_READ_UNMAPPED
UC_HOOK_MEM_WRITE_UNMAPPED, , UC_HOOK_MEM_WRITE_UNMAPPED
UC_HOOK_MEM_FETCH_UNMAPPED, , UC_HOOK_MEM_FETCH_UNMAPPED
UC_HOOK_MEM_READ_PROT, , UC_HOOK_MEM_READ_PROT
UC_HOOK_MEM_WRITE_PROT, , UC_HOOK_MEM_WRITE_PROT
UC_HOOK_MEM_FETCH_PROT) , UC_HOOK_MEM_FETCH_PROT
with prefix="UC_" )
deriving (Show, Eq, Bounded) #} with prefix = "UC_"
deriving (Show, Eq, Bounded)
#}
-- | Memory event hook types (for invalid memory accesses). -- | Memory event hook types (for invalid memory accesses).
{# enum uc_hook_type as MemoryEventHookType {# enum uc_hook_type as MemoryEventHookType
{underscoreToCase} { underscoreToCase }
omit (UC_HOOK_INTR, omit ( UC_HOOK_INTR
UC_HOOK_INSN, , UC_HOOK_INSN
UC_HOOK_CODE, , UC_HOOK_CODE
UC_HOOK_BLOCK, , UC_HOOK_BLOCK
UC_HOOK_MEM_READ, , UC_HOOK_MEM_READ
UC_HOOK_MEM_WRITE, , UC_HOOK_MEM_WRITE
UC_HOOK_MEM_FETCH) , UC_HOOK_MEM_FETCH
with prefix="UC_" , UC_HOOK_MEM_READ_AFTER
deriving (Show, Eq, Bounded) #} )
with prefix = "UC_"
deriving (Show, Eq, Bounded)
#}
-- | Unify the hook types with a type class -- | Unify the hook types with a type class
class Enum a => HookTypeC a class Enum a => HookTypeC a
@ -143,9 +152,10 @@ instance HookTypeC MemoryEventHookType
-- | Memory access. -- | Memory access.
{# enum uc_mem_type as MemoryAccess {# enum uc_mem_type as MemoryAccess
{underscoreToCase} { underscoreToCase }
with prefix="UC_" with prefix = "UC_"
deriving (Show, Eq, Bounded) #} deriving (Show, Eq, Bounded)
#}
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
-- Hook callbacks -- Hook callbacks
@ -159,16 +169,18 @@ type CodeHook a = Engine -- ^ 'Unicorn' engine handle
-> a -- ^ User data passed to tracing APIs -> a -- ^ User data passed to tracing APIs
-> IO () -> IO ()
type CCodeHook = EnginePtr -> Word64 -> Word32 -> Ptr () -> IO () type CCodeHook = EnginePtr -> Word64 -> Word32 -> Ptr () -> IO ()
foreign import ccall "wrapper" foreign import ccall "wrapper"
mkCodeHook :: CCodeHook -> IO {# type uc_cb_hookcode_t #} mkCodeHook :: CCodeHook
-> IO {# type uc_cb_hookcode_t #}
marshalCodeHook :: Storable a marshalCodeHook :: Storable a
=> CodeHook a -> IO {# type uc_cb_hookcode_t #} => CodeHook a
-> IO {# type uc_cb_hookcode_t #}
marshalCodeHook codeHook = marshalCodeHook codeHook =
mkCodeHook $ \ucPtr address size userDataPtr -> do mkCodeHook $ \ucPtr address size userDataPtr -> do
uc <- mkEngineNC ucPtr uc <- mkEngineNC ucPtr
userData <- castPtrAndPeek userDataPtr userData <- castPtrAndPeek userDataPtr
let maybeSize = if size == 0 then Nothing let maybeSize = if size == 0 then Nothing
else Just $ fromIntegral size else Just $ fromIntegral size
@ -186,10 +198,11 @@ foreign import ccall "wrapper"
mkInterruptHook :: CInterruptHook -> IO {# type uc_cb_hookintr_t #} mkInterruptHook :: CInterruptHook -> IO {# type uc_cb_hookintr_t #}
marshalInterruptHook :: Storable a marshalInterruptHook :: Storable a
=> InterruptHook a -> IO {# type uc_cb_hookintr_t #} => InterruptHook a
-> IO {# type uc_cb_hookintr_t #}
marshalInterruptHook interruptHook = marshalInterruptHook interruptHook =
mkInterruptHook $ \ucPtr intNo userDataPtr -> do mkInterruptHook $ \ucPtr intNo userDataPtr -> do
uc <- mkEngineNC ucPtr uc <- mkEngineNC ucPtr
userData <- castPtrAndPeek userDataPtr userData <- castPtrAndPeek userDataPtr
interruptHook uc (fromIntegral intNo) userData interruptHook uc (fromIntegral intNo) userData
@ -197,7 +210,8 @@ marshalInterruptHook interruptHook =
type BlockHook a = CodeHook a type BlockHook a = CodeHook a
marshalBlockHook :: Storable a marshalBlockHook :: Storable a
=> BlockHook a -> IO {# type uc_cb_hookcode_t #} => BlockHook a
-> IO {# type uc_cb_hookcode_t #}
marshalBlockHook = marshalBlockHook =
marshalCodeHook marshalCodeHook
@ -214,10 +228,11 @@ foreign import ccall "wrapper"
mkInHook :: CInHook -> IO {# type uc_cb_insn_in_t #} mkInHook :: CInHook -> IO {# type uc_cb_insn_in_t #}
marshalInHook :: Storable a marshalInHook :: Storable a
=> InHook a -> IO {# type uc_cb_insn_in_t #} => InHook a
-> IO {# type uc_cb_insn_in_t #}
marshalInHook inHook = marshalInHook inHook =
mkInHook $ \ucPtr port size userDataPtr -> do mkInHook $ \ucPtr port size userDataPtr -> do
uc <- mkEngineNC ucPtr uc <- mkEngineNC ucPtr
userData <- castPtrAndPeek userDataPtr userData <- castPtrAndPeek userDataPtr
inHook uc (fromIntegral port) (fromIntegral size) userData 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 () type COutHook = EnginePtr -> Word32 -> Int32 -> Word32 -> Ptr () -> IO ()
foreign import ccall "wrapper" 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 marshalOutHook :: Storable a
=> OutHook a -> IO {# type uc_cb_insn_out_t #} => OutHook a
-> IO {# type uc_cb_insn_out_t #}
marshalOutHook outHook = marshalOutHook outHook =
mkOutHook $ \ucPtr port size value userDataPtr -> do mkOutHook $ \ucPtr port size value userDataPtr -> do
uc <- mkEngineNC ucPtr uc <- mkEngineNC ucPtr
userData <- castPtrAndPeek userDataPtr userData <- castPtrAndPeek userDataPtr
outHook uc (fromIntegral port) (fromIntegral size) (fromIntegral value) outHook uc (fromIntegral port) (fromIntegral size) (fromIntegral value)
userData userData
@ -251,13 +268,15 @@ type SyscallHook a = Engine -- ^ 'Unicorn' engine handle
type CSyscallHook = Ptr () -> Ptr () -> IO () type CSyscallHook = Ptr () -> Ptr () -> IO ()
foreign import ccall "wrapper" 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 marshalSyscallHook :: Storable a
=> SyscallHook a -> IO {# type uc_cb_insn_syscall_t #} => SyscallHook a
-> IO {# type uc_cb_insn_syscall_t #}
marshalSyscallHook syscallHook = marshalSyscallHook syscallHook =
mkSyscallHook $ \ucPtr userDataPtr -> do mkSyscallHook $ \ucPtr userDataPtr -> do
uc <- mkEngineNC $ castPtr ucPtr uc <- mkEngineNC $ castPtr ucPtr
userData <- castPtrAndPeek userDataPtr userData <- castPtrAndPeek userDataPtr
syscallHook uc userData syscallHook uc userData
@ -281,13 +300,15 @@ type CMemoryHook = EnginePtr
-> IO () -> IO ()
foreign import ccall "wrapper" foreign import ccall "wrapper"
mkMemoryHook :: CMemoryHook -> IO {# type uc_cb_hookmem_t #} mkMemoryHook :: CMemoryHook
-> IO {# type uc_cb_hookmem_t #}
marshalMemoryHook :: Storable a marshalMemoryHook :: Storable a
=> MemoryHook a -> IO {# type uc_cb_hookmem_t #} => MemoryHook a
-> IO {# type uc_cb_hookmem_t #}
marshalMemoryHook memoryHook = marshalMemoryHook memoryHook =
mkMemoryHook $ \ucPtr memAccessI address size value userDataPtr -> do mkMemoryHook $ \ucPtr memAccessI address size value userDataPtr -> do
uc <- mkEngineNC ucPtr uc <- mkEngineNC ucPtr
userData <- castPtrAndPeek userDataPtr userData <- castPtrAndPeek userDataPtr
let memAccess = toMemAccess memAccessI let memAccess = toMemAccess memAccessI
maybeValue = case memAccess of maybeValue = case memAccess of
@ -304,10 +325,11 @@ type MemoryReadHook a = Engine -- ^ 'Unicorn' engine handle
-> IO () -> IO ()
marshalMemoryReadHook :: Storable a marshalMemoryReadHook :: Storable a
=> MemoryReadHook a -> IO {# type uc_cb_hookmem_t #} => MemoryReadHook a
-> IO {# type uc_cb_hookmem_t #}
marshalMemoryReadHook memoryReadHook = marshalMemoryReadHook memoryReadHook =
mkMemoryHook $ \ucPtr _ address size _ userDataPtr -> do mkMemoryHook $ \ucPtr _ address size _ userDataPtr -> do
uc <- mkEngineNC ucPtr uc <- mkEngineNC ucPtr
userData <- castPtrAndPeek userDataPtr userData <- castPtrAndPeek userDataPtr
memoryReadHook uc address (fromIntegral size) userData memoryReadHook uc address (fromIntegral size) userData
@ -321,10 +343,11 @@ type MemoryWriteHook a = Engine -- ^ 'Unicorn' engine handle
-> IO () -> IO ()
marshalMemoryWriteHook :: Storable a marshalMemoryWriteHook :: Storable a
=> MemoryWriteHook a -> IO {# type uc_cb_hookmem_t #} => MemoryWriteHook a
-> IO {# type uc_cb_hookmem_t #}
marshalMemoryWriteHook memoryWriteHook = marshalMemoryWriteHook memoryWriteHook =
mkMemoryHook $ \ucPtr _ address size value userDataPtr -> do mkMemoryHook $ \ucPtr _ address size value userDataPtr -> do
uc <- mkEngineNC ucPtr uc <- mkEngineNC ucPtr
userData <- castPtrAndPeek userDataPtr userData <- castPtrAndPeek userDataPtr
memoryWriteHook uc address (fromIntegral size) (fromIntegral value) memoryWriteHook uc address (fromIntegral size) (fromIntegral value)
userData userData
@ -351,15 +374,17 @@ type CMemoryEventHook = EnginePtr
-> IO Int32 -> IO Int32
foreign import ccall "wrapper" foreign import ccall "wrapper"
mkMemoryEventHook :: CMemoryEventHook -> IO {# type uc_cb_eventmem_t #} mkMemoryEventHook :: CMemoryEventHook
-> IO {# type uc_cb_eventmem_t #}
marshalMemoryEventHook :: Storable a marshalMemoryEventHook :: Storable a
=> MemoryEventHook a -> IO {# type uc_cb_eventmem_t #} => MemoryEventHook a
-> IO {# type uc_cb_eventmem_t #}
marshalMemoryEventHook eventMemoryHook = marshalMemoryEventHook eventMemoryHook =
mkMemoryEventHook $ \ucPtr memAccessI address size value userDataPtr -> do mkMemoryEventHook $ \ucPtr memAccessI address size value userDataPtr -> do
uc <- mkEngineNC ucPtr uc <- mkEngineNC ucPtr
userData <- castPtrAndPeek userDataPtr userData <- castPtrAndPeek userDataPtr
let memAccess = toMemAccess memAccessI let memAccess = toMemAccess memAccessI
maybeValue = case memAccess of maybeValue = case memAccess of
MemReadUnmapped -> Nothing MemReadUnmapped -> Nothing
MemReadProt -> Nothing MemReadProt -> Nothing
@ -369,7 +394,7 @@ marshalMemoryEventHook eventMemoryHook =
res <- eventMemoryHook uc memAccess address (fromIntegral size) res <- eventMemoryHook uc memAccess address (fromIntegral size)
maybeValue userData maybeValue userData
return $ boolToInt res return $ boolToInt res
where boolToInt True = 1 where boolToInt True = 1
boolToInt False = 0 boolToInt False = 0
@ -378,38 +403,43 @@ marshalMemoryEventHook eventMemoryHook =
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
{# fun variadic uc_hook_add as ucHookAdd {# fun variadic uc_hook_add as ucHookAdd
`(Storable a, HookTypeC h)' => `HookTypeC h' =>
{`Engine', { `Engine'
alloca- `Hook' peek*, , alloca- `Hook' peek*
enumToNum `h', , enumToNum `h'
castFunPtrToPtr `FunPtr b', , castFunPtrToPtr `FunPtr b'
castPtr `Ptr a', , castPtr `Ptr a'
`Word64', , `Word64'
`Word64'} , `Word64'
-> `Error' #} } -> `Error'
#}
{# fun variadic uc_hook_add[int] as ucInsnHookAdd {# fun variadic uc_hook_add[int] as ucInsnHookAdd
`(Storable a, HookTypeC h)' => `HookTypeC h' =>
{`Engine', { `Engine'
alloca- `Hook' peek*, , alloca- `Hook' peek*
enumToNum `h', , enumToNum `h'
castFunPtrToPtr `FunPtr b', , castFunPtrToPtr `FunPtr b'
castPtr `Ptr a', , castPtr `Ptr a'
`Word64', , `Word64'
`Word64', , `Word64'
enumToNum `Instruction'} , enumToNum `Instruction'
-> `Error' #} } -> `Error'
#}
-- | Unregister (remove) a hook callback. -- | Unregister (remove) a hook callback.
{# fun uc_hook_del as ^ {# fun uc_hook_del as ^
{`Engine', { `Engine'
fromIntegral `Hook'} , fromIntegral `Hook'
-> `Error' #} } -> `Error'
#}
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
-- Helper functions -- Helper functions
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
toMemAccess :: Integral a => a -> MemoryAccess toMemAccess :: Integral a
=> a
-> MemoryAccess
toMemAccess = toMemAccess =
toEnum . fromIntegral 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 This module should not be directly imported; it is only exposed because of the
way cabal handles ordering of chs files. way cabal handles ordering of chs files.
-} -}
module Unicorn.Internal.Unicorn ( module Unicorn.Internal.Unicorn
-- * Types ( -- * Types
Architecture(..), Architecture(..)
Mode(..), , Mode(..)
MemoryPermission(..), , MemoryPermission(..)
MemoryRegion(..), , MemoryRegion(..)
QueryType(..), , QueryType(..)
, Context
-- * Function bindings -- * Function bindings
ucOpen, , ucOpen
ucQuery, , ucQuery
ucEmuStart, , ucEmuStart
ucEmuStop, , ucEmuStop
ucRegWrite, , ucRegWrite
ucRegRead, , ucRegRead
ucMemWrite, , ucMemWrite
ucMemRead, , ucMemRead
ucMemMap, , ucMemMap
ucMemUnmap, , ucMemUnmap
ucMemProtect, , ucMemProtect
ucMemRegions, , ucMemRegions
ucVersion, , mkContext
ucErrno, , ucContextAlloc
ucStrerror, , ucContextSave
) where , ucContextRestore
, ucVersion
, ucErrno
, ucStrerror
) where
import Control.Applicative import Control.Applicative
import Control.Monad
import Data.ByteString (ByteString, useAsCStringLen) import Data.ByteString (ByteString, useAsCStringLen)
import Foreign import Foreign
import Foreign.C import Foreign.C
@ -46,11 +52,12 @@ import Prelude hiding (until)
import Unicorn.Internal.Util import Unicorn.Internal.Util
{# context lib="unicorn" #}
{# import Unicorn.Internal.Core #} {# import Unicorn.Internal.Core #}
{# context lib = "unicorn" #}
#include <unicorn/unicorn.h> #include <unicorn/unicorn.h>
#include "unicorn_wrapper.h"
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
-- Types -- Types
@ -58,29 +65,33 @@ import Unicorn.Internal.Util
-- | CPU architecture. -- | CPU architecture.
{# enum uc_arch as Architecture {# enum uc_arch as Architecture
{underscoreToCase} { underscoreToCase }
with prefix="UC_" with prefix = "UC_"
deriving (Show, Eq, Bounded) #} deriving (Show, Eq, Bounded)
#}
-- | CPU hardware mode. -- | CPU hardware mode.
{# enum uc_mode as Mode {# enum uc_mode as Mode
{underscoreToCase} { underscoreToCase }
with prefix="UC_" with prefix = "UC_"
deriving (Show, Eq, Bounded) #} deriving (Show, Eq, Bounded)
#}
-- | Memory permissions. -- | Memory permissions.
{# enum uc_prot as MemoryPermission {# enum uc_prot as MemoryPermission
{underscoreToCase} { underscoreToCase }
with prefix="UC_" with prefix = "UC_"
deriving (Show, Eq, Bounded) #} deriving (Show, Eq, Bounded)
#}
-- | Memory region mapped by 'memMap'. Retrieve the list of memory regions with -- | Memory region mapped by 'memMap'. Retrieve the list of memory regions with
-- 'memRegions'. -- 'memRegions'.
data MemoryRegion = MemoryRegion { data MemoryRegion = MemoryRegion
mrBegin :: Word64, -- ^ Begin address of the region (inclusive) {
mrEnd :: Word64, -- ^ End address of the region (inclusive) mrBegin :: Word64 -- ^ Begin address of the region (inclusive)
mrPerms :: [MemoryPermission] -- ^ Memory permissions of the region , mrEnd :: Word64 -- ^ End address of the region (inclusive)
} , mrPerms :: [MemoryPermission] -- ^ Memory permissions of the region
}
instance Storable MemoryRegion where instance Storable MemoryRegion where
sizeOf _ = {# sizeof uc_mem_region #} sizeOf _ = {# sizeof uc_mem_region #}
@ -99,121 +110,174 @@ instance Storable MemoryRegion where
-- | Query types for the 'query' API. -- | Query types for the 'query' API.
{# enum uc_query_type as QueryType {# enum uc_query_type as QueryType
{underscoreToCase} { underscoreToCase }
with prefix="UC_" with prefix = "UC_"
deriving (Show, Eq, Bounded) #} 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 -- Emulator control
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
{# fun uc_open as ^ {# fun uc_open as ^
{`Architecture', { `Architecture'
combineEnums `[Mode]', , combineEnums `[Mode]'
alloca- `EnginePtr' peek*} , alloca- `EnginePtr' peek*
-> `Error' #} } -> `Error'
#}
{# fun uc_query as ^ {# fun uc_query as ^
{`Engine', { `Engine'
`QueryType', , `QueryType'
alloca- `Int' castPtrAndPeek*} , alloca- `Int' castPtrAndPeek*
-> `Error' #} } -> `Error'
#}
{# fun uc_emu_start as ^ {# fun uc_emu_start as ^
{`Engine', { `Engine'
`Word64', , `Word64'
`Word64', , `Word64'
`Int', , `Int'
`Int'} , `Int'} -> `Error'
-> `Error' #} #}
{# fun uc_emu_stop as ^ {# fun uc_emu_stop as ^
{`Engine'} { `Engine'
-> `Error' #} } -> `Error'
#}
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
-- Register operations -- Register operations
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
{# fun uc_reg_write as ^ {# fun uc_reg_write as ^
`Reg r' => `Reg r' =>
{`Engine', { `Engine'
enumToNum `r', , enumToNum `r'
castPtr `Ptr Int64'} , castPtr `Ptr Int64'
-> `Error' #} } -> `Error'
#}
{# fun uc_reg_read as ^ {# fun uc_reg_read as ^
`Reg r' => `Reg r' =>
{`Engine', { `Engine'
enumToNum `r', , enumToNum `r'
allocaInt64ToVoid- `Int64' castPtrAndPeek*} , allocaInt64ToVoid- `Int64' castPtrAndPeek*
-> `Error' #} } -> `Error'
#}
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
-- Memory operations -- Memory operations
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
{# fun uc_mem_write as ^ {# fun uc_mem_write as ^
{`Engine', { `Engine'
`Word64', , `Word64'
withByteStringLen* `ByteString'&} , withByteStringLen* `ByteString'&
-> `Error' #} } -> `Error'
#}
{# fun uc_mem_read as ^ {# fun uc_mem_read as ^
{`Engine', { `Engine'
`Word64', , `Word64'
castPtr `Ptr Word8', , castPtr `Ptr Word8'
`Int'} , `Int'} -> `Error'
-> `Error' #} #}
{# fun uc_mem_map as ^ {# fun uc_mem_map as ^
{`Engine', { `Engine'
`Word64', , `Word64'
`Int', , `Int'
combineEnums `[MemoryPermission]'} , combineEnums `[MemoryPermission]'
-> `Error' #} } -> `Error' #}
{# fun uc_mem_unmap as ^ {# fun uc_mem_unmap as ^
{`Engine', { `Engine'
`Word64', , `Word64'
`Int'} , `Int'
-> `Error' #} } -> `Error'
#}
{# fun uc_mem_protect as ^ {# fun uc_mem_protect as ^
{`Engine', { `Engine'
`Word64', , `Word64'
`Int', , `Int'
combineEnums `[MemoryPermission]'} , combineEnums `[MemoryPermission]'
-> `Error' #} } -> `Error'
#}
{# fun uc_mem_regions as ^ {# fun uc_mem_regions as ^
{`Engine', { `Engine'
alloca- `MemoryRegionPtr' peek*, , alloca- `MemoryRegionPtr' peek*
alloca- `Int' castPtrAndPeek*} , alloca- `Int' castPtrAndPeek*
-> `Error' #} } -> `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. -- Misc.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
{# fun pure unsafe uc_version as ^ {# fun pure unsafe uc_version as ^
{id `Ptr CUInt', { id `Ptr CUInt'
id `Ptr CUInt'} , id `Ptr CUInt'
-> `Int' #} } -> `Int'
#}
{# fun unsafe uc_errno as ^ {# fun unsafe uc_errno as ^
{`Engine'} { `Engine'
-> `Error' #} } -> `Error'
#}
{# fun pure unsafe uc_strerror as ^ {# fun pure unsafe uc_strerror as ^
{`Error'} { `Error'
-> `String' #} } -> `String'
#}
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
-- Helper functions -- Helper functions
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
expandMemPerms :: (Integral a, Bits a) => a -> [MemoryPermission] expandMemPerms :: (Integral a, Bits a)
=> a
-> [MemoryPermission]
expandMemPerms perms = expandMemPerms perms =
-- Only interested in the 3 least-significant bits -- Only interested in the 3 least-significant bits
let maskedPerms = fromIntegral $ perms .&. 0x7 in let maskedPerms = fromIntegral $ perms .&. 0x7 in
@ -232,10 +296,13 @@ expandMemPerms perms =
checkRWE _ [] = checkRWE _ [] =
[] []
allocaInt64ToVoid :: (Ptr () -> IO b) -> IO b allocaInt64ToVoid :: (Ptr () -> IO b)
-> IO b
allocaInt64ToVoid f = allocaInt64ToVoid f =
alloca $ \(ptr :: Ptr Int64) -> poke ptr 0 >> f (castPtr ptr) 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 = withByteStringLen bs f =
useAsCStringLen bs $ \(ptr, len) -> f (castPtr ptr, fromIntegral len) useAsCStringLen bs $ \(ptr, len) -> f (castPtr ptr, fromIntegral len)

View File

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

View File

@ -6,3 +6,7 @@ void uc_close_wrapper(uc_engine *uc) {
void uc_close_dummy(uc_engine *uc) { void uc_close_dummy(uc_engine *uc) {
} }
void uc_context_free_wrapper(uc_context *context) {
uc_context_free(context);
}

View File

@ -13,4 +13,9 @@ void uc_close_wrapper(uc_engine *uc);
*/ */
void uc_close_dummy(uc_engine *uc); void uc_close_dummy(uc_engine *uc);
/*
* Wrap Unicorn's uc_context_free function and ignore the returned error code.
*/
void uc_context_free_wrapper(uc_context *context);
#endif #endif

View File

@ -13,8 +13,9 @@ copyright: (c) 2016, Adrian Herrera
category: System category: System
build-type: Simple build-type: Simple
stability: experimental stability: experimental
cabal-version: >=1.10 cabal-version: >= 1.10
extra-source-files: cbits/, include/ extra-source-files: cbits/
, include/
library library
exposed-modules: Unicorn.Internal.Core exposed-modules: Unicorn.Internal.Core
@ -29,10 +30,10 @@ library
Unicorn.Hook Unicorn.Hook
Unicorn Unicorn
other-modules: Unicorn.Internal.Util other-modules: Unicorn.Internal.Util
build-depends: base >=4 && <5, build-depends: base >=4 && <5
bytestring >= 0.9.1, , bytestring >= 0.9.1
transformers < 0.6, , transformers < 0.6
either >= 4.4 , either >= 4.4
hs-source-dirs: src hs-source-dirs: src
c-sources: src/cbits/unicorn_wrapper.c c-sources: src/cbits/unicorn_wrapper.c
include-dirs: src/include include-dirs: src/include