module Hdis86.Types
(
Instruction(..)
, Prefix(..)
, Operand(..), Memory(..), Pointer(..), Immediate(..)
, Register(..), GPR(..), Half(..)
, Segment(..), ControlRegister(..), DebugRegister(..)
, MMXRegister(..), X87Register(..), XMMRegister(..)
, WordSize(..), wordSize, bitsInWord
, Metadata(..)
, Config(..)
, Vendor(..), CPUMode(..), Syntax(..)
, intel32, intel64, amd32, amd64
, Opcode(..)
) where
import Hdis86.Internal.Opcode
import Data.Typeable ( Typeable )
import Data.Data ( Data )
import Data.Word
import Data.Int
import Control.Applicative hiding ( Const )
import qualified Data.ByteString as BS
import qualified Text.Read as R
import qualified Test.QuickCheck as Q
data WordSize
= Bits0
| Bits8
| Bits16
| Bits32
| Bits48
| Bits64
| Bits80
deriving (Eq, Ord, Show, Read, Typeable, Data, Enum, Bounded)
wordSize :: Word8 -> Maybe WordSize
wordSize 0 = Just Bits0
wordSize 8 = Just Bits8
wordSize 16 = Just Bits16
wordSize 32 = Just Bits32
wordSize 48 = Just Bits48
wordSize 64 = Just Bits64
wordSize 80 = Just Bits80
wordSize _ = Nothing
bitsInWord :: WordSize -> Word8
bitsInWord Bits0 = 0
bitsInWord Bits8 = 8
bitsInWord Bits16 = 16
bitsInWord Bits32 = 32
bitsInWord Bits48 = 48
bitsInWord Bits64 = 64
bitsInWord Bits80 = 80
data Register
= RegNone
| Reg8 GPR Half
| Reg16 GPR
| Reg32 GPR
| Reg64 GPR
| RegSeg Segment
| RegCtl ControlRegister
| RegDbg DebugRegister
| RegMMX MMXRegister
| RegX87 X87Register
| RegXMM XMMRegister
| RegIP
deriving (Eq, Ord, Show, Read, Typeable, Data)
data GPR
= RAX | RCX | RDX | RBX
| RSP | RBP | RSI | RDI
| R8 | R9 | R10 | R11
| R12 | R13 | R14 | R15
deriving (Eq, Ord, Show, Read, Typeable, Data, Enum, Bounded)
data Half
= L
| H
deriving (Eq, Ord, Show, Read, Typeable, Data, Enum, Bounded)
data Segment
= ES | CS | SS | DS | FS | GS
deriving (Eq, Ord, Show, Read, Typeable, Data, Enum, Bounded)
data ControlRegister
= CR0 | CR1 | CR2 | CR3
| CR4 | CR5 | CR6 | CR7
| CR8 | CR9 | CR10 | CR11
| CR12 | CR13 | CR14 | CR15
deriving (Eq, Ord, Show, Read, Typeable, Data, Enum, Bounded)
data DebugRegister
= DR0 | DR1 | DR2 | DR3
| DR4 | DR5 | DR6 | DR7
| DR8 | DR9 | DR10 | DR11
| DR12 | DR13 | DR14 | DR15
deriving (Eq, Ord, Show, Read, Typeable, Data, Enum, Bounded)
data MMXRegister
= MM0 | MM1 | MM2 | MM3
| MM4 | MM5 | MM6 | MM7
deriving (Eq, Ord, Show, Read, Typeable, Data, Enum, Bounded)
data X87Register
= ST0 | ST1 | ST2 | ST3
| ST4 | ST5 | ST6 | ST7
deriving (Eq, Ord, Show, Read, Typeable, Data, Enum, Bounded)
data XMMRegister
= XMM0 | XMM1 | XMM2 | XMM3
| XMM4 | XMM5 | XMM6 | XMM7
| XMM8 | XMM9 | XMM10 | XMM11
| XMM12 | XMM13 | XMM14 | XMM15
deriving (Eq, Ord, Show, Read, Typeable, Data, Enum, Bounded)
data Instruction = Inst
{ inPrefixes :: [Prefix]
, inOpcode :: Opcode
, inOperands :: [Operand]
} deriving (Eq, Ord, Typeable, Data)
instance Show Instruction where
showsPrec p (Inst pfx opc opr) = showParen (p >= 11) body
where
body = foldr (.) id
[("Inst "++), showsPrec 11 pfx, (" "++),
showsPrec 11 opc, (" "++), showsPrec 11 opr]
instance Read Instruction where
readsPrec d = R.readParen (d > 10) $ \r ->
[(Inst pfx opc opr, xd)
| ("Inst", xa) <- R.lex r
, (pfx, xb) <- readsPrec 11 xa
, (opc, xc) <- readsPrec 11 xb
, (opr, xd) <- readsPrec 11 xc]
data Prefix
= Seg Segment
| Rex
| OperSize
| AddrSize
| Lock
| Rep
| RepE
| RepNE
deriving (Eq, Ord, Show, Read, Typeable, Data)
data Operand
= Mem Memory
| Reg Register
| Ptr Pointer
| Imm (Immediate Word64)
| Jump (Immediate Int64 )
| Const (Immediate Word64)
deriving (Eq, Ord, Show, Read, Typeable, Data)
data Memory = Memory
{ mSize :: WordSize
, mBase :: Register
, mIndex :: Register
, mScale :: Word8
, mOffset :: Immediate Int64
} deriving (Eq, Ord, Show, Read, Typeable, Data)
data Pointer = Pointer
{ pSegment :: Word16
, pOffset :: Immediate Word32
} deriving (Eq, Ord, Show, Read, Typeable, Data)
data Immediate t = Immediate
{ iSize :: WordSize
, iValue :: t
} deriving (Eq, Ord, Show, Read, Typeable, Data)
data Metadata = Metadata
{ mdOffset :: Word64
, mdLength :: Word
, mdHex :: String
, mdBytes :: BS.ByteString
, mdAssembly :: String
, mdInst :: Instruction
} deriving (Eq, Ord, Show, Read, Typeable, Data)
data Vendor
= Intel
| AMD
deriving (Eq, Ord, Show, Read, Enum, Bounded, Typeable, Data)
data Syntax
= SyntaxNone
| SyntaxIntel
| SyntaxATT
deriving (Eq, Ord, Show, Read, Enum, Bounded, Typeable, Data)
data Config = Config
{ cfgVendor :: Vendor
, cfgCPUMode :: CPUMode
, cfgSyntax :: Syntax
, cfgOrigin :: Word64
} deriving (Eq, Ord, Show, Read, Typeable, Data)
data CPUMode
= Mode16
| Mode32
| Mode64
deriving (Eq, Ord, Show, Read, Enum, Bounded, Typeable, Data)
intel32, intel64, amd32, amd64 :: Config
intel32 = Config Intel Mode32 SyntaxNone 0
intel64 = Config Intel Mode64 SyntaxNone 0
amd32 = Config AMD Mode32 SyntaxNone 0
amd64 = Config AMD Mode64 SyntaxNone 0
_prop_Instruction_ReadShow :: Instruction -> Bool
_prop_Instruction_ReadShow i = read (show i) == i
arbEnum :: forall a. (Enum a, Bounded a) => Q.Gen a
arbEnum = toEnum <$> Q.choose (fromEnum lb, fromEnum ub) where
lb, ub :: a
(lb, ub) = (minBound, maxBound)
instance Q.Arbitrary GPR where arbitrary = arbEnum
instance Q.Arbitrary Half where arbitrary = arbEnum
instance Q.Arbitrary Segment where arbitrary = arbEnum
instance Q.Arbitrary ControlRegister where arbitrary = arbEnum
instance Q.Arbitrary DebugRegister where arbitrary = arbEnum
instance Q.Arbitrary MMXRegister where arbitrary = arbEnum
instance Q.Arbitrary X87Register where arbitrary = arbEnum
instance Q.Arbitrary XMMRegister where arbitrary = arbEnum
instance Q.Arbitrary WordSize where arbitrary = arbEnum
instance Q.Arbitrary Vendor where arbitrary = arbEnum
instance Q.Arbitrary CPUMode where arbitrary = arbEnum
instance Q.Arbitrary Syntax where arbitrary = arbEnum
instance Q.Arbitrary Opcode where arbitrary = arbEnum
instance Q.Arbitrary Register where
arbitrary = Q.oneof [
pure RegNone
, pure RegIP
, Reg8 <$> Q.arbitrary <*> Q.arbitrary
, Reg16 <$> Q.arbitrary
, Reg32 <$> Q.arbitrary
, Reg64 <$> Q.arbitrary
, RegSeg <$> Q.arbitrary
, RegCtl <$> Q.arbitrary
, RegDbg <$> Q.arbitrary
, RegMMX <$> Q.arbitrary
, RegX87 <$> Q.arbitrary
, RegXMM <$> Q.arbitrary ]
instance (Q.Arbitrary t) => Q.Arbitrary (Immediate t) where
arbitrary = Immediate <$> Q.arbitrary <*> Q.arbitrary
instance Q.Arbitrary Pointer where
arbitrary = Pointer <$> Q.arbitrary <*> Q.arbitrary
instance Q.Arbitrary Memory where
arbitrary = Memory <$> Q.arbitrary <*> Q.arbitrary <*> Q.arbitrary
<*> Q.arbitrary <*> Q.arbitrary
instance Q.Arbitrary Operand where
arbitrary = Q.oneof [
Mem <$> Q.arbitrary
, Reg <$> Q.arbitrary
, Ptr <$> Q.arbitrary
, Imm <$> Q.arbitrary
, Jump <$> Q.arbitrary
, Const <$> Q.arbitrary ]
instance Q.Arbitrary Prefix where
arbitrary = Q.oneof (
(Seg <$> Q.arbitrary)
: map pure [Rex, OperSize, AddrSize, Lock, Rep, RepE, RepNE] )
instance Q.Arbitrary Instruction where
arbitrary = do
np <- Q.choose (0,3)
no <- Q.choose (0,3)
Inst <$> Q.vectorOf np Q.arbitrary
<*> Q.arbitrary
<*> Q.vectorOf no Q.arbitrary
instance Q.Arbitrary Config where
arbitrary = Config <$> Q.arbitrary <*> Q.arbitrary
<*> Q.arbitrary <*> Q.arbitrary