{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ImplicitParams #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
module MemSetup
(
withInitializedMemory
)
where
import Control.Lens ( (^.) )
import Data.Parameterized.NatRepr
import Data.Parameterized.Nonce
import Data.Parameterized.Some
import qualified Text.LLVM.AST as L
import qualified What4.Expr as WE
import qualified Lang.Crucible.Backend as CB
import qualified Lang.Crucible.Backend.Simple as CBS
import Lang.Crucible.FunctionHandle ( withHandleAllocator, HandleAllocator )
import qualified Lang.Crucible.LLVM.MemModel as LLVMMem
import Lang.Crucible.LLVM.TypeContext
import qualified Lang.Crucible.LLVM.Extension as LLVME
import qualified Lang.Crucible.LLVM.Globals as LLVMG
import qualified Lang.Crucible.LLVM.MemModel as LLVMM
import qualified Lang.Crucible.LLVM.Translation as LLVMTr
-- | Call 'initializeMemory' and get the result
withInitializedMemory :: forall a. L.Module
-> (forall wptr sym. ( ?lc :: TypeContext
, LLVMMem.HasPtrWidth wptr
, CB.IsSymInterface sym
, LLVMMem.HasLLVMAnn sym
, ?memOpts :: LLVMMem.MemOptions
)
=> LLVMMem.MemImpl sym
-> IO a)
-> IO a
withInitializedMemory mod' action =
withLLVMCtx mod' $ \(ctx :: LLVMTr.LLVMContext arch) sym ->
action @(LLVME.ArchWidth arch) =<< LLVMG.initializeAllMemory sym ctx mod'
-- | Create an LLVM context from a module and make some assertions about it.
withLLVMCtx :: forall a. L.Module
-> (forall arch sym bak.
( ?lc :: TypeContext
, LLVMM.HasPtrWidth (LLVME.ArchWidth arch)
, CB.IsSymBackend sym bak
, LLVMMem.HasLLVMAnn sym
, ?memOpts :: LLVMMem.MemOptions
)
=> LLVMTr.LLVMContext arch
-> bak
-> IO a)
-> IO a
withLLVMCtx mod' action =
let -- This is a separate function because we need to use the scoped type variable
-- @s@ in the binding of @sym@, which is difficult to do inline.
with :: forall s. NonceGenerator IO s -> HandleAllocator -> IO a
with nonceGen halloc = do
sym <- WE.newExprBuilder WE.FloatRealRepr WE.EmptyExprBuilderState nonceGen
bak <- CBS.newSimpleBackend sym
let ?memOpts = LLVMMem.defaultMemOptions
let ?transOpts = LLVMTr.defaultTranslationOptions
memVar <- LLVMM.mkMemVar "test_llvm_memory" halloc
Some mtrans <- LLVMTr.translateModule halloc memVar mod'
let ctx = mtrans ^. LLVMTr.transContext
case LLVMTr.llvmArch ctx of { LLVME.X86Repr width ->
case assertLeq (knownNat @1) width of { LeqProof ->
case assertLeq (knownNat @16) width of { LeqProof -> do
let ?ptrWidth = width
let ?lc = LLVMTr._llvmTypeCtx ctx
let ?recordLLVMAnnotation = \_ _ _ -> pure ()
action ctx bak
}}}
in withIONonceGenerator $ \nonceGen ->
withHandleAllocator $ \halloc -> with nonceGen halloc
assertLeq :: forall m n . NatRepr m -> NatRepr n -> LeqProof m n
assertLeq m n =
case testLeq m n of
Just LeqProof -> LeqProof
Nothing -> error $ "No LeqProof for " ++ show m ++ " and " ++ show n