{-| Module : Heystone 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 . -} module Heystone ( -- * 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.Except (runExceptT, throwE) import Data.ByteString (ByteString, packCStringLen) import Data.List (intercalate) import Foreign import Heystone.Internal.Core import Heystone.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 = runExceptT -- | 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 throwE 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 return () else throwE 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 return (bs, statCount) else do -- On failure, call errno for error code err <- errno ks throwE 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