Start support for ParsedBlock.

This commit is contained in:
Joe Hendrix 2018-01-05 11:02:11 -08:00
parent 250c41d40b
commit 7ee4f6ef28
No known key found for this signature in database
GPG Key ID: 8DFA5FF784098C4F
5 changed files with 371 additions and 153 deletions

View File

@ -1,5 +1,5 @@
{-| {-|
Copyright : (c) Galois, Inc 2016-2017 Copyright : (c) Galois, Inc 2016-2018
Maintainer : jhendrix@galois.com Maintainer : jhendrix@galois.com
This defines the main data structure for storing information learned from code This defines the main data structure for storing information learned from code

View File

@ -659,8 +659,8 @@ memAsAddrPairs mem end = addrWidthClass (memAddrWidth mem) $ do
------------------------------------------------------------------------ ------------------------------------------------------------------------
-- MemAddr -- MemAddr
-- | A memory address is either an absolute value in memory or an offset of segment that -- | A memory address is either an absolute value in memory or an
-- could be relocated. -- offset of segment that could be relocated.
-- --
-- This representation does not require that the address is mapped to -- This representation does not require that the address is mapped to
-- actual memory (see `MemSegmentOff` for an address representation -- actual memory (see `MemSegmentOff` for an address representation

View File

@ -11,29 +11,36 @@ module Data.Macaw.Symbolic
( Data.Macaw.Symbolic.CrucGen.CrucGenArchFunctions(..) ( Data.Macaw.Symbolic.CrucGen.CrucGenArchFunctions(..)
, Data.Macaw.Symbolic.CrucGen.CrucGen , Data.Macaw.Symbolic.CrucGen.CrucGen
, MacawSimulatorState , MacawSimulatorState
, stepBlocks , freshVarsForRegs
, runCodeBlock
, runBlocks
, mkBlocksCFG
, mkFunCFG
, Data.Macaw.Symbolic.PersistentState.ArchRegContext , Data.Macaw.Symbolic.PersistentState.ArchRegContext
, Data.Macaw.Symbolic.PersistentState.ToCrucibleType , Data.Macaw.Symbolic.PersistentState.ToCrucibleType
, Data.Macaw.Symbolic.PersistentState.UsedHandleSet
) where ) where
import Control.Monad.Except import Control.Lens ((^.))
import Control.Monad.ST import Control.Monad (forM)
import Control.Monad.State.Strict import Control.Monad.ST (ST, RealWorld, stToIO)
import Data.Foldable
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 Data.Parameterized.Context as Ctx import Data.Parameterized.Context as Ctx
import qualified Data.Parameterized.Map as MapF import qualified Data.Parameterized.Map as MapF
import Data.Parameterized.TraversableFC import Data.Parameterized.TraversableFC
import qualified Data.Set as Set import qualified Data.Set as Set
import Data.Text (Text)
import qualified Data.Text as Text import qualified Data.Text as Text
import Data.Word import Data.Word
import qualified Lang.Crucible.Analysis.Postdom as C
import qualified Lang.Crucible.CFG.Core as C import qualified Lang.Crucible.CFG.Core as C
import qualified Lang.Crucible.CFG.Reg as CR import qualified Lang.Crucible.CFG.Reg as CR
import qualified Lang.Crucible.CFG.SSAConversion as C import qualified Lang.Crucible.CFG.SSAConversion as C
import qualified Lang.Crucible.Config as C import qualified Lang.Crucible.Config as C
import qualified Lang.Crucible.FunctionHandle as C import qualified Lang.Crucible.FunctionHandle as C
import qualified Lang.Crucible.FunctionName as C import qualified Lang.Crucible.FunctionName as C
import qualified Lang.Crucible.ProgramLoc as C
import qualified Lang.Crucible.Simulator.ExecutionTree as C import qualified Lang.Crucible.Simulator.ExecutionTree as C
import qualified Lang.Crucible.Simulator.GlobalState as C import qualified Lang.Crucible.Simulator.GlobalState as C
import qualified Lang.Crucible.Simulator.OverrideSim as C import qualified Lang.Crucible.Simulator.OverrideSim as C
@ -43,6 +50,7 @@ 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.CFG.Core as M
import qualified Data.Macaw.Discovery.State 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
@ -52,20 +60,20 @@ import Data.Macaw.Symbolic.PersistentState
data MacawSimulatorState sym = MacawSimulatorState data MacawSimulatorState sym = MacawSimulatorState
-- | Create the variables from a collection of registers. -- | Create the variables from a collection of registers.
regVars :: (IsSymInterface sym, M.HasRepr reg M.TypeRepr) freshVarsForRegs :: (IsSymInterface sym, M.HasRepr reg M.TypeRepr)
=> sym => sym
-> (forall tp . reg tp -> SolverSymbol) -> (forall tp . reg tp -> SolverSymbol)
-> Ctx.Assignment reg ctx -> Ctx.Assignment reg ctx
-> IO (Ctx.Assignment (C.RegValue' sym) (CtxToCrucibleType ctx)) -> IO (Ctx.Assignment (C.RegValue' sym) (CtxToCrucibleType ctx))
regVars sym nameFn a = freshVarsForRegs sym nameFn a =
case a of case a of
Empty -> pure Ctx.empty Empty -> pure Ctx.empty
b :> reg -> do b :> reg -> do
varAssign <- regVars sym nameFn b varAssign <- freshVarsForRegs sym nameFn b
c <- freshConstant sym (nameFn reg) (typeToCrucibleBase (M.typeRepr reg)) c <- freshConstant sym (nameFn reg) (typeToCrucibleBase (M.typeRepr reg))
pure (varAssign :> C.RV c) pure (varAssign :> C.RV c)
#if !MIN_VERSION_base(4,10,0) #if !MIN_VERSION_base(4,10,0)
_ -> error "internal: regVars encountered case non-exhaustive pattern" _ -> error "internal: freshVarsForRegs encountered case non-exhaustive pattern"
#endif #endif
-- | An override that creates a fresh value with the given type. -- | An override that creates a fresh value with the given type.
@ -95,28 +103,28 @@ runWriteMemOverride :: M.AddrWidthRepr w -- ^ Width of a pointer
(C.RegValue sym C.UnitType) (C.RegValue sym C.UnitType)
runWriteMemOverride = undefined runWriteMemOverride = undefined
createHandleBinding :: CrucGenContext arch s createHandleBinding :: M.AddrWidthRepr (M.ArchAddrWidth arch)
-> HandleId arch '(args, rtp) -> HandleId arch '(args, rtp)
-> C.OverrideSim MacawSimulatorState sym ret args rtp (C.RegValue sym rtp) -> C.OverrideSim MacawSimulatorState sym ret args rtp (C.RegValue sym rtp)
createHandleBinding ctx hid = createHandleBinding w hid =
case hid of case hid of
MkFreshSymId repr -> runFreshSymOverride repr MkFreshSymId repr -> runFreshSymOverride repr
ReadMemId repr -> runReadMemOverride (archWidthRepr ctx) repr ReadMemId repr -> runReadMemOverride w repr
WriteMemId repr -> runWriteMemOverride (archWidthRepr ctx) repr WriteMemId repr -> runWriteMemOverride w repr
-- | This function identifies all the handles needed, and returns -- | This function identifies all the handles needed, and returns
-- function bindings for each one. -- function bindings for each one.
createHandleMap :: forall arch s sym createHandleMap :: forall arch sym
. CrucGenContext arch s . M.AddrWidthRepr (M.ArchAddrWidth arch)
-> UsedHandleSet arch -> UsedHandleSet arch
-> C.FunctionBindings MacawSimulatorState sym -> C.FunctionBindings MacawSimulatorState sym
createHandleMap ctx = MapF.foldrWithKey go C.emptyHandleMap createHandleMap w = MapF.foldrWithKey go C.emptyHandleMap
where go :: HandleId arch pair where go :: HandleId arch pair
-> HandleVal pair -> HandleVal pair
-> C.FunctionBindings MacawSimulatorState sym -> C.FunctionBindings MacawSimulatorState sym
-> C.FunctionBindings MacawSimulatorState sym -> C.FunctionBindings MacawSimulatorState sym
go hid (HandleVal h) b = go hid (HandleVal h) b =
let o = C.mkOverride' (handleIdName hid) (handleIdRetType hid) (createHandleBinding ctx hid) let o = C.mkOverride' (handleIdName hid) (handleIdRetType hid) (createHandleBinding w hid)
in C.insertHandleMap h (C.UseOverride o) b in C.insertHandleMap h (C.UseOverride o) b
mkMemSegmentBinding :: (1 <= w) mkMemSegmentBinding :: (1 <= w)
@ -141,57 +149,144 @@ mkMemBaseVarMap halloc mem = do
] ]
Map.fromList <$> traverse (mkMemSegmentBinding halloc (M.memWidth mem)) (Set.toList baseIndices) Map.fromList <$> traverse (mkMemSegmentBinding halloc (M.memWidth mem)) (Set.toList baseIndices)
stepBlocks :: forall sym arch ids -- | Create a Crucible CFG from a list of blocks
. (IsSymInterface sym, M.ArchConstraints arch) mkCrucCFG :: forall s arch ids
=> sym . M.ArchConstraints arch
=> C.HandleAllocator s
-- ^ Handle allocator to make function handles
-> CrucGenArchFunctions arch -> CrucGenArchFunctions arch
-> M.Memory (M.ArchAddrWidth arch) -- ^ Crucible architecture-specific functions.
-- ^ Memory image for executable -> MemSegmentMap (M.ArchAddrWidth arch)
-> Text -- ^ Map from region indices to their address
-- ^ Name of executable
-> C.FunctionName -> C.FunctionName
-- ^ Name of function for pretty print purposes. -- ^ Name of function for pretty print purposes.
-> Word64 -> (CrucGenContext arch s
-- ^ Code address -> MacawMonad arch ids s [CR.Block s (MacawFunctionResult arch)])
-> [M.Block arch ids] -- ^ Action to run
-- ^ List of blocks -> ST s (UsedHandleSet arch, C.SomeCFG (EmptyCtx ::> ArchRegStruct arch) (ArchRegStruct arch))
-> IO (C.ExecResult mkCrucCFG halloc archFns memBaseVarMap nm action = do
MacawSimulatorState let regAssign = crucGenRegAssignment archFns
sym
(C.RegEntry sym (C.StructType (CtxToCrucibleType (ArchRegContext arch)))))
stepBlocks sym sinfo mem binPath nm addr macawBlocks = do
let regAssign = crucGenRegAssignment sinfo
let crucRegTypes = typeCtxToCrucible (fmapFC M.typeRepr regAssign) let crucRegTypes = typeCtxToCrucible (fmapFC M.typeRepr regAssign)
let macawStructRepr = C.StructRepr crucRegTypes let macawStructRepr = C.StructRepr crucRegTypes
halloc <- C.newHandleAllocator
let argTypes = Empty :> macawStructRepr let argTypes = Empty :> macawStructRepr
h <- stToIO $ C.mkHandle' halloc nm argTypes macawStructRepr h <- C.mkHandle' halloc nm argTypes macawStructRepr
-- Map block map to Crucible CFG
let blockLabelMap :: Map Word64 (CR.Label RealWorld)
blockLabelMap = Map.fromList [ (w, CR.Label (fromIntegral w))
| w <- M.blockLabel <$> macawBlocks ]
memBaseVarMap <- stToIO $ mkMemBaseVarMap halloc mem
let genCtx = CrucGenContext { archConstraints = \x -> x let genCtx = CrucGenContext { archConstraints = \x -> x
, macawRegAssign = regAssign , macawRegAssign = regAssign
, regIndexMap = mkRegIndexMap regAssign (Ctx.size crucRegTypes) , regIndexMap = mkRegIndexMap regAssign (Ctx.size crucRegTypes)
, handleAlloc = halloc , handleAlloc = halloc
, binaryPath = binPath
, macawIndexToLabelMap = blockLabelMap
, memBaseAddrMap = memBaseVarMap , memBaseAddrMap = memBaseVarMap
} }
let ps0 = initCrucPersistentState let ps0 = initCrucPersistentState
blockRes <- stToIO $ runStateT (runExceptT (mapM_ (addMacawBlock sinfo genCtx addr) macawBlocks)) ps0 blockRes <- runMacawMonad ps0 (action genCtx)
ps <- (blks, ps) <-
case blockRes of case blockRes of
(Left err, _) -> fail err (Left err, _) -> fail err
(Right _, s) -> pure s (Right blks, s) -> pure (blks, s)
-- Create control flow graph -- Create control flow graph
let rg :: CR.CFG RealWorld (MacawFunctionArgs arch) (MacawFunctionResult arch) let rg :: CR.CFG s (MacawFunctionArgs arch) (MacawFunctionResult arch)
rg = CR.CFG { CR.cfgHandle = h rg = CR.CFG { CR.cfgHandle = h
, CR.cfgBlocks = Map.elems (seenBlockMap ps) , CR.cfgBlocks = blks
} }
pure $ (handleMap ps, C.toSSA rg)
-- | Create a Crucible CFG from a list of blocks
addBlocksCFG :: forall s arch ids
. M.ArchConstraints arch
=> CrucGenArchFunctions arch
-- ^ Crucible specific functions.
-> CrucGenContext arch s
-> (M.ArchAddrWord arch -> C.Position)
-- ^ Function that maps offsets from start of block to Crucible position.
-> [M.Block arch ids]
-- ^ List of blocks for this region.
-> MacawMonad arch ids s [CR.Block s (MacawFunctionResult arch)]
addBlocksCFG archFns ctx posFn macawBlocks = do
-- Map block map to Crucible CFG
let blockLabelMap :: Map Word64 (CR.Label s)
blockLabelMap = Map.fromList [ (w, CR.Label (fromIntegral w))
| w <- M.blockLabel <$> macawBlocks ]
forM macawBlocks $ \b -> do
addMacawBlock archFns ctx blockLabelMap posFn b
-- | Create a Crucible CFG from a list of blocks
mkBlocksCFG :: forall s arch ids
. M.ArchConstraints arch
=> C.HandleAllocator s
-- ^ Handle allocator to make the blocks
-> CrucGenArchFunctions arch
-- ^ Crucible specific functions.
-> MemSegmentMap (M.ArchAddrWidth arch)
-- ^ Map from region indices to their address
-> C.FunctionName
-- ^ Name of function for pretty print purposes.
-> (M.ArchAddrWord arch -> C.Position)
-- ^ Function that maps offsets from start of block to Crucible position.
-> [M.Block arch ids]
-- ^ List of blocks for this region.
-> ST s (UsedHandleSet arch, C.SomeCFG (EmptyCtx ::> ArchRegStruct arch) (ArchRegStruct arch))
mkBlocksCFG halloc archFns memBaseVarMap nm posFn macawBlocks = do
mkCrucCFG halloc archFns memBaseVarMap nm $ \ctx -> do
addBlocksCFG archFns ctx posFn macawBlocks
type FunBlockMap arch s = Map (M.ArchSegmentOff arch, Word64) (CR.Label s)
mkFunCFG :: forall s arch ids
. M.ArchConstraints arch
=> C.HandleAllocator s
-- ^ Handle allocator to make the blocks
-> CrucGenArchFunctions arch
-- ^ Crucible specific functions.
-> MemSegmentMap (M.ArchAddrWidth arch)
-- ^ Map from region indices to their address
-> C.FunctionName
-- ^ Name of function for pretty print purposes.
-> (M.ArchSegmentOff arch -> C.Position)
-- ^ Function that maps function address to Crucible position
-> M.DiscoveryFunInfo arch ids
-- ^ List of blocks for this region.
-> ST s (UsedHandleSet arch, C.SomeCFG (EmptyCtx ::> ArchRegStruct arch) (ArchRegStruct arch))
mkFunCFG halloc archFns memBaseVarMap nm posFn fn = do
mkCrucCFG halloc archFns memBaseVarMap nm $ \ctx -> do
let insSentences :: M.ArchSegmentOff arch
-> (FunBlockMap arch s,Int)
-> [M.StatementList arch ids]
-> (FunBlockMap arch s,Int)
insSentences _ m [] = m
insSentences base (m,c) (s:r) =
insSentences base
(Map.insert (base,M.stmtsIdent s) (CR.Label c) m,c+1)
(nextStatements (M.stmtsTerm s) ++ r)
let insBlock :: (FunBlockMap arch s,Int) -> M.ParsedBlock arch ids -> (FunBlockMap arch s,Int)
insBlock m b = insSentences (M.pblockAddr b) m [M.blockStatementList b]
let blockLabelMap :: FunBlockMap arch s
blockLabelMap = fst $ foldl' insBlock (Map.empty,0) (Map.elems (fn^.M.parsedBlocks))
fmap concat $
forM (Map.elems (fn^.M.parsedBlocks)) $ \b -> do
addParsedBlock archFns ctx blockLabelMap posFn b
-- | Run the simulator over a contiguous set of code.
runCodeBlock :: forall sym arch blocks
. (IsSymInterface sym, M.ArchConstraints arch)
=> sym
-> CrucGenArchFunctions arch
-> C.HandleAllocator RealWorld
-> UsedHandleSet arch
-- ^ Handle map
-> C.CFG blocks (EmptyCtx ::> ArchRegStruct arch) (ArchRegStruct arch)
-> Ctx.Assignment (C.RegValue' sym) (ArchCrucibleRegTypes arch)
-- ^ Register assignment
-> IO (C.ExecResult
MacawSimulatorState
sym
(C.RegEntry sym (ArchRegStruct arch)))
runCodeBlock sym archFns halloc hmap g regStruct = do
let regAssign = crucGenRegAssignment archFns
let crucRegTypes = typeCtxToCrucible (fmapFC M.typeRepr regAssign)
let macawStructRepr = C.StructRepr crucRegTypes
-- Run the symbolic simulator.
cfg <- C.initialConfig 0 [] cfg <- C.initialConfig 0 []
let ptrWidth :: M.AddrWidthRepr (M.ArchAddrWidth arch)
ptrWidth = M.addrWidthRepr ptrWidth
let ctx :: C.SimContext MacawSimulatorState sym let ctx :: C.SimContext MacawSimulatorState sym
ctx = C.SimContext { C._ctxSymInterface = sym ctx = C.SimContext { C._ctxSymInterface = sym
, C.ctxSolverProof = \a -> a , C.ctxSolverProof = \a -> a
@ -199,18 +294,41 @@ stepBlocks sym sinfo mem binPath nm addr macawBlocks = do
, C.simConfig = cfg , C.simConfig = cfg
, C.simHandleAllocator = halloc , C.simHandleAllocator = halloc
, C.printHandle = stdout , C.printHandle = stdout
, C._functionBindings = createHandleMap genCtx (handleMap ps) , C._functionBindings =
C.insertHandleMap (C.cfgHandle g) (C.UseCFG g (C.postdomInfo g)) $
createHandleMap ptrWidth hmap
, C._cruciblePersonality = MacawSimulatorState , C._cruciblePersonality = MacawSimulatorState
} }
-- 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. C.runOverrideSim s macawStructRepr $ do
-- This should be a symbolic variable for each register in the architecture.
regStruct <- regVars sym (crucGenArchRegName sinfo) regAssign
let args :: C.RegMap sym (MacawFunctionArgs arch) let args :: C.RegMap sym (MacawFunctionArgs arch)
args = C.RegMap (Ctx.singleton (C.RegEntry macawStructRepr regStruct)) args = C.RegMap (Ctx.singleton (C.RegEntry macawStructRepr regStruct))
-- Run the symbolic simulator.
case C.toSSA rg of
C.SomeCFG g ->
C.runOverrideSim s macawStructRepr $ do
C.regValue <$> C.callCFG g args C.regValue <$> C.callCFG g args
-- | Run the simulator over a contiguous set of code.
runBlocks :: forall sym arch ids
. (IsSymInterface sym, M.ArchConstraints arch)
=> sym
-> CrucGenArchFunctions arch
-- ^ Crucible specific functions.
-> M.Memory (M.ArchAddrWidth arch)
-- ^ Memory image for executable
-> C.FunctionName
-- ^ Name of function for pretty print purposes.
-> (M.ArchAddrWord arch -> C.Position)
-- ^ Function that maps offsets from start of block to Crucible position.
-> [M.Block arch ids]
-- ^ List of blocks for this region.
-> Ctx.Assignment (C.RegValue' sym) (CtxToCrucibleType (ArchRegContext arch))
-- ^ Register assignment
-> IO (C.ExecResult
MacawSimulatorState
sym
(C.RegEntry sym (C.StructType (CtxToCrucibleType (ArchRegContext arch)))))
runBlocks sym archFns mem nm posFn macawBlocks regStruct = do
halloc <- C.newHandleAllocator
memBaseVarMap <- stToIO $ mkMemBaseVarMap halloc mem
(hmap, C.SomeCFG g) <- stToIO $ mkBlocksCFG halloc archFns memBaseVarMap nm posFn macawBlocks
-- Run the symbolic simulator.
runCodeBlock sym archFns halloc hmap g regStruct

View File

@ -8,19 +8,24 @@ This defines the core operations for mapping from Reopt to Crucible.
{-# LANGUAGE DataKinds #-} {-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-} {-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PolyKinds #-} {-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-} {-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-} {-# LANGUAGE TypeOperators #-}
{-# OPTIONS_GHC -Wwarn #-}
module Data.Macaw.Symbolic.CrucGen module Data.Macaw.Symbolic.CrucGen
( CrucGenArchFunctions(..) ( CrucGenArchFunctions(..)
-- ** Operations for implementing new backends. -- ** Operations for implementing new backends.
, CrucGen , CrucGen
, MacawMonad
, runMacawMonad
, addMacawBlock , addMacawBlock
, addParsedBlock
, nextStatements
) where ) where
import Control.Lens hiding (Empty, (:>)) import Control.Lens hiding (Empty, (:>))
@ -30,8 +35,10 @@ import Control.Monad.State.Strict
import Data.Bits import Data.Bits
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.CFG.Block as M
import qualified Data.Macaw.Discovery.State 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 qualified Data.Map.Strict as Map import qualified Data.Map.Strict as Map
import Data.Parameterized.Context as Ctx import Data.Parameterized.Context as Ctx
import Data.Parameterized.Map (MapF) import Data.Parameterized.Map (MapF)
@ -83,10 +90,12 @@ data CrucGenState arch ids s
, crucCtx :: !(CrucGenContext arch s) , crucCtx :: !(CrucGenContext arch s)
, crucPState :: !(CrucPersistentState arch ids s) , crucPState :: !(CrucPersistentState arch ids s)
-- ^ State that persists across blocks. -- ^ State that persists across blocks.
, macawPositionFn :: !(M.ArchAddrWord arch -> C.Position)
-- ^ Map from offset to Crucible position.
, blockLabel :: (CR.Label s) , blockLabel :: (CR.Label s)
-- ^ Label for this block we are translating -- ^ Label for this block we are translating
, crucPos :: !C.Position , codeOff :: !(M.ArchAddrWord arch)
-- ^ Position in the crucible file. -- ^ Offset
, prevStmts :: ![C.Posd (CR.Stmt s)] , prevStmts :: ![C.Posd (CR.Stmt s)]
-- ^ List of states in reverse order -- ^ List of states in reverse order
} }
@ -98,13 +107,15 @@ assignValueMapLens :: Simple Lens (CrucPersistentState arch ids s)
(MapF (M.AssignId ids) (MacawCrucibleValue (CR.Atom s))) (MapF (M.AssignId ids) (MacawCrucibleValue (CR.Atom s)))
assignValueMapLens = lens assignValueMap (\s v -> s { assignValueMap = v }) assignValueMapLens = lens assignValueMap (\s v -> s { assignValueMap = v })
type CrucGenRet arch ids s = (CrucGenState arch ids s, CR.TermStmt s (MacawFunctionResult arch))
newtype CrucGen arch ids s r newtype CrucGen arch ids s r
= CrucGen { unCrucGen = CrucGen { unCrucGen
:: CrucGenState arch ids s :: CrucGenState arch ids s
-> (CrucGenState arch ids s -> (CrucGenState arch ids s
-> r -> r
-> ST s (CrucPersistentState arch ids s, CR.Block s (MacawFunctionResult arch))) -> ST s (CrucGenRet arch ids s))
-> ST s (CrucPersistentState arch ids s, CR.Block s (MacawFunctionResult arch)) -> ST s (CrucGenRet arch ids s)
} }
instance Functor (CrucGen arch ids s) where instance Functor (CrucGen arch ids s) where
@ -131,7 +142,7 @@ liftST m = CrucGen $ \s cont -> m >>= cont s
-- | Get current position -- | Get current position
getPos :: CrucGen arch ids s C.Position getPos :: CrucGen arch ids s C.Position
getPos = gets crucPos getPos = gets $ \s -> macawPositionFn s (codeOff s)
addStmt :: CR.Stmt s -> CrucGen arch ids s () addStmt :: CR.Stmt s -> CrucGen arch ids s ()
addStmt stmt = seq stmt $ do addStmt stmt = seq stmt $ do
@ -144,13 +155,15 @@ addStmt stmt = seq stmt $ do
addTermStmt :: CR.TermStmt s (MacawFunctionResult arch) addTermStmt :: CR.TermStmt s (MacawFunctionResult arch)
-> CrucGen arch ids s a -> CrucGen arch ids s a
addTermStmt tstmt = do addTermStmt tstmt = do
termPos <- getPos CrucGen $ \s _ -> pure (s, tstmt)
CrucGen $ \s _ -> do {-
let termPos = macawPositionFn s (codeOff s)
let lbl = blockLabel s let lbl = blockLabel s
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 = CR.mkBlock (CR.LabelID lbl) Set.empty stmts term let blk = CR.mkBlock (CR.LabelID lbl) Set.empty stmts term
pure $ (crucPState s, blk) pure $ (crucPState s, blk)
-}
freshValueIndex :: CrucGen arch ids s Int freshValueIndex :: CrucGen arch ids s Int
freshValueIndex = do freshValueIndex = do
@ -235,28 +248,18 @@ bvAdc w x y c = do
cbv <- appAtom =<< C.BVIte c w <$> bvLit w 1 <*> bvLit w 0 cbv <- appAtom =<< C.BVIte c w <$> bvLit w 1 <*> bvLit w 0
appAtom $ C.BVAdd w s cbv appAtom $ C.BVAdd w s cbv
appToCrucible :: M.App (M.Value arch ids) tp appToCrucible :: M.App (M.Value arch ids) tp
-> CrucGen arch ids s (CR.Atom s (ToCrucibleType tp)) -> CrucGen arch ids s (CR.Atom s (ToCrucibleType tp))
appToCrucible app = do appToCrucible app = do
ctx <- getCtx ctx <- getCtx
archConstraints ctx $ do archConstraints ctx $ do
case app of case app of
M.Eq x y -> M.Eq x y -> do
case M.typeRepr x of let btp = typeToCrucibleBase (M.typeRepr x)
M.BoolTypeRepr -> do appAtom =<< C.BaseIsEq btp <$> v2c x <*> v2c y
eq <- appAtom =<< C.BoolXor <$> v2c x <*> v2c y M.Mux tp c t f -> do
appAtom (C.Not eq) let btp = typeToCrucibleBase tp
M.BVTypeRepr w -> do appAtom =<< C.BaseIte btp <$> v2c c <*> v2c t <*> v2c f
appAtom =<< C.BVEq w <$> v2c x <*> v2c y
M.TupleTypeRepr _ -> undefined -- TODO: Fix this
M.Mux tp c t f ->
case tp of
M.BoolTypeRepr ->
appAtom =<< C.BoolIte <$> v2c c <*> v2c t <*> v2c f
M.BVTypeRepr w ->
appAtom =<< C.BVIte <$> v2c c <*> pure w <*> v2c t <*> v2c f
M.TupleTypeRepr _ -> undefined -- TODO: Fix this
M.TupleField tps x i -> M.TupleField tps x i ->
undefined tps x i -- TODO: Fix this undefined tps x i -- TODO: Fix this
@ -367,7 +370,7 @@ mkHandleVal hid = do
Just (HandleVal h) -> pure h Just (HandleVal h) -> pure h
Nothing -> do Nothing -> do
ctx <- getCtx ctx <- getCtx
let argTypes = handleIdArgTypes ctx hid let argTypes = handleIdArgTypes (archWidthRepr ctx) hid
let retType = handleIdRetType hid let retType = handleIdRetType hid
hndl <- liftST $ C.mkHandle' (handleAlloc ctx) (handleIdName hid) argTypes retType hndl <- liftST $ C.mkHandle' (handleAlloc ctx) (handleIdName hid) argTypes retType
crucPStateLens . handleMapLens %= MapF.insert hid (HandleVal hndl) crucPStateLens . handleMapLens %= MapF.insert hid (HandleVal hndl)
@ -421,7 +424,8 @@ assignRhsToCrucible rhs =
fns <- translateFns <$> get fns <- translateFns <$> get
crucGenArchFn fns f crucGenArchFn fns f
addMacawStmt :: M.Stmt arch ids -> CrucGen arch ids s () addMacawStmt :: M.Stmt arch ids
-> CrucGen arch ids s ()
addMacawStmt stmt = addMacawStmt stmt =
case stmt of case stmt of
M.AssignStmt asgn -> do M.AssignStmt asgn -> do
@ -433,20 +437,21 @@ addMacawStmt stmt =
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 (CR.ErrorStmt cmsg) addTermStmt (CR.ErrorStmt cmsg)
M.InstructionStart addr _ -> do M.InstructionStart off _ -> do
-- Update the position -- Update the position
modify $ \s -> modify $ \s -> s { codeOff = off }
crucGenArchConstraints (translateFns s) $
s { crucPos = C.BinaryPos (binaryPath (crucCtx s)) (fromIntegral addr) }
M.Comment _txt -> do M.Comment _txt -> do
pure () pure ()
M.ExecArchStmt astmt -> do M.ExecArchStmt astmt -> do
fns <- translateFns <$> get fns <- translateFns <$> get
crucGenArchStmt fns astmt crucGenArchStmt fns astmt
lookupCrucibleLabel :: Word64 -> CrucGen arch ids s (CR.Label s) lookupCrucibleLabel :: Map Word64 (CR.Label s)
lookupCrucibleLabel idx = do -- ^ Map from block index to Crucible label
m <- macawIndexToLabelMap <$> getCtx -> Word64
-- ^ Index of crucible block
-> CrucGen arch ids s (CR.Label s)
lookupCrucibleLabel m idx = do
case Map.lookup idx m of case Map.lookup idx m of
Nothing -> fail $ "Could not find label for block " ++ show idx Nothing -> fail $ "Could not find label for block " ++ show idx
Just l -> pure l Just l -> pure l
@ -464,16 +469,19 @@ createRegStruct regs = do
fields <- macawAssignToCrucM valueToCrucible a fields <- macawAssignToCrucM valueToCrucible a
crucibleValue $ C.MkStruct (typeCtxToCrucible tps) fields crucibleValue $ C.MkStruct (typeCtxToCrucible tps) fields
addMacawTermStmt :: M.TermStmt arch ids -> CrucGen arch ids s () addMacawTermStmt :: Map Word64 (CR.Label s)
addMacawTermStmt tstmt = -- ^ Map from block index to Crucible label
-> M.TermStmt arch ids
-> CrucGen arch ids s ()
addMacawTermStmt blockLabelMap tstmt =
case tstmt of case tstmt of
M.FetchAndExecute regs -> do M.FetchAndExecute regs -> do
s <- createRegStruct regs s <- createRegStruct regs
addTermStmt (CR.Return s) addTermStmt (CR.Return s)
M.Branch macawPred macawTrueLbl macawFalseLbl -> do M.Branch macawPred macawTrueLbl macawFalseLbl -> do
p <- valueToCrucible macawPred p <- valueToCrucible macawPred
t <- lookupCrucibleLabel macawTrueLbl t <- lookupCrucibleLabel blockLabelMap macawTrueLbl
f <- lookupCrucibleLabel macawFalseLbl f <- lookupCrucibleLabel blockLabelMap macawFalseLbl
addTermStmt (CR.Br p t f) addTermStmt (CR.Br p t f)
M.ArchTermStmt ts regs -> do M.ArchTermStmt ts regs -> do
fns <- translateFns <$> get fns <- translateFns <$> get
@ -485,32 +493,133 @@ addMacawTermStmt tstmt =
----------------- -----------------
-- | Monad for adding new blocks to a state. -- | Monad for adding new blocks to a state.
type MacawMonad arch ids s = ExceptT String (StateT (CrucPersistentState arch ids s) (ST s)) newtype MacawMonad arch ids s a
= MacawMonad ( ExceptT String (StateT (CrucPersistentState arch ids s) (ST s)) a)
deriving ( Functor
, Applicative
, Monad
, MonadError String
, MonadState (CrucPersistentState arch ids s)
)
addMacawBlock :: CrucGenArchFunctions arch runMacawMonad :: CrucPersistentState arch ids s
-> MacawMonad arch ids s a
-> ST s (Either String a, CrucPersistentState arch ids s)
runMacawMonad s (MacawMonad m) = runStateT (runExceptT m) s
mmExecST :: ST s a -> MacawMonad arch ids s a
mmExecST = MacawMonad . lift . lift
runCrucGen :: CrucGenArchFunctions arch
-> CrucGenContext arch s -> CrucGenContext arch s
-> Word64 -> (M.ArchAddrWord arch -> C.Position)
-- ^ Code address -- ^ Function for generating position from offset from start of this block.
-> M.Block arch ids -> M.ArchAddrWord arch
-> MacawMonad arch ids s () -- ^ Offset
addMacawBlock tfns ctx addr b = do -> CR.Label s
pstate <- get -> CrucGen arch ids s ()
let idx = M.blockLabel b -> MacawMonad arch ids s (CR.Block s (MacawFunctionResult arch), M.ArchAddrWord arch)
lbl <- runCrucGen tfns ctx posFn off lbl action = do
case Map.lookup idx (macawIndexToLabelMap ctx) of ps <- get
Just lbl -> pure lbl
Nothing -> throwError $ "Internal: Could not find block with index " ++ show idx
let s0 = CrucGenState { translateFns = tfns let s0 = CrucGenState { translateFns = tfns
, crucCtx = ctx , crucCtx = ctx
, crucPState = pstate , crucPState = ps
, macawPositionFn = posFn
, blockLabel = lbl , blockLabel = lbl
, crucPos = C.BinaryPos (binaryPath ctx) addr , codeOff = off
, prevStmts = [] , prevStmts = []
} }
let cont _s () = fail "Unterminated crucible block" let cont _s () = fail "Unterminated crucible block"
let action = do (s, tstmt) <- mmExecST $ unCrucGen action s0 cont
put (crucPState s)
let termPos = macawPositionFn s (codeOff s)
let stmts = Seq.fromList (reverse (prevStmts s))
let term = C.Posd termPos tstmt
let blk = CR.mkBlock (CR.LabelID lbl) Set.empty stmts term
pure (blk, codeOff s)
addMacawBlock :: M.MemWidth (M.ArchAddrWidth arch)
=> CrucGenArchFunctions arch
-> CrucGenContext arch s
-> Map Word64 (CR.Label s)
-- ^ Map from block index to Crucible label
-> (M.ArchAddrWord arch -> C.Position)
-- ^ Function for generating position from offset from start of this block.
-> M.Block arch ids
-> MacawMonad arch ids s (CR.Block s (MacawFunctionResult arch))
addMacawBlock tfns ctx blockLabelMap posFn b = do
let idx = M.blockLabel b
lbl <-
case Map.lookup idx blockLabelMap of
Just lbl ->
pure lbl
Nothing ->
throwError $ "Internal: Could not find block with index " ++ show idx
fmap fst $ runCrucGen tfns ctx posFn 0 lbl $ do
mapM_ addMacawStmt (M.blockStmts b) mapM_ addMacawStmt (M.blockStmts b)
addMacawTermStmt (M.blockTerm b) addMacawTermStmt blockLabelMap (M.blockTerm b)
(ps, blk) <- lift $ lift $ unCrucGen action s0 cont
put $ ps & seenBlockMapLens %~ Map.insert idx blk addMacawParsedTermStmt :: M.ParsedTermStmt arch ids
-> CrucGen arch ids s ()
addMacawParsedTermStmt tstmt =
case tstmt of
M.ParsedCall{} -> undefined
M.ParsedJump{} -> undefined
M.ParsedLookupTable{} -> undefined
M.ParsedReturn{} -> undefined
M.ParsedIte{} -> undefined
M.ParsedArchTermStmt{} -> undefined
M.ParsedTranslateError{} -> undefined
M.ClassifyFailure{} -> undefined
nextStatements :: M.ParsedTermStmt arch ids -> [M.StatementList arch ids]
nextStatements tstmt =
case tstmt of
M.ParsedIte _ x y -> [x, y]
_ -> []
addStatementList :: M.MemWidth (M.ArchAddrWidth arch)
=> CrucGenArchFunctions arch
-> CrucGenContext arch s
-> Map (M.ArchSegmentOff arch, Word64) (CR.Label s)
-- ^ Map from block index to Crucible label
-> M.ArchSegmentOff arch
-- ^ Address of statements
-> (M.ArchAddrWord arch -> C.Position)
-- ^ Function for generating position from offset from start of this block.
-> [(M.ArchAddrWord arch, M.StatementList arch ids)]
-> [CR.Block s (MacawFunctionResult arch)]
-> MacawMonad arch ids s [CR.Block s (MacawFunctionResult arch)]
addStatementList _ _ _ _ _ [] rlist =
pure (reverse rlist)
addStatementList tfns ctx blockLabelMap addr posFn ((off,stmts):rest) r = do
let idx = M.stmtsIdent stmts
lbl <-
case Map.lookup (addr, idx) blockLabelMap of
Just lbl ->
pure lbl
Nothing ->
throwError $ "Internal: Could not find block with address " ++ show addr ++ " index " ++ show idx
(b,off') <-
runCrucGen tfns ctx posFn off lbl $ do
mapM_ addMacawStmt (M.stmtsNonterm stmts)
addMacawParsedTermStmt (M.stmtsTerm stmts)
let new = (off',) <$> nextStatements (M.stmtsTerm stmts)
addStatementList tfns ctx blockLabelMap addr posFn (new ++ rest) (b:r)
addParsedBlock :: forall arch ids s
. M.MemWidth (M.ArchAddrWidth arch)
=> CrucGenArchFunctions arch
-> CrucGenContext arch s
-> Map (M.ArchSegmentOff arch, Word64) (CR.Label s)
-- ^ Map from block index to Crucible label
-> (M.ArchSegmentOff arch -> C.Position)
-- ^ Function for generating position from offset from start of this block.
-> M.ParsedBlock arch ids
-> MacawMonad arch ids s [CR.Block s (MacawFunctionResult arch)]
addParsedBlock tfns ctx blockLabelMap posFn b = do
let base = M.pblockAddr b
let thisPosFn :: M.ArchAddrWord arch -> C.Position
thisPosFn off = posFn r
where Just r = M.incSegmentOff base (toInteger off)
addStatementList tfns ctx blockLabelMap (M.pblockAddr b) thisPosFn [(0, M.blockStatementList b)] []

View File

@ -21,7 +21,6 @@ module Data.Macaw.Symbolic.PersistentState
CrucPersistentState(..) CrucPersistentState(..)
, initCrucPersistentState , initCrucPersistentState
, handleMapLens , handleMapLens
, seenBlockMapLens
-- * Types -- * Types
, ToCrucibleBaseType , ToCrucibleBaseType
, ToCrucibleType , ToCrucibleType
@ -54,8 +53,6 @@ module Data.Macaw.Symbolic.PersistentState
, IndexPair(..) , IndexPair(..)
-- * Values -- * Values
, MacawCrucibleValue(..) , MacawCrucibleValue(..)
-- * Blocks
, CrucSeenBlockMap
) where ) where
import Control.Lens hiding (Index, (:>), Empty) import Control.Lens hiding (Index, (:>), Empty)
@ -64,7 +61,6 @@ import qualified Data.Macaw.CFG 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)
import qualified Data.Map.Strict as Map
import Data.Parameterized.Classes import Data.Parameterized.Classes
import Data.Parameterized.Context import Data.Parameterized.Context
import qualified Data.Parameterized.List as P import qualified Data.Parameterized.List as P
@ -74,8 +70,6 @@ import Data.Parameterized.NatRepr
import Data.Parameterized.TraversableF import Data.Parameterized.TraversableF
import Data.Parameterized.TraversableFC import Data.Parameterized.TraversableFC
import Data.String import Data.String
import Data.Text (Text)
import Data.Word
import qualified Lang.Crucible.CFG.Common as C import qualified Lang.Crucible.CFG.Common as C
import qualified Lang.Crucible.CFG.Reg as CR import qualified Lang.Crucible.CFG.Reg as CR
import qualified Lang.Crucible.FunctionHandle as C import qualified Lang.Crucible.FunctionHandle as C
@ -195,6 +189,10 @@ type ArchConstraints arch
-- | Map from indices of segments without a fixed base address to a -- | Map from indices of segments without a fixed base address to a
-- global variable storing the base address. -- global variable storing the base address.
--
-- This uses a global variable so that we can do the translation, and then
-- decide where to locate it without requiring us to also pass the values
-- around arguments.
type MemSegmentMap w = Map M.RegionIndex (C.GlobalVar (C.BVType w)) type MemSegmentMap w = Map M.RegionIndex (C.GlobalVar (C.BVType w))
--- | Information that does not change during generating Crucible from MAcaw --- | Information that does not change during generating Crucible from MAcaw
@ -203,14 +201,11 @@ data CrucGenContext arch s
{ archConstraints :: !(forall a . (ArchConstraints arch => a) -> a) { archConstraints :: !(forall a . (ArchConstraints arch => a) -> a)
-- ^ Typeclass constraints for architecture -- ^ Typeclass constraints for architecture
, macawRegAssign :: !(Assignment (M.ArchReg arch) (ArchRegContext arch)) , macawRegAssign :: !(Assignment (M.ArchReg arch) (ArchRegContext arch))
-- ^ Assignment from register to the context -- ^ Assignment from register index to the register identifier.
, regIndexMap :: !(RegIndexMap arch) , regIndexMap :: !(RegIndexMap arch)
-- ^ Map from register identifier to the index in Macaw/Crucible.
, handleAlloc :: !(C.HandleAllocator s) , handleAlloc :: !(C.HandleAllocator s)
-- ^ Handle allocator -- ^ Handle allocator
, binaryPath :: !Text
-- ^ Name of binary these blocks come from.
, macawIndexToLabelMap :: !(Map Word64 (CR.Label s))
-- ^ Map from block indices to the associated label.
, memBaseAddrMap :: !(MemSegmentMap (M.ArchAddrWidth arch)) , memBaseAddrMap :: !(MemSegmentMap (M.ArchAddrWidth arch))
-- ^ Map from indices of segments without a fixed base address to a global -- ^ Map from indices of segments without a fixed base address to a global
-- variable storing the base address. -- variable storing the base address.
@ -276,16 +271,21 @@ handleIdName h =
WriteMemId (M.BVMemRepr w end) -> WriteMemId (M.BVMemRepr w end) ->
fromString $ "writeMem_" ++ show (8 * natValue w) ++ "_" ++ endName end fromString $ "writeMem_" ++ show (8 * natValue w) ++ "_" ++ endName end
handleIdArgTypes :: CrucGenContext arch s
widthTypeRepr :: M.AddrWidthRepr w -> C.TypeRepr (C.BVType w)
widthTypeRepr M.Addr32 = C.knownRepr
widthTypeRepr M.Addr64 = C.knownRepr
handleIdArgTypes :: M.AddrWidthRepr (M.ArchAddrWidth arch)
-> HandleId arch '(args, ret) -> HandleId arch '(args, ret)
-> Assignment C.TypeRepr args -> Assignment C.TypeRepr args
handleIdArgTypes ctx h = handleIdArgTypes ptrRepr h =
case h of case h of
MkFreshSymId _repr -> empty MkFreshSymId _repr -> empty
ReadMemId _repr -> archConstraints ctx $ ReadMemId _repr ->
empty :> C.BVRepr (M.addrWidthNatRepr (archWidthRepr ctx)) empty :> widthTypeRepr ptrRepr
WriteMemId repr -> archConstraints ctx $ WriteMemId repr ->
empty :> C.BVRepr (M.addrWidthNatRepr (archWidthRepr ctx)) empty :> widthTypeRepr ptrRepr
:> memReprToCrucible repr :> memReprToCrucible repr
handleIdRetType :: HandleId arch '(args, ret) handleIdRetType :: HandleId arch '(args, ret)
@ -310,9 +310,6 @@ type UsedHandleSet arch = MapF (HandleId arch) HandleVal
-- | A Crucible value with a Macaw type. -- | A Crucible value with a Macaw type.
data MacawCrucibleValue f tp = MacawCrucibleValue (f (ToCrucibleType tp)) data MacawCrucibleValue f tp = MacawCrucibleValue (f (ToCrucibleType tp))
-- | Map from block indices to the associated crucible block.
type CrucSeenBlockMap s arch = Map Word64 (CR.Block s (MacawFunctionResult arch))
------------------------------------------------------------------------ ------------------------------------------------------------------------
-- CrucPersistentState -- CrucPersistentState
@ -325,8 +322,6 @@ data CrucPersistentState arch ids s
-- ^ Counter used to get fresh indices for Crucible atoms. -- ^ Counter used to get fresh indices for Crucible atoms.
, assignValueMap :: !(MapF (M.AssignId ids) (MacawCrucibleValue (CR.Atom s))) , assignValueMap :: !(MapF (M.AssignId ids) (MacawCrucibleValue (CR.Atom 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
} }
-- | Initial crucible persistent state -- | Initial crucible persistent state
@ -339,11 +334,7 @@ initCrucPersistentState =
{ handleMap = MapF.empty { handleMap = MapF.empty
, valueCount = sizeInt argCount , valueCount = sizeInt argCount
, assignValueMap = MapF.empty , assignValueMap = MapF.empty
, seenBlockMap = Map.empty
} }
handleMapLens :: Simple Lens (CrucPersistentState arch ids s) (UsedHandleSet arch) handleMapLens :: Simple Lens (CrucPersistentState arch ids s) (UsedHandleSet arch)
handleMapLens = lens handleMap (\s v -> s { handleMap = v }) handleMapLens = lens handleMap (\s v -> s { handleMap = v })
seenBlockMapLens :: Simple Lens (CrucPersistentState arch ids s) (CrucSeenBlockMap s arch)
seenBlockMapLens = lens seenBlockMap (\s v -> s { seenBlockMap = v })