You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

129 lines
4.3 KiB

{-|
Module : Keystone
Description : The Keystone assembler engine.
Copyright : (c) Adrian Herrera, 2016
License : GPL-2
Keystone is a lightweight multi-platform, multi-architecture assembler
framework.
Further information is available at <http://www.keystone-engine.org>.
-}
module Keystone
( -- * Assembler control
Assembler
, Engine
, Architecture(..)
, Mode(..)
, OptionType(..)
, OptionValue(..)
, runAssembler
, open
, option
, assemble
-- * Error handling
, Error(..)
, errno
, strerror
-- * Misc.
, version
) where
import Control.Monad.Trans.Class (lift)
import Control.Monad.Trans.Either (left, right, runEitherT)
import Data.ByteString (ByteString, packCStringLen)
import Data.List (intercalate)
import Foreign
import Keystone.Internal.Core
import Keystone.Internal.Keystone
-------------------------------------------------------------------------------
-- Assembler control
-------------------------------------------------------------------------------
-- | Run the Keystone assembler and return a result on success, or an 'Error'
-- on failure.
runAssembler :: Assembler a -- ^ The assembler code to execute
-> IO (Either Error a) -- ^ A result on success, or an 'Error' on
-- failure
runAssembler =
runEitherT
-- | Create a new instance of the Keystone assembler.
open :: Architecture -- ^ CPU architecture
-> [Mode] -- ^ CPU hardware mode
-> Assembler Engine -- ^ A 'Keystone' engine on success, or an 'Error'
-- on failure
open arch mode = do
(err, ksPtr) <- lift $ ksOpen arch mode
if err == ErrOk then
-- Return a pointer to the Keystone engine if ksOpen completed
-- successfully
lift $ mkEngine ksPtr
else
-- Otherwise return an error
left err
option :: Engine -- ^ 'Keystone' engine handle
-> OptionType -- ^ Type of option to set
-> OptionValue -- ^ Option value corresponding with the type
-> Assembler () -- ^ An 'Error' on failure
option ks optType optValue = do
err <- lift $ ksOption ks optType optValue
if err == ErrOk then
right ()
else
left err
-- | Assemble a list of statements.
assemble :: Engine -- ^ 'Keystone' engine handle
-> [String] -- ^ List of statements to assemble.
-> Maybe Word64 -- ^ Optional address of the first
-- assembly instruction
-> Assembler (ByteString, Int) -- ^ Returns the encoded input assembly
-- string and the number of statements
-- successfully processed. Returns an
-- 'Error' on failure
assemble ks stmts addr = do
let string = intercalate ";" stmts
(res, encPtr, encSize, statCount) <- lift $ ksAsm ks string (maybeZ addr)
if res == 0 then do
-- If ksAsm completed successfully, pack the encoded bytes into a
-- ByteString. Once the encoded bytes have been packed the original
-- encoded bytes can be freed. The ByteString is returned with the
-- statement count
bs <- lift $ packCStringLen (castPtr encPtr, encSize)
lift $ ksFree encPtr
right (bs, statCount)
else do
-- On failure, call errno for error code
err <- errno ks
left err
where maybeZ = maybe 0 id
-------------------------------------------------------------------------------
-- Misc.
-------------------------------------------------------------------------------
-- | Combined API version & major and minor version numbers. Returns a
-- hexadecimal number as (major << 8 | minor), which encodes both major and
-- minor versions.
version :: Int
version =
ksVersion nullPtr nullPtr
-- | Report the 'Error' number when some API function failed.
errno :: Engine -- ^ 'Keystone' engine handle
-> Assembler Error -- ^ The last 'Error' code
errno =
lift . ksErrno
-- | Return a string describing the given 'Error'.
strerror :: Error -- ^ The 'Error' code
-> String -- ^ Description of the error code
strerror =
ksStrerror