Add blockAddr/symbolic updates.

This commit is contained in:
Joe Hendrix 2017-08-03 11:48:47 -07:00
parent e71eff0a88
commit b452cf51da
No known key found for this signature in database
GPG Key ID: 8DFA5FF784098C4F
7 changed files with 340 additions and 145 deletions

View File

@ -1,5 +1,7 @@
{-# LANGUAGE DataKinds #-} {-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE KindSignatures #-} {-# LANGUAGE KindSignatures #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-} {-# LANGUAGE TypeOperators #-}
@ -8,11 +10,12 @@ module Data.Macaw.Symbolic
) where ) where
import Control.Monad.ST import Control.Monad.ST
import Control.Monad.State.Strict
import Data.Map.Strict (Map) import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map import qualified Data.Map.Strict as Map
import qualified Data.Parameterized.Context as Ctx import qualified Data.Parameterized.Context as Ctx
import qualified Data.Parameterized.Map as MapF import qualified Data.Parameterized.Map as MapF
import qualified Data.Set as Set import Data.Parameterized.TraversableFC
import Data.String import Data.String
import Data.Word import Data.Word
import qualified Lang.Crucible.CFG.Core as C import qualified Lang.Crucible.CFG.Core as C
@ -29,48 +32,103 @@ import Numeric (showHex)
import System.IO (stdout) import System.IO (stdout)
import qualified Data.Macaw.CFG.Block as M import qualified Data.Macaw.CFG.Block as M
import qualified Data.Macaw.CFG.Core as M
import qualified Data.Macaw.Types as M
import Data.Macaw.Symbolic.App import Data.Macaw.Symbolic.App
data ReoptSimulatorState sym = ReoptSimulatorState data ReoptSimulatorState sym = ReoptSimulatorState
translateBlock :: Map Word64 (CR.Label s)
-- ^ Map from block indices to the associated label.
-- Return the types associated with a register assignment.
regTypes :: Ctx.Assignment M.TypeRepr ctx
-> Ctx.Assignment C.TypeRepr (CtxToCrucibleType ctx)
regTypes a =
case Ctx.view a of
Ctx.AssignEmpty -> Ctx.empty
Ctx.AssignExtend b tp -> regTypes b Ctx.%> typeToCrucible tp
-- | Create the variables from a collection of registers.
regVars :: (IsSymInterface sym, M.HasRepr reg M.TypeRepr)
=> sym
-> (forall tp . reg tp -> SolverSymbol)
-> Ctx.Assignment reg ctx
-> IO (Ctx.Assignment (C.RegValue' sym) (CtxToCrucibleType ctx))
regVars sym nameFn a =
case Ctx.view a of
Ctx.AssignEmpty -> pure Ctx.empty
Ctx.AssignExtend b reg -> do
varAssign <- regVars sym nameFn b
c <- freshConstant sym (nameFn reg) (typeToCrucibleBase (M.typeRepr reg))
pure (varAssign Ctx.%> C.RV c)
translateBlock :: CrucGenContext arch ids s
-> M.Block arch ids -> M.Block arch ids
-> Either String (CR.Block s (MacawFunctionResult arch)) -> StateT (CrucPersistentState arch ids s) (ST s) ()
translateBlock idMap b = do translateBlock = undefined
let idx = M.blockLabel b {-
lbl <- translateBlock ctx blockMap idx ip = do
case Map.lookup idx idMap of s <- get
Just lbl -> Right (CR.LabelID lbl) mr <- lift $ runExceptT (mkCrucibleBlock ctx undefined s b)
Nothing -> Left $ "Internal: Could not find block with index " ++ show idx case mr of
let stmts = undefined Left err ->
term = undefined fail err
pure $ CR.mkBlock lbl Set.empty stmts term Right r -> do
undefined r
-}
translateBlocks :: CrucGenContext arch ids s
-> Map Word64 (M.Block arch ids)
-> ST s (CrucGenHandles arch, [CR.Block s (MacawFunctionResult arch)])
translateBlocks genCtx l = do
let ps0 = CrucPersistentState
{ handleMap = undefined
, valueCount = 0
, assignValueMap = MapF.empty
, seenBlockMap = Map.empty
}
ps <- execStateT (mapM_ (translateBlock genCtx) (Map.elems l)) ps0
pure (handleMap ps, Map.elems (seenBlockMap ps))
createHandleMap :: CrucGenHandles arch -> C.FunctionBindings ReoptSimulatorState sym
createHandleMap = undefined
stepBlocks :: forall sym arch ids stepBlocks :: forall sym arch ids
. IsSymInterface sym . (IsSymInterface sym, M.ArchConstraints arch)
=> sym => sym
-> Ctx.Assignment C.TypeRepr (ArchRegContext arch) -> (forall tp . M.ArchReg arch tp -> SolverSymbol)
-> Ctx.Assignment (M.ArchReg arch) (ArchRegContext arch)
-> Word64 -> Word64
-- ^ Starting IP for block
-> Map Word64 (M.Block arch ids) -> Map Word64 (M.Block arch ids)
-- ^ Map from block indices to block -- ^ Map from block indices to block
-> IO (C.ExecResult -> IO (C.ExecResult
ReoptSimulatorState ReoptSimulatorState
sym sym
(C.RegEntry sym (C.StructType (ArchRegContext arch)))) (C.RegEntry sym (C.StructType (CtxToCrucibleType (ArchRegContext arch)))))
stepBlocks sym regTypes addr macawBlockMap = do stepBlocks sym nameFn regAssign addr macawBlockMap = do
let macawStructRepr = C.StructRepr regTypes let macawStructRepr = C.StructRepr (regTypes (fmapFC M.typeRepr regAssign))
halloc <- C.newHandleAllocator halloc <- C.newHandleAllocator
let argTypes = Ctx.empty Ctx.%> macawStructRepr let argTypes = Ctx.empty Ctx.%> macawStructRepr
let nm = fromString $ "macaw_0x" ++ showHex addr "" let nm = fromString $ "macaw_0x" ++ showHex addr ""
h <- stToIO $ C.mkHandle' halloc nm argTypes macawStructRepr h <- stToIO $ C.mkHandle' halloc nm argTypes macawStructRepr
-- Map block map to Crucible CFG -- Map block map to Crucible CFG
let blockLabelMap :: Map Word64 (CR.Label ()) let blockLabelMap :: Map Word64 (CR.Label RealWorld)
blockLabelMap = Map.fromList [ (w, CR.Label (fromIntegral w)) | w <- Map.keys macawBlockMap ] blockLabelMap = Map.fromList [ (w, CR.Label (fromIntegral w)) | w <- Map.keys macawBlockMap ]
let Right blks = traverse (translateBlock blockLabelMap) $ Map.elems macawBlockMap let genCtx = CrucGenContext { archConstraints = \x -> x
, translateArchFn = undefined
, translateArchStmt = undefined
, handleAlloc = halloc
, binaryPath = undefined
, macawIndexToLabelMap = blockLabelMap
, memSegmentMap = undefined
, regValueMap = undefined
, syscallHandle = undefined
}
(hndls, blks) <- stToIO $ translateBlocks genCtx macawBlockMap
-- Create control flow graph -- Create control flow graph
let rg :: CR.CFG () (MacawFunctionArgs arch) (MacawFunctionResult arch) let rg :: CR.CFG RealWorld (MacawFunctionArgs arch) (MacawFunctionResult arch)
rg = CR.CFG { CR.cfgHandle = h rg = CR.CFG { CR.cfgHandle = h
, CR.cfgBlocks = blks , CR.cfgBlocks = blks
} }
@ -82,15 +140,16 @@ stepBlocks sym regTypes addr macawBlockMap = do
, C.simConfig = cfg , C.simConfig = cfg
, C.simHandleAllocator = halloc , C.simHandleAllocator = halloc
, C.printHandle = stdout , C.printHandle = stdout
, C._functionBindings = C.emptyHandleMap , C._functionBindings = createHandleMap hndls
, C._cruciblePersonality = ReoptSimulatorState , C._cruciblePersonality = ReoptSimulatorState
} }
-- Create the symbolic simulator state -- Create the symbolic simulator state
let s = C.initSimState ctx C.emptyGlobals C.defaultErrorHandler let s = C.initSimState ctx C.emptyGlobals C.defaultErrorHandler
-- Define the arguments to call the Reopt CFG with. -- Define the arguments to call the Reopt CFG with.
-- This should be a symbolic variable for each register in the architecture. -- This should be a symbolic variable for each register in the architecture.
regStruct <- regVars sym nameFn regAssign
let args :: C.RegMap sym (MacawFunctionArgs arch) let args :: C.RegMap sym (MacawFunctionArgs arch)
args = undefined args = C.RegMap (Ctx.singleton (C.RegEntry macawStructRepr regStruct))
-- Run the symbolic simulator. -- Run the symbolic simulator.
case C.toSSA rg of case C.toSSA rg of
C.SomeCFG g -> C.SomeCFG g ->

View File

@ -6,15 +6,31 @@
{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-} {-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-} {-# LANGUAGE TypeOperators #-}
{-# OPTIONS_GHC -Wwarn #-} {-# OPTIONS_GHC -Wwarn #-}
module Data.Macaw.Symbolic.App where module Data.Macaw.Symbolic.App
( CrucGenHandles(..)
, emptyCrucGenHandles
, CrucGenContext(..)
, CrucPersistentState(..)
, CrucSeenBlockMap
, CtxToCrucibleType
, ArchRegContext
, MacawFunctionArgs
, MacawFunctionResult
, typeToCrucible
, typeToCrucibleBase
, addMacawBlock
) where
import Control.Lens import Control.Lens
import Control.Monad.Except
import Control.Monad.ST import Control.Monad.ST
import Control.Monad.State.Strict import Control.Monad.State.Strict
import qualified Data.Macaw.CFG as M import qualified Data.Macaw.CFG as M
import qualified Data.Macaw.CFG.Block as M
import qualified Data.Macaw.Memory as M import qualified Data.Macaw.Memory as M
import qualified Data.Macaw.Types as M import qualified Data.Macaw.Types as M
import Data.Map.Strict (Map) import Data.Map.Strict (Map)
@ -37,22 +53,33 @@ import qualified Lang.Crucible.FunctionHandle as C
import Lang.Crucible.ProgramLoc as C import Lang.Crucible.ProgramLoc as C
import qualified Lang.Crucible.Types as C import qualified Lang.Crucible.Types as C
type family ArchRegContext (arch :: *) :: Ctx C.CrucibleType type family ToCrucibleBaseType (mtp :: M.Type) :: C.BaseType where
ToCrucibleBaseType (M.BVType w) = C.BaseBVType w
ToCrucibleBaseType M.BoolType = C.BaseBoolType
type ArchRegStruct (arch :: *) = C.StructType (ArchRegContext arch)
type ToCrucibleType tp = C.BaseToType (ToCrucibleBaseType tp)
type family CtxToCrucibleType (mtp :: Ctx M.Type) :: Ctx C.CrucibleType where
CtxToCrucibleType EmptyCtx = EmptyCtx
CtxToCrucibleType (c ::> tp) = CtxToCrucibleType c ::> ToCrucibleType tp
-- | Type family for arm registe
type family ArchRegContext (arch :: *) :: Ctx M.Type
type ArchRegStruct (arch :: *) = C.StructType (CtxToCrucibleType (ArchRegContext arch))
type MacawFunctionArgs arch = EmptyCtx ::> ArchRegStruct arch type MacawFunctionArgs arch = EmptyCtx ::> ArchRegStruct arch
type MacawFunctionResult arch = ArchRegStruct arch type MacawFunctionResult arch = ArchRegStruct arch
type family ToCrucibleType (mtp :: M.Type) :: C.CrucibleType where typeToCrucibleBase :: M.TypeRepr tp -> C.BaseTypeRepr (ToCrucibleBaseType tp)
ToCrucibleType (M.BVType w) = C.BVType w typeToCrucibleBase tp =
ToCrucibleType M.BoolType = C.BoolType case tp of
M.BoolTypeRepr -> C.BaseBoolRepr
M.BVTypeRepr w -> C.BaseBVRepr w
typeToCrucible :: M.TypeRepr tp -> C.TypeRepr (ToCrucibleType tp) typeToCrucible :: M.TypeRepr tp -> C.TypeRepr (ToCrucibleType tp)
typeToCrucible tp = typeToCrucible = C.baseToType . typeToCrucibleBase
case tp of
M.BoolTypeRepr -> C.BoolRepr
M.BVTypeRepr w -> C.BVRepr w
memReprToCrucible :: M.MemRepr tp -> C.TypeRepr (ToCrucibleType tp) memReprToCrucible :: M.MemRepr tp -> C.TypeRepr (ToCrucibleType tp)
memReprToCrucible = typeToCrucible . M.typeRepr memReprToCrucible = typeToCrucible . M.typeRepr
@ -69,7 +96,7 @@ newtype SymbolicHandle f tp = SymbolicHandle (f (ToCrucibleType tp))
type ArchAddrCrucibleType arch = C.BVType (M.ArchAddrWidth arch) type ArchAddrCrucibleType arch = C.BVType (M.ArchAddrWidth arch)
-- | Type -- | Type of a function that reads memory
type ReadMemHandle arch = C.FnHandle (EmptyCtx ::> ArchAddrCrucibleType arch) type ReadMemHandle arch = C.FnHandle (EmptyCtx ::> ArchAddrCrucibleType arch)
type WriteMemHandle arch tp type WriteMemHandle arch tp
@ -82,7 +109,7 @@ type FreshSymHandleMap = MapF M.TypeRepr (SymbolicHandle (C.FnHandle EmptyCtx))
type ReadMemHandleMap arch = MapF M.MemRepr (SymbolicHandle (ReadMemHandle arch)) type ReadMemHandleMap arch = MapF M.MemRepr (SymbolicHandle (ReadMemHandle arch))
type WriteMemHandleMap arch = MapF M.MemRepr (WriteMemWrapper arch) type WriteMemHandleMap arch = MapF M.MemRepr (WriteMemWrapper arch)
-- | Structure for getitng information about what handles are used -- | Structure for getting information about what handles are used
data CrucGenHandles arch data CrucGenHandles arch
= CrucGenHandles = CrucGenHandles
{ freshSymHandleMap :: !FreshSymHandleMap { freshSymHandleMap :: !FreshSymHandleMap
@ -102,55 +129,83 @@ readMemHandleMapLens = lens readMemHandleMap (\s v -> s { readMemHandleMap = v})
writeMemHandleMapLens :: Simple Lens (CrucGenHandles arch) (WriteMemHandleMap arch) writeMemHandleMapLens :: Simple Lens (CrucGenHandles arch) (WriteMemHandleMap arch)
writeMemHandleMapLens = lens writeMemHandleMap (\s v -> s { writeMemHandleMap = v}) writeMemHandleMapLens = lens writeMemHandleMap (\s v -> s { writeMemHandleMap = v})
-- | State used for generating blocks emptyCrucGenHandles :: CrucGenHandles arch
data CrucGenState arch ids s emptyCrucGenHandles =
= CrucGenState CrucGenHandles { freshSymHandleMap = MapF.empty
, readMemHandleMap = MapF.empty
, writeMemHandleMap = MapF.empty
}
data CrucGenContext arch ids s
= CrucGenContext
{ archConstraints :: !(forall a . (ArchConstraints arch => a) -> a) { archConstraints :: !(forall a . (ArchConstraints arch => a) -> a)
-- ^ Typeclass constraints for architecture -- ^ Typeclass constraints for architecture
, archWidthRepr :: !(NatRepr (M.ArchAddrWidth arch))
-- ^ Width of the architecture
, handleAlloc :: !(C.HandleAllocator s)
-- ^ Handle allocator
, binaryPath :: !Text
-- ^ Name of binary these blocks come from.
, codeAddr :: !Word64
-- ^ Address of this code
, translateArchFn :: !(forall tp , translateArchFn :: !(forall tp
. M.ArchFn arch ids tp . M.ArchFn arch ids tp
-> CrucGen arch ids s (C.Atom s (ToCrucibleType tp))) -> CrucGen arch ids s (C.Atom s (ToCrucibleType tp)))
-- ^ Function for translating an architecture specific function -- ^ Function for translating an architecture specific function
, translateArchStmt :: !(M.ArchStmt arch ids -> CrucGen arch ids s ()) , translateArchStmt :: !(M.ArchStmt arch ids -> CrucGen arch ids s ())
-- ^ Function for translating an architecture specific statement. -- ^ Function for translating an architecture specific statement.
, blockLabel :: (C.Label s) , handleAlloc :: !(C.HandleAllocator s)
-- ^ Label for this block we are tranlating -- ^ Handle allocator
, handleMap :: !(CrucGenHandles arch) , binaryPath :: !Text
-- ^ Handles found so far -- ^ Name of binary these blocks come from.
, prevStmts :: ![C.Posd (C.Stmt s)] , macawIndexToLabelMap :: !(Map Word64 (C.Label s))
-- ^ List of states in reverse order -- ^ Map from block indices to the associated label.
, valueCount :: !Int
-- ^ Counter used to get fresh indices for Crucible atoms.
, memSegmentMap :: !(Map M.SegmentIndex (C.Atom s (C.BVType (M.ArchAddrWidth arch)))) , memSegmentMap :: !(Map M.SegmentIndex (C.Atom s (C.BVType (M.ArchAddrWidth arch))))
-- ^ Map from segment indices to the Crucible value denoting the base. -- ^ Map from segment indices to the Crucible value denoting the base.
, regValueMap :: !(MapF (M.ArchReg arch) (WrappedAtom s)) , regValueMap :: !(MapF (M.ArchReg arch) (WrappedAtom s))
-- ^ Maps Macaw register initial values in block to associated Crucible value. -- ^ Maps Macaw register initial values in block to associated Crucible value.
, syscallHandle :: C.FnHandle (EmptyCtx ::> ArchRegStruct arch) (ArchRegStruct arch)
-- ^ Function to call for system call
}
type CrucSeenBlockMap s arch = Map Word64 (C.Block s (MacawFunctionResult arch))
-- | State that needs to be persisted across block translations
data CrucPersistentState arch ids s
= CrucPersistentState
{ handleMap :: !(CrucGenHandles arch)
-- ^ Handles found so far
, valueCount :: !Int
-- ^ Counter used to get fresh indices for Crucible atoms.
, assignValueMap :: !(MapF (M.AssignId ids) (WrappedAtom s)) , assignValueMap :: !(MapF (M.AssignId ids) (WrappedAtom s))
-- ^ Map Macaw assign id to associated Crucible value. -- ^ Map Macaw assign id to associated Crucible value.
, seenBlockMap :: !(CrucSeenBlockMap s arch)
-- ^ Map Macaw block indices to the associated crucible block
} }
handleMapLens :: Simple Lens (CrucGenState arch ids s) (CrucGenHandles arch) handleMapLens :: Simple Lens (CrucPersistentState arch ids s) (CrucGenHandles arch)
handleMapLens = lens handleMap (\s v -> s { handleMap = v }) handleMapLens = lens handleMap (\s v -> s { handleMap = v })
data CrucGenResult arch ids s seenBlockMapLens :: Simple Lens (CrucPersistentState arch ids s) (CrucSeenBlockMap s arch)
= CrucGenResult seenBlockMapLens = lens seenBlockMap (\s v -> s { seenBlockMap = v })
{ resHandleMap :: !(CrucGenHandles arch)
, resBlock :: !(C.Block s (MacawFunctionResult arch)) -- | State used for generating blocks
data CrucGenState arch ids s
= CrucGenState
{ crucCtx :: !(CrucGenContext arch ids s)
, crucPState :: !(CrucPersistentState arch ids s)
, blockLabel :: (C.Label s)
-- ^ Label for this block we are translating
, macawBlockIndex :: !Word64
, codeAddr :: !Word64
-- ^ Address of this code
, prevStmts :: ![C.Posd (C.Stmt s)]
-- ^ List of states in reverse order
} }
crucPStateLens :: Simple Lens (CrucGenState arch ids s) (CrucPersistentState arch ids s)
crucPStateLens = lens crucPState (\s v -> s { crucPState = v })
assignValueMapLens :: Simple Lens (CrucGenState arch ids s) (MapF (M.AssignId ids) (WrappedAtom s))
assignValueMapLens = crucPStateLens . lens assignValueMap (\s v -> s { assignValueMap = v })
newtype CrucGen arch ids s r newtype CrucGen arch ids s r
= CrucGen { unContGen = CrucGen { unContGen
:: CrucGenState arch ids s :: CrucGenState arch ids s
-> (CrucGenState arch ids s -> r -> ST s (CrucGenResult arch ids s)) -> (CrucGenState arch ids s -> r -> ST s (CrucPersistentState arch ids s))
-> ST s (CrucGenResult arch ids s) -> ST s (CrucPersistentState arch ids s)
} }
instance Functor (CrucGen arch ids s) where instance Functor (CrucGen arch ids s) where
@ -169,11 +224,14 @@ instance MonadState (CrucGenState arch ids s) (CrucGen arch ids s) where
get = CrucGen $ \s cont -> cont s s get = CrucGen $ \s cont -> cont s s
put s = CrucGen $ \_ cont -> cont s () put s = CrucGen $ \_ cont -> cont s ()
getCtx :: CrucGen arch ids s (CrucGenContext arch ids s)
getCtx = gets crucCtx
liftST :: ST s r -> CrucGen arch ids s r liftST :: ST s r -> CrucGen arch ids s r
liftST m = CrucGen $ \s cont -> m >>= cont s liftST m = CrucGen $ \s cont -> m >>= cont s
getPos :: CrucGen arch ids s C.Position getPos :: CrucGen arch ids s C.Position
getPos = C.BinaryPos <$> gets binaryPath <*> gets codeAddr getPos = C.BinaryPos <$> (binaryPath <$> getCtx) <*> gets codeAddr
addStmt :: C.Stmt s -> CrucGen arch ids s () addStmt :: C.Stmt s -> CrucGen arch ids s ()
addStmt stmt = seq stmt $ do addStmt stmt = seq stmt $ do
@ -192,23 +250,20 @@ addTermStmt tstmt = do
let stmts = Seq.fromList (reverse (prevStmts s)) let stmts = Seq.fromList (reverse (prevStmts s))
let term = C.Posd termPos tstmt let term = C.Posd termPos tstmt
let blk = C.mkBlock lbl Set.empty stmts term let blk = C.mkBlock lbl Set.empty stmts term
let res = CrucGenResult pure $! crucPState s & seenBlockMapLens %~ Map.insert (macawBlockIndex s) blk
{ resHandleMap = handleMap s
, resBlock = blk
}
pure $! res
freshValueIndex :: CrucGen arch ids s Int freshValueIndex :: CrucGen arch ids s Int
freshValueIndex = do freshValueIndex = do
s <- get s <- get
let cnt = valueCount s let ps = crucPState s
put $! s { valueCount = cnt + 1 } let cnt = valueCount ps
put $! s { crucPState = ps { valueCount = cnt + 1 } }
pure $! cnt pure $! cnt
-- | Evaluate the crucible app and return a reference to the result. -- | Evaluate the crucible app and return a reference to the result.
evalAtom :: C.AtomValue s ctp -> CrucGen arch ids s (C.Atom s ctp) evalAtom :: C.AtomValue s ctp -> CrucGen arch ids s (C.Atom s ctp)
evalAtom av = do evalAtom av = do
fname <- gets binaryPath fname <- binaryPath <$> getCtx
addr <- gets codeAddr addr <- gets codeAddr
let p = C.BinaryPos fname addr let p = C.BinaryPos fname addr
i <- freshValueIndex i <- freshValueIndex
@ -240,7 +295,7 @@ appToCrucible app =
valueToCrucible :: M.Value arch ids tp valueToCrucible :: M.Value arch ids tp
-> CrucGen arch ids s (C.Atom s (ToCrucibleType tp)) -> CrucGen arch ids s (C.Atom s (ToCrucibleType tp))
valueToCrucible v = do valueToCrucible v = do
cns <- gets archConstraints cns <- archConstraints <$> getCtx
cns $ do cns $ do
case v of case v of
M.BVValue w c -> do M.BVValue w c -> do
@ -253,20 +308,20 @@ valueToCrucible v = do
crucibleValue (C.BVLit w (toInteger base)) crucibleValue (C.BVLit w (toInteger base))
Right (seg,off) -> do Right (seg,off) -> do
let idx = M.segmentIndex seg let idx = M.segmentIndex seg
segMap <- gets memSegmentMap segMap <- memSegmentMap <$> getCtx
case Map.lookup idx segMap of case Map.lookup idx segMap of
Just a -> do Just a -> do
offset <- crucibleValue (C.BVLit w (toInteger off)) offset <- crucibleValue (C.BVLit w (toInteger off))
crucibleValue (C.BVAdd w a offset) crucibleValue (C.BVAdd w a offset)
Nothing -> fail $ "internal: No Crucible address associated with segment." Nothing -> fail $ "internal: No Crucible address associated with segment."
M.Initial r -> do M.Initial r -> do
regmap <- gets regValueMap regmap <- regValueMap <$> getCtx
case MapF.lookup r regmap of case MapF.lookup r regmap of
Just (WrappedAtom a) -> pure a Just (WrappedAtom a) -> pure a
Nothing -> fail $ "internal: Register is not bound." Nothing -> fail $ "internal: Register is not bound."
M.AssignedValue asgn -> do M.AssignedValue asgn -> do
let idx = M.assignId asgn let idx = M.assignId asgn
amap <- gets assignValueMap amap <- use assignValueMapLens
case MapF.lookup idx amap of case MapF.lookup idx amap of
Just (WrappedAtom r) -> pure r Just (WrappedAtom r) -> pure r
Nothing -> fail "internal: Assignment id is not bound." Nothing -> fail "internal: Assignment id is not bound."
@ -274,75 +329,84 @@ valueToCrucible v = do
freshSymbolicHandle :: M.TypeRepr tp freshSymbolicHandle :: M.TypeRepr tp
-> CrucGen arch ids s (C.FnHandle EmptyCtx (ToCrucibleType tp)) -> CrucGen arch ids s (C.FnHandle EmptyCtx (ToCrucibleType tp))
freshSymbolicHandle repr = do freshSymbolicHandle repr = do
hmap <- use $ handleMapLens . freshSymHandleMapLens hmap <- use $ crucPStateLens . handleMapLens . freshSymHandleMapLens
case MapF.lookup repr hmap of case MapF.lookup repr hmap of
Just (SymbolicHandle h) -> pure h Just (SymbolicHandle h) -> pure h
Nothing -> do Nothing -> do
let fnm = case repr of let fnm = case repr of
M.BoolTypeRepr -> "symbolicBool" M.BoolTypeRepr -> "symbolicBool"
M.BVTypeRepr w -> fromString $ "symbolicBV" ++ show w M.BVTypeRepr w -> fromString $ "symbolicBV" ++ show w
halloc <- gets handleAlloc halloc <- handleAlloc <$> getCtx
hndl <- liftST $ C.mkHandle' halloc fnm Ctx.empty (typeToCrucible repr) hndl <- liftST $ C.mkHandle' halloc fnm Ctx.empty (typeToCrucible repr)
handleMapLens . freshSymHandleMapLens %= MapF.insert repr (SymbolicHandle hndl) crucPStateLens . handleMapLens . freshSymHandleMapLens %= MapF.insert repr (SymbolicHandle hndl)
pure $! hndl pure $! hndl
archWidthRepr :: forall arch ids s . CrucGenContext arch ids s -> NatRepr (M.ArchAddrWidth arch)
archWidthRepr ctx = archConstraints ctx $
let arepr :: M.AddrWidthRepr (M.ArchAddrWidth arch)
arepr = M.addrWidthRepr arepr
in M.addrWidthNatRepr arepr
readMemHandle :: M.MemRepr tp readMemHandle :: M.MemRepr tp
-> CrucGen arch ids s (ReadMemHandle arch (ToCrucibleType tp)) -> CrucGen arch ids s (ReadMemHandle arch (ToCrucibleType tp))
readMemHandle repr = do readMemHandle repr = do
hmap <- use $ handleMapLens . readMemHandleMapLens hmap <- use $ crucPStateLens . handleMapLens . readMemHandleMapLens
case MapF.lookup repr hmap of case MapF.lookup repr hmap of
Just (SymbolicHandle r) -> pure r Just (SymbolicHandle r) -> pure r
Nothing -> do Nothing -> do
cns <- gets archConstraints cns <- archConstraints <$> getCtx
cns $ do cns $ do
halloc <- gets handleAlloc halloc <- handleAlloc <$> getCtx
let fnm = case repr of let fnm = case repr of
M.BVMemRepr w _ -> fromString $ "readWord" ++ show (8 * natValue w) M.BVMemRepr w _ -> fromString $ "readWord" ++ show (8 * natValue w)
wrepr <- gets archWidthRepr wrepr <- archWidthRepr <$> getCtx
let argTypes = Ctx.empty Ctx.%> C.BVRepr wrepr let argTypes = Ctx.empty Ctx.%> C.BVRepr wrepr
hndl <- liftST $ C.mkHandle' halloc fnm argTypes (memReprToCrucible repr) hndl <- liftST $ C.mkHandle' halloc fnm argTypes (memReprToCrucible repr)
handleMapLens . readMemHandleMapLens %= MapF.insert repr (SymbolicHandle hndl) crucPStateLens . handleMapLens . readMemHandleMapLens %= MapF.insert repr (SymbolicHandle hndl)
pure hndl pure hndl
writeMemHandle :: M.MemRepr tp writeMemHandle :: M.MemRepr tp
-> CrucGen arch ids s (WriteMemHandle arch (ToCrucibleType tp)) -> CrucGen arch ids s (WriteMemHandle arch (ToCrucibleType tp))
writeMemHandle repr = do writeMemHandle repr = do
hmap <- use $ handleMapLens . writeMemHandleMapLens hmap <- use $ crucPStateLens . handleMapLens . writeMemHandleMapLens
case MapF.lookup repr hmap of case MapF.lookup repr hmap of
Just (WriteMemWrapper r) -> pure r Just (WriteMemWrapper r) -> pure r
Nothing -> do Nothing -> do
cns <- gets archConstraints cns <- archConstraints <$> getCtx
cns $ do cns $ do
halloc <- gets handleAlloc halloc <- handleAlloc <$> getCtx
let fnm = case repr of let fnm = case repr of
M.BVMemRepr w _ -> fromString $ "readWord" ++ show (8 * natValue w) M.BVMemRepr w _ -> fromString $ "readWord" ++ show (8 * natValue w)
wrepr <- gets archWidthRepr wrepr <- archWidthRepr <$> getCtx
let argTypes = Ctx.empty Ctx.%> C.BVRepr wrepr Ctx.%> memReprToCrucible repr let argTypes = Ctx.empty Ctx.%> C.BVRepr wrepr Ctx.%> memReprToCrucible repr
hndl <- liftST $ C.mkHandle' halloc fnm argTypes C.UnitRepr hndl <- liftST $ C.mkHandle' halloc fnm argTypes C.UnitRepr
handleMapLens . writeMemHandleMapLens %= MapF.insert repr (WriteMemWrapper hndl) crucPStateLens . handleMapLens . writeMemHandleMapLens %= MapF.insert repr (WriteMemWrapper hndl)
pure hndl pure hndl
runCall :: C.FnHandle args ret -- | Call a function handle
callFnHandle :: C.FnHandle args ret
-- ^ Handle to call
-> Ctx.Assignment (C.Atom s) args -> Ctx.Assignment (C.Atom s) args
-> C.TypeRepr ret -- ^ Arguments to function
-> CrucGen arch ids s (C.Atom s ret) -> CrucGen arch ids s (C.Atom s ret)
runCall hndl args ret = do callFnHandle hndl args = do
hatom <- crucibleValue (C.HandleLit hndl) hatom <- crucibleValue (C.HandleLit hndl)
evalAtom $ C.Call hatom args ret evalAtom $ C.Call hatom args (C.handleReturnType hndl)
-- | Create a fresh symbolic value of the given type.
freshSymbolic :: M.TypeRepr tp -> CrucGen arch ids s (C.Atom s (ToCrucibleType tp)) freshSymbolic :: M.TypeRepr tp -> CrucGen arch ids s (C.Atom s (ToCrucibleType tp))
freshSymbolic repr = do freshSymbolic repr = do
hndl <- freshSymbolicHandle repr hndl <- freshSymbolicHandle repr
runCall hndl Ctx.empty (typeToCrucible repr) callFnHandle hndl Ctx.empty
-- | Read the given memory address
readMem :: M.ArchAddrValue arch ids readMem :: M.ArchAddrValue arch ids
-> M.MemRepr tp -> M.MemRepr tp
-> CrucGen arch ids s (C.Atom s (ToCrucibleType tp)) -> CrucGen arch ids s (C.Atom s (ToCrucibleType tp))
readMem addr repr = do readMem addr repr = do
hndl <- readMemHandle repr hndl <- readMemHandle repr
caddr <- valueToCrucible addr caddr <- valueToCrucible addr
runCall hndl (Ctx.empty Ctx.%> caddr) (memReprToCrucible repr) callFnHandle hndl (Ctx.empty Ctx.%> caddr)
writeMem :: M.ArchAddrValue arch ids writeMem :: M.ArchAddrValue arch ids
-> M.MemRepr tp -> M.MemRepr tp
@ -353,7 +417,7 @@ writeMem addr repr val = do
caddr <- valueToCrucible addr caddr <- valueToCrucible addr
cval <- valueToCrucible val cval <- valueToCrucible val
let args = Ctx.empty Ctx.%> caddr Ctx.%> cval let args = Ctx.empty Ctx.%> caddr Ctx.%> cval
void $ runCall hndl args C.UnitRepr void $ callFnHandle hndl args
assignRhsToCrucible :: M.AssignRhs arch ids tp assignRhsToCrucible :: M.AssignRhs arch ids tp
-> CrucGen arch ids s (C.Atom s (ToCrucibleType tp)) -> CrucGen arch ids s (C.Atom s (ToCrucibleType tp))
@ -363,25 +427,88 @@ assignRhsToCrucible rhs =
M.SetUndefined mrepr -> freshSymbolic mrepr M.SetUndefined mrepr -> freshSymbolic mrepr
M.ReadMem addr repr -> readMem addr repr M.ReadMem addr repr -> readMem addr repr
M.EvalArchFn f _ -> do M.EvalArchFn f _ -> do
fn <- gets translateArchFn fn <- translateArchFn <$> getCtx
fn f fn f
addMacawStmt :: M.Stmt arch ids -> CrucGen arch ids s () addMacawStmt :: M.Stmt arch ids -> CrucGen arch ids s ()
addMacawStmt stmt = do addMacawStmt stmt =
case stmt of case stmt of
M.AssignStmt asgn -> do M.AssignStmt asgn -> do
let idx = M.assignId asgn let idx = M.assignId asgn
a <- assignRhsToCrucible (M.assignRhs asgn) a <- assignRhsToCrucible (M.assignRhs asgn)
modify' $ \s -> s { assignValueMap = MapF.insert idx (WrappedAtom a) (assignValueMap s) } assignValueMapLens %= MapF.insert idx (WrappedAtom a)
M.WriteMem addr repr val -> do M.WriteMem addr repr val -> do
writeMem addr repr val writeMem addr repr val
M.PlaceHolderStmt _vals msg -> do M.PlaceHolderStmt _vals msg -> do
cmsg <- crucibleValue (C.TextLit (Text.pack msg)) cmsg <- crucibleValue (C.TextLit (Text.pack msg))
addTermStmt (C.ErrorStmt cmsg) addTermStmt (C.ErrorStmt cmsg)
M.InstructionStart _ _ -> M.InstructionStart addr _ -> do
pure () cns <- archConstraints <$> getCtx
cns $ do
modify $ \s -> s { codeAddr = fromIntegral addr }
M.Comment _txt -> do M.Comment _txt -> do
pure () pure ()
M.ExecArchStmt astmt -> do M.ExecArchStmt astmt -> do
f <- gets translateArchStmt f <- translateArchStmt <$> getCtx
f astmt f astmt
lookupCrucibleLabel :: Word64 -> CrucGen arch ids s (C.Label s)
lookupCrucibleLabel idx = do
m <- macawIndexToLabelMap <$> getCtx
case Map.lookup idx m of
Nothing -> fail $ "Could not find label for block " ++ show idx
Just l -> pure l
createRegStruct :: M.RegState (M.ArchReg arch) (M.Value arch ids)
-> CrucGen arch ids s (C.Atom s (ArchRegStruct arch))
createRegStruct _regs = do
let ctx = undefined
a = undefined
crucibleValue (C.MkStruct ctx a)
addMacawTermStmt :: M.TermStmt arch ids -> CrucGen arch ids s ()
addMacawTermStmt tstmt =
case tstmt of
M.FetchAndExecute regs -> do
s <- createRegStruct regs
addTermStmt (C.Return s)
M.Branch macawPred macawTrueLbl macawFalseLbl -> do
p <- valueToCrucible macawPred
t <- lookupCrucibleLabel macawTrueLbl
f <- lookupCrucibleLabel macawFalseLbl
addTermStmt (C.Br p t f)
M.Syscall regs -> do
h <- syscallHandle <$> getCtx
s <- createRegStruct regs
s' <- callFnHandle h (Ctx.empty Ctx.%> s)
addTermStmt (C.Return s')
M.TranslateError _regs msg -> do
cmsg <- crucibleValue (C.TextLit msg)
addTermStmt (C.ErrorStmt cmsg)
addMacawBlock :: CrucGenContext arch ids s
-> Word64 -- ^ Starting IP for block
-> M.Block arch ids
-> ExceptT String
(StateT (CrucPersistentState arch ids s) (ST s))
()
addMacawBlock ctx addr b = do
pstate <- get
let idx = M.blockLabel b
lbl <-
case Map.lookup idx (macawIndexToLabelMap ctx) of
Just lbl -> pure lbl
Nothing -> throwError $ "Internal: Could not find block with index " ++ show idx
let s0 = CrucGenState { crucCtx = ctx
, crucPState = pstate
, blockLabel = lbl
, macawBlockIndex = idx
, codeAddr = addr
, prevStmts = []
}
let cont _s () = fail "Unterminated crucible block"
let action = do
mapM_ addMacawStmt (M.blockStmts b)
addMacawTermStmt (M.blockTerm b)
r <- lift $ lift $ unContGen action s0 cont
put $!r

View File

@ -68,6 +68,8 @@ instance ( RegisterInfo(ArchReg arch)
data Block arch ids data Block arch ids
= Block { blockLabel :: !Word64 = Block { blockLabel :: !Word64
-- ^ Index of this block -- ^ Index of this block
, blockAddr :: !(ArchSegmentOff arch)
-- ^ Address at start of block
, blockStmts :: !([Stmt arch ids]) , blockStmts :: !([Stmt arch ids])
-- ^ List of statements in the block. -- ^ List of statements in the block.
, blockTerm :: !(TermStmt arch ids) , blockTerm :: !(TermStmt arch ids)

View File

@ -483,7 +483,6 @@ class ( OrdF r
-- | Registers used for passing system call arguments -- | Registers used for passing system call arguments
syscallArgumentRegs :: [r (BVType (RegAddrWidth r))] syscallArgumentRegs :: [r (BVType (RegAddrWidth r))]
-- The value of the current instruction pointer. -- The value of the current instruction pointer.
curIP :: RegisterInfo r curIP :: RegisterInfo r
=> Simple Lens (RegState r f) (f (BVType (RegAddrWidth r))) => Simple Lens (RegState r f) (f (BVType (RegAddrWidth r)))

View File

@ -177,7 +177,8 @@ rewriteBlock b = do
rewriteTermStmt (blockTerm b) rewriteTermStmt (blockTerm b)
-- Return new block -- Return new block
pure $ pure $
Block { blockLabel = blockLabel b Block { blockAddr = blockAddr b
, blockLabel = blockLabel b
, blockStmts = tgtStmts , blockStmts = tgtStmts
, blockTerm = tgtTermStmt , blockTerm = tgtTermStmt
} }
@ -208,9 +209,7 @@ addBlockDemands b = do
-- | Return a block after filtering out statements not needed to compute it. -- | Return a block after filtering out statements not needed to compute it.
elimDeadBlockStmts :: AssignIdSet ids -> Block arch ids -> Block arch ids elimDeadBlockStmts :: AssignIdSet ids -> Block arch ids -> Block arch ids
elimDeadBlockStmts demandSet b = elimDeadBlockStmts demandSet b =
Block { blockLabel = blockLabel b b { blockStmts = filter (stmtNeeded demandSet) (blockStmts b)
, blockStmts = filter (stmtNeeded demandSet) (blockStmts b)
, blockTerm = blockTerm b
} }
------------------------------------------------------------------------ ------------------------------------------------------------------------
@ -780,7 +779,7 @@ transferBlocks src finfo sz block_map =
, _newFunctionAddrs = [] , _newFunctionAddrs = []
} }
let (pblock, ps) = runState (parseBlock ctx b regs) ps0 let (pblock, ps) = runState (parseBlock ctx b regs) ps0
let pb = ParsedBlock { blockAddr = src let pb = ParsedBlock { pblockAddr = src
, blockSize = sz , blockSize = sz
, blockReason = foundReason finfo , blockReason = foundReason finfo
, blockAbstractState = foundAbstractState finfo , blockAbstractState = foundAbstractState finfo
@ -795,12 +794,13 @@ transferBlocks src finfo sz block_map =
transfer :: ArchSegmentOff arch transfer :: ArchSegmentOff arch
-> FunM arch ids () -> FunM arch ids ()
transfer addr = do transfer addr = do
ainfo <- uses curFunCtx archInfo s <- use curFunCtx
let ainfo = archInfo s
withArchConstraints ainfo $ do withArchConstraints ainfo $ do
mfinfo <- use $ foundAddrs . at addr mfinfo <- use $ foundAddrs . at addr
let finfo = fromMaybe (error $ "transfer called on unfound address " ++ show addr ++ ".") $ let finfo = fromMaybe (error $ "transfer called on unfound address " ++ show addr ++ ".") $
mfinfo mfinfo
mem <- uses curFunCtx memory let mem = memory s
nonceGen <- gets funNonceGen nonceGen <- gets funNonceGen
prev_block_map <- use $ curFunBlocks prev_block_map <- use $ curFunBlocks
-- Get maximum number of bytes to disassemble -- Get maximum number of bytes to disassemble
@ -813,33 +813,36 @@ transfer addr = do
let ab = foundAbstractState finfo let ab = foundAbstractState finfo
(bs0, sz, maybeError) <- (bs0, sz, maybeError) <-
liftST $ disassembleFn ainfo mem nonceGen addr max_size ab liftST $ disassembleFn ainfo mem nonceGen addr max_size ab
-- If no blocks are returned, then we just add an empty parsed block.
if null bs0 then do
let errMsg = Text.pack $ fromMaybe "Unknown error" maybeError
let stmts = StatementList
{ stmtsIdent = 0
, stmtsNonterm = []
, stmtsTerm = ParsedTranslateError errMsg
, stmtsAbsState = initAbsProcessorState mem (foundAbstractState finfo)
}
let pb = ParsedBlock { pblockAddr = addr
, blockSize = sz
, blockReason = foundReason finfo
, blockAbstractState = foundAbstractState finfo
, blockStatementList = stmts
}
curFunBlocks %= Map.insert addr pb
else do
-- Rewrite returned blocks to simplify expressions
let ctx = RewriteContext { rwctxNonceGen = nonceGen let ctx = RewriteContext { rwctxNonceGen = nonceGen
, rwctxArchFn = rewriteArchFn ainfo , rwctxArchFn = rewriteArchFn ainfo
, rwctxArchStmt = rewriteArchStmt ainfo , rwctxArchStmt = rewriteArchStmt ainfo
, rwctxConstraints = \x -> x , rwctxConstraints = \x -> x
} }
bs1 <- liftST $ runRewriter ctx $ do bs1 <- liftST $ runRewriter ctx $ traverse rewriteBlock bs0
traverse rewriteBlock bs0 -- Comute demand set
let demandSet = let demandSet =
runDemandComp (archDemandContext ainfo) $ do runDemandComp (archDemandContext ainfo) $ do
traverse_ addBlockDemands bs1 traverse_ addBlockDemands bs1
let bs2 = elimDeadBlockStmts demandSet <$> bs1 let bs = elimDeadBlockStmts demandSet <$> bs1
-- Call transfer blocks to calculate parsedblocks
-- Make sure at least one block is returned
let bs | null bs2 =
let -- TODO: Fix this to work with segmented memory
w = addrWidthNatRepr (archAddrWidth ainfo)
errState = mkRegState Initial
& boundValue ip_reg .~ RelocatableValue w (relativeSegmentAddr addr)
errMsg = Text.pack $ fromMaybe "Unknown error" maybeError
errBlock = Block { blockLabel = 0
, blockStmts = []
, blockTerm = TranslateError errState errMsg
}
in [errBlock]
| otherwise = bs2
let block_map = Map.fromList [ (blockLabel b, b) | b <- bs ] let block_map = Map.fromList [ (blockLabel b, b) | b <- bs ]
transferBlocks addr finfo sz block_map transferBlocks addr finfo sz block_map

View File

@ -295,7 +295,7 @@ rewriteStatementList b = do
-- | A contiguous region of instructions in memory. -- | A contiguous region of instructions in memory.
data ParsedBlock arch ids data ParsedBlock arch ids
= ParsedBlock { blockAddr :: !(ArchSegmentOff arch) = ParsedBlock { pblockAddr :: !(ArchSegmentOff arch)
-- ^ Address of region -- ^ Address of region
, blockSize :: !(ArchAddrWord arch) , blockSize :: !(ArchAddrWord arch)
-- ^ The size of the region of memory covered by this. -- ^ The size of the region of memory covered by this.
@ -316,8 +316,8 @@ instance ArchConstraints arch
=> Pretty (ParsedBlock arch ids) where => Pretty (ParsedBlock arch ids) where
pretty b = pretty b =
let sl = blockStatementList b let sl = blockStatementList b
ppOff o = text (show (incAddr (toInteger o) (relativeSegmentAddr (blockAddr b)))) ppOff o = text (show (incAddr (toInteger o) (relativeSegmentAddr (pblockAddr b))))
in text (show (blockAddr b)) PP.<> text ":" <$$> in text (show (pblockAddr b)) PP.<> text ":" <$$>
indent 2 (vcat (ppStmt ppOff <$> stmtsNonterm sl) <$$> ppTermStmt ppOff (stmtsTerm sl)) indent 2 (vcat (ppStmt ppOff <$> stmtsNonterm sl) <$$> ppTermStmt ppOff (stmtsTerm sl))
------------------------------------------------------------------------ ------------------------------------------------------------------------

View File

@ -3,7 +3,7 @@ Copyright : (c) Galois Inc, 2015-2016
Maintainer : jhendrix@galois.com Maintainer : jhendrix@galois.com
Declares 'Memory', a type for representing segmented memory with permissions. Declares 'Memory', a type for representing segmented memory with permissions.
n-} -}
{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-} {-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-} {-# LANGUAGE GADTs #-}
@ -206,6 +206,9 @@ instance Ord (MemWord w) where
-- | Typeclass for legal memory widths -- | Typeclass for legal memory widths
class (1 <= w) => MemWidth w where class (1 <= w) => MemWidth w where
addrWidthRepr :: p w -> AddrWidthRepr w
-- | @addrWidthMod w@ returns @2^(8 * addrSize w - 1)@. -- | @addrWidthMod w@ returns @2^(8 * addrSize w - 1)@.
addrWidthMod :: p w -> Word64 addrWidthMod :: p w -> Word64
@ -268,6 +271,7 @@ instance MemWidth w => Integral (MemWord w) where
instance MemWidth 32 where instance MemWidth 32 where
addrWidthRepr _ = Addr32
addrWidthMod _ = 0xffffffff addrWidthMod _ = 0xffffffff
addrRotate (MemWord w) i = MemWord (fromIntegral ((fromIntegral w :: Word32) `rotate` i)) addrRotate (MemWord w) i = MemWord (fromIntegral ((fromIntegral w :: Word32) `rotate` i))
addrSize _ = 4 addrSize _ = 4
@ -279,6 +283,7 @@ instance MemWidth 32 where
LittleEndian -> Just $ MemWord $ fromIntegral $ bsWord32le s LittleEndian -> Just $ MemWord $ fromIntegral $ bsWord32le s
instance MemWidth 64 where instance MemWidth 64 where
addrWidthRepr _ = Addr64
addrWidthMod _ = 0xffffffffffffffff addrWidthMod _ = 0xffffffffffffffff
addrRotate (MemWord w) i = MemWord (w `rotate` i) addrRotate (MemWord w) i = MemWord (w `rotate` i)
addrSize _ = 8 addrSize _ = 8