From 41a3b7e00e9e3e070c30e9e3b2ce89341c35d8c0 Mon Sep 17 00:00:00 2001 From: Langston Barrett Date: Thu, 25 Apr 2024 16:32:12 -0400 Subject: [PATCH 1/3] llvm: Refactor and document binding functions Binding functions (whether they be translated CFGs or overrides) in the LLVM memory model is a bit more complex than in other frontends. We had organically grown a number of helpers that take care of various parts of this process, without actually documenting what needs to happen for everything to work as expected. This commit collects those helpers into a single module, with a top-level comment that outlines the whole process. Along the way, it removes some superfluous helpers (`bindLLVMFunPtr`) and introduces some new ones (`bindLLVMCFG`). --- crucible-llvm/crucible-llvm.cabal | 1 + crucible-llvm/src/Lang/Crucible/LLVM.hs | 18 +- .../src/Lang/Crucible/LLVM/Functions.hs | 254 ++++++++++++++++++ .../src/Lang/Crucible/LLVM/Globals.hs | 52 +--- .../Lang/Crucible/LLVM/Intrinsics/Common.hs | 43 +-- .../src/Lang/Crucible/LLVM/MemModel.hs | 30 +-- 6 files changed, 279 insertions(+), 119 deletions(-) create mode 100644 crucible-llvm/src/Lang/Crucible/LLVM/Functions.hs diff --git a/crucible-llvm/crucible-llvm.cabal b/crucible-llvm/crucible-llvm.cabal index 47b34dd5e..e25e1f5ac 100644 --- a/crucible-llvm/crucible-llvm.cabal +++ b/crucible-llvm/crucible-llvm.cabal @@ -71,6 +71,7 @@ library Lang.Crucible.LLVM.Errors.UndefinedBehavior Lang.Crucible.LLVM.Eval Lang.Crucible.LLVM.Extension + Lang.Crucible.LLVM.Functions Lang.Crucible.LLVM.Globals Lang.Crucible.LLVM.Intrinsics Lang.Crucible.LLVM.Intrinsics.Cast diff --git a/crucible-llvm/src/Lang/Crucible/LLVM.hs b/crucible-llvm/src/Lang/Crucible/LLVM.hs index c3275534c..2391be7d2 100644 --- a/crucible-llvm/src/Lang/Crucible/LLVM.hs +++ b/crucible-llvm/src/Lang/Crucible/LLVM.hs @@ -40,6 +40,7 @@ import Lang.Crucible.FunctionHandle import Lang.Crucible.LLVM.Eval (llvmExtensionEval) import Lang.Crucible.Panic (panic) import Lang.Crucible.LLVM.Extension (ArchWidth) +import Lang.Crucible.LLVM.Functions (bindLLVMHandle, bindLLVMCFG) import Lang.Crucible.LLVM.Intrinsics import Lang.Crucible.LLVM.MemModel ( llvmStatementExec, HasPtrWidth, HasLLVMAnn, MemOptions, MemImpl @@ -84,13 +85,12 @@ registerModuleFn handleWarning mtrans sym = , show sym ] Just (decl, AnyCFG cfg, warns) -> do - let h = cfgHandle cfg - s = UseCFG cfg (postdomInfo cfg) - binds <- use (stateContext . functionBindings) let llvmCtx = mtrans ^. transContext let mvar = llvmMemVar llvmCtx - bind_llvm_handle mvar (L.decName decl) h s + bindLLVMCFG mvar (L.decName decl) cfg + binds <- use (stateContext . functionBindings) + let h = cfgHandle cfg when (isJust $ lookupHandleMap h $ fnBindings binds) $ do loc <- liftIO . getCurrentProgramLoc =<< getSymInterface liftIO (handleWarning (LLVMTranslationWarning sym (plSourceLoc loc) "LLVM function handle registered twice")) @@ -128,7 +128,9 @@ registerLazyModuleFn handleWarning mtrans sym = , show sym ] Just (decl, SomeHandle h) -> - do -- Bind the function handle we just created to the following bootstrapping code, + do let llvmCtx = mtrans ^. transContext + let mvar = llvmMemVar llvmCtx + -- Bind the function handle we just created to the following bootstrapping code, -- which actually translates the function on its first execution and patches up -- behind itself. let s = @@ -151,15 +153,13 @@ registerLazyModuleFn handleWarning mtrans sym = Just Refl -> do liftIO $ mapM_ handleWarning warns -- Here we rebind the function handle to use the translated CFG - bindFnHandle h (UseCFG cfg (postdomInfo cfg)) + bindLLVMHandle mvar (L.decName decl) h (UseCFG cfg (postdomInfo cfg)) -- Now, make recursive call to ourself, which should invoke the -- newly-installed CFG regValue <$> (callFnVal (HandleFnVal h) =<< getOverrideArgs) -- Bind the function handle to the appropriate global symbol. - let llvmCtx = mtrans ^. transContext - let mvar = llvmMemVar llvmCtx - bind_llvm_handle mvar (L.decName decl) h s + bindLLVMHandle mvar (L.decName decl) h s llvmGlobalsToCtx diff --git a/crucible-llvm/src/Lang/Crucible/LLVM/Functions.hs b/crucible-llvm/src/Lang/Crucible/LLVM/Functions.hs new file mode 100644 index 000000000..9b16b4506 --- /dev/null +++ b/crucible-llvm/src/Lang/Crucible/LLVM/Functions.hs @@ -0,0 +1,254 @@ +-- | +-- Module : Lang.Crucible.LLVM.Functions +-- Description : Register functions (CFGs and overrides) +-- Copyright : (c) Galois, Inc 2024 +-- License : BSD3 +-- Maintainer : Langston Barrett +-- Stability : provisional +-- +-- Registering functions to be used with the LLVM memory model is somewhat more +-- complex than for other Crucible frontends, as LLVM has a notion of function +-- pointers. Each function to be registered has to go through a few steps (the +-- first two are common to all Crucible frontends): +-- +-- * Create a 'FnHandle' and a 'FnState' (a translated CFG or an override) +-- * Bind the 'FnHandle' to the 'FnState' ('OverrideSim.bindFnHandle') +-- * Create a (global, immutable, zero-sized) allocation coressponding to the +-- function in the 'MemImpl' ('allocFunPtr') +-- * Register the correspondence between the function\'s name (and any aliases) +-- and its global allocation ('registerGlobal', or via 'registerFunPtr') +-- * Register the correspondence between the function\'s allocation and its +-- handle ('doInstallHandle', or via 'bindLLVMHandle', 'bindLLVMCFG', or +-- 'bindLLVMFunc') +-- +-- This module provides helpers to accomplish all of this. They\'re ordered +-- roughly low-level/customizable to high-level/automated. +-- +-- Perhaps surprisingly, there\'s no function that does all of the above at +-- once. This is because there are two main places where binding functions +-- happens: +-- +-- * "Lang.Crucible.LLVM" registers translated CFGs, but does so lazily. In +-- particular, this means that it initially binds the handle and allocation to +-- a \"stub\" that, when called, will translate the actual CFG and then +-- re-bind the handle and allocation to it. +-- * "Lang.Crucible.LLVM.Intrinsics.Common" registers overrides, which generally +-- apply to functions that are @declare@d but not @define@d. Thus, they +-- already have corresponding allocations, which just need to be associated +-- with the override. +-- +-- Prior to these, function allocation happens in +-- 'Lang.Crucible.LLVM.Globals.initializeMemory'. +------------------------------------------------------------------------ + +{-# LANGUAGE GADTs #-} +{-# LANGUAGE ImplicitParams #-} + +module Lang.Crucible.LLVM.Functions + ( allocFunPtr + , allocLLVMFunPtr + , allocLLVMFunPtrs + , registerFunPtr + , bindLLVMHandle + , bindLLVMCFG + , bindLLVMFunc + ) where + +import Control.Lens (use) +import Control.Monad (foldM) +import Control.Monad.IO.Class (liftIO) +import qualified Data.Map as Map +import qualified Data.Set as Set +import qualified Data.Text as Text + +import qualified Text.LLVM.AST as L + +import qualified Data.Parameterized.Context as Ctx + +import What4.FunctionName (functionNameFromText) +import qualified What4.Interface as W4 + +import Lang.Crucible.Analysis.Postdom (postdomInfo) +import Lang.Crucible.Backend +import Lang.Crucible.CFG.Common (GlobalVar) +import Lang.Crucible.CFG.Core (CFG) +import Lang.Crucible.CFG.Core (TypeRepr(..), cfgHandle) +import Lang.Crucible.FunctionHandle (FnHandle(handleArgTypes), mkHandle') +import Lang.Crucible.Simulator.ExecutionTree (stateContext) +import Lang.Crucible.Simulator (FnState(..), SimContext(..)) +import Lang.Crucible.Simulator.OverrideSim (OverrideSim) +import qualified Lang.Crucible.Simulator.OverrideSim as OverrideSim + +import Lang.Crucible.LLVM.DataLayout +import Lang.Crucible.LLVM.MemModel +import qualified Lang.Crucible.LLVM.MemModel as G +import Lang.Crucible.LLVM.Translation.Monad +import Lang.Crucible.LLVM.Extension (LLVM) + +-- | Create a global allocation to be assocated with a function. +-- +-- The returned allocation is global ('G.GlobalAlloc'), immutable +-- ('G.Immutable'), and has a size and alignment of zero. +allocFunPtr :: + ( IsSymBackend sym bak, HasPtrWidth wptr, HasLLVMAnn sym + , ?memOpts :: MemOptions ) => + bak -> + MemImpl sym -> + -- | Function Name + String -> + IO (LLVMPtr sym wptr, MemImpl sym) +allocFunPtr bak mem nm = do + let sym = backendGetSym bak + z <- W4.bvZero sym ?ptrWidth + doMalloc bak G.GlobalAlloc G.Immutable nm mem z noAlignment + +-- | Create a global allocation assocated with a function (see 'allocFunPtr'), +-- and register the function\'s primary symbol and its aliases as associated +-- with that allocation. +registerFunPtr :: + ( IsSymBackend sym bak, HasPtrWidth wptr, HasLLVMAnn sym + , ?memOpts :: MemOptions ) => + bak -> + MemImpl sym -> + -- | Display name + String -> + -- | Function name + L.Symbol -> + -- | Aliases + [L.Symbol] -> + IO (LLVMPtr sym wptr, MemImpl sym) +registerFunPtr bak mem displayName nm aliases = do + (ptr, mem') <- allocFunPtr bak mem displayName + return $ (ptr, registerGlobal mem' (nm:aliases) ptr) + +-- Not exported +funAliases :: + LLVMContext arch -> + L.Symbol -> + [L.Symbol] +funAliases llvmCtx symbol = + let aliases = llvmFunctionAliases llvmCtx + in map L.aliasName $ maybe [] Set.toList $ Map.lookup symbol aliases + +-- | Create a global allocation assocated with a function (see 'allocFunPtr'), +-- register the function\'s primary symbol and its aliases as associated with +-- that allocation (see 'registerFunPtr'), looking up the aliases from the +-- 'LLVMContext'. +allocLLVMFunPtr :: + ( IsSymBackend sym bak, HasPtrWidth wptr, HasLLVMAnn sym + , ?memOpts :: MemOptions ) => + bak -> + LLVMContext arch -> + MemImpl sym -> + Either L.Declare L.Define -> + IO (LLVMPtr sym wptr, MemImpl sym) +allocLLVMFunPtr bak llvm_ctx mem decl = do + let (symbol, displayString) = + case decl of + Left d -> + let s@(L.Symbol nm) = L.decName d + in ( s, "[external function] " ++ nm ) + Right d -> + let s@(L.Symbol nm) = L.defName d + in ( s, "[defined function ] " ++ nm) + let aliases = funAliases llvm_ctx symbol + registerFunPtr bak mem displayString symbol aliases + +-- | Create global allocations associated with each function in a module (see +-- 'allocLLVMFunPtr'). +allocLLVMFunPtrs :: + ( IsSymBackend sym bak, HasPtrWidth wptr, HasLLVMAnn sym + , ?memOpts :: MemOptions ) => + bak -> + LLVMContext arch -> + MemImpl sym -> + L.Module -> + IO (MemImpl sym) +allocLLVMFunPtrs bak llvmCtx mem0 llvmMod = do + -- allocate pointers values for function symbols, but do not + -- yet bind them to function handles + let decls = map Left (L.modDeclares llvmMod) ++ map Right (L.modDefines llvmMod) + + let allocLLVMFunPtr' bak' lctx mem decl = snd <$> allocLLVMFunPtr bak' lctx mem decl + foldM (allocLLVMFunPtr' bak llvmCtx) mem0 decls + +-- Not exported +someFnHandle :: FnHandle args ret -> SomeFnHandle +someFnHandle h = + case handleArgTypes h of + (_ Ctx.:> VectorRepr AnyRepr) -> VarargsFnHandle h + _ -> SomeFnHandle h + +-- | Look up an existing global function allocation by name and bind a handle +-- to it. +-- +-- This can overwrite existing allocation/handle associations, and is used to do +-- so when registering lazily-translated CFGs. +bindLLVMHandle :: + (IsSymInterface sym, HasPtrWidth wptr) => + GlobalVar Mem -> + -- | Function name + L.Symbol -> + -- | Function handle + FnHandle args ret -> + -- | Function implementation (CFG or override) + FnState p sym ext args ret -> + OverrideSim p sym ext rtp l a () +bindLLVMHandle mvar nm hdl impl = do + OverrideSim.bindFnHandle hdl impl + mem <- OverrideSim.readGlobal mvar + mem' <- OverrideSim.ovrWithBackend $ \bak -> do + ptr <- liftIO (doResolveGlobal bak mem nm) + liftIO $ doInstallHandle bak ptr (someFnHandle hdl) mem + OverrideSim.writeGlobal mvar mem' + +-- | Look up an existing global function allocation by name and bind a CFG to +-- it. +-- +-- This can overwrite existing allocation/handle associations, and is used to do +-- so when registering lazily-translated CFGs. +bindLLVMCFG :: + (IsSymInterface sym, HasPtrWidth wptr) => + GlobalVar Mem -> + -- | Function name + L.Symbol -> + -- | Function CFG + CFG LLVM blocks init ret -> + OverrideSim p sym LLVM rtp l a () +bindLLVMCFG mvar name cfg = do + let h = cfgHandle cfg + s = UseCFG cfg (postdomInfo cfg) + bindLLVMHandle mvar name h s + +-- Private helper to make function handles +mkHandle :: + -- | Function name + L.Symbol -> + -- | Argument types + Ctx.Assignment TypeRepr args -> + -- | Return type + TypeRepr ret -> + OverrideSim p sym ext rtp l a (FnHandle args ret) +mkHandle nm args ret = do + let L.Symbol strNm = nm + let fnm = functionNameFromText (Text.pack strNm) + ctx <- use stateContext + let ha = simHandleAllocator ctx + liftIO $ mkHandle' ha fnm args ret + +-- | Create a function handle, then call 'bindLLVMHandle' on it. +bindLLVMFunc :: + (IsSymInterface sym, HasPtrWidth wptr) => + GlobalVar Mem -> + -- | Function name + L.Symbol -> + -- | Argument types + Ctx.Assignment TypeRepr args -> + -- | Return type + TypeRepr ret -> + -- | Function implementation (CFG or override) + FnState p sym ext args ret -> + OverrideSim p sym ext rtp l a () +bindLLVMFunc mvar nm args ret impl = do + hdl <- mkHandle nm args ret + bindLLVMHandle mvar nm hdl impl diff --git a/crucible-llvm/src/Lang/Crucible/LLVM/Globals.hs b/crucible-llvm/src/Lang/Crucible/LLVM/Globals.hs index 433b06c30..a978cbb98 100644 --- a/crucible-llvm/src/Lang/Crucible/LLVM/Globals.hs +++ b/crucible-llvm/src/Lang/Crucible/LLVM/Globals.hs @@ -36,7 +36,6 @@ module Lang.Crucible.LLVM.Globals , populateGlobals , populateAllGlobals , populateConstGlobals - , registerFunPtr , GlobalInitializerMap , makeGlobalMap @@ -58,14 +57,13 @@ import qualified Data.Parameterized.Context as Ctx import qualified Text.LLVM.AST as L -import qualified Data.BitVector.Sized as BV import Data.Parameterized.NatRepr as NatRepr import Lang.Crucible.LLVM.Bytes import Lang.Crucible.LLVM.DataLayout +import Lang.Crucible.LLVM.Functions (allocLLVMFunPtrs) import Lang.Crucible.LLVM.MemType import Lang.Crucible.LLVM.MemModel -import qualified Lang.Crucible.LLVM.MemModel.Generic as G import qualified Lang.Crucible.LLVM.PrettyPrint as LPP import Lang.Crucible.LLVM.Translation.Constant import Lang.Crucible.LLVM.Translation.Monad @@ -182,10 +180,9 @@ initializeMemory predicate bak llvm_ctx llvmModl = do let endianness = dl^.intLayout mem0 <- emptyMem endianness - -- allocate pointers values for function symbols, but do not - -- yet bind them to function handles - let decls = map Left (L.modDeclares llvmModl) ++ map Right (L.modDefines llvmModl) - mem <- foldM (allocLLVMFunPtr bak llvm_ctx) mem0 decls + -- allocate pointers values for function symbols, but do not yet bind them to + -- function handles + mem <- allocLLVMFunPtrs bak llvm_ctx mem0 llvmModl -- Allocate global values let globAliases = llvmGlobalAliases llvm_ctx @@ -222,47 +219,6 @@ initializeMemory predicate bak llvm_ctx llvmModl = do allocGlobals bak (filter (\(g, _, _, _) -> predicate g) gs_alloc) mem -allocLLVMFunPtr :: - ( IsSymBackend sym bak, HasPtrWidth wptr, HasLLVMAnn sym - , ?memOpts :: MemOptions ) => - bak -> - LLVMContext arch -> - MemImpl sym -> - Either L.Declare L.Define -> - IO (MemImpl sym) -allocLLVMFunPtr bak llvm_ctx mem decl = - do let (symbol, displayString) = - case decl of - Left d -> - let s@(L.Symbol nm) = L.decName d - in ( s, "[external function] " ++ nm ) - Right d -> - let s@(L.Symbol nm) = L.defName d - in ( s, "[defined function ] " ++ nm) - let funAliases = llvmFunctionAliases llvm_ctx - let aliases = map L.aliasName $ maybe [] Set.toList $ Map.lookup symbol funAliases - (_ptr, mem') <- registerFunPtr bak mem displayString symbol aliases - return mem' - --- | Create a global allocation assocated with a function -registerFunPtr :: - ( IsSymBackend sym bak, HasPtrWidth wptr, HasLLVMAnn sym - , ?memOpts :: MemOptions ) => - bak -> - MemImpl sym -> - -- | Display name - String -> - -- | Function name - L.Symbol -> - -- | Aliases - [L.Symbol] -> - IO (LLVMPtr sym wptr, MemImpl sym) -registerFunPtr bak mem displayName nm aliases = do - let sym = backendGetSym bak - z <- bvZero sym ?ptrWidth - (ptr, mem') <- doMalloc bak G.GlobalAlloc G.Immutable displayName mem z noAlignment - return $ (ptr, registerGlobal mem' (nm:aliases) ptr) - ------------------------------------------------------------------------ -- ** populateGlobals diff --git a/crucible-llvm/src/Lang/Crucible/LLVM/Intrinsics/Common.hs b/crucible-llvm/src/Lang/Crucible/LLVM/Intrinsics/Common.hs index 1113632a4..3225c594f 100644 --- a/crucible-llvm/src/Lang/Crucible/LLVM/Intrinsics/Common.hs +++ b/crucible-llvm/src/Lang/Crucible/LLVM/Intrinsics/Common.hs @@ -32,8 +32,6 @@ module Lang.Crucible.LLVM.Intrinsics.Common , build_llvm_override , register_llvm_override , register_1arg_polymorphic_override - , bind_llvm_handle - , bind_llvm_func , do_register_llvm_override , alloc_and_register_override ) where @@ -55,9 +53,7 @@ import Data.Parameterized.Some (Some(..)) import Lang.Crucible.Backend import Lang.Crucible.CFG.Common (GlobalVar) import Lang.Crucible.Simulator.ExecutionTree (FnState(UseOverride)) -import Lang.Crucible.FunctionHandle (FnHandle, mkHandle') import Lang.Crucible.Panic (panic) -import Lang.Crucible.Simulator (stateContext, simHandleAllocator) import Lang.Crucible.Simulator.OverrideSim import Lang.Crucible.Utils.MonadVerbosity (getLogFunction) import Lang.Crucible.Simulator.RegMap @@ -67,7 +63,7 @@ import What4.FunctionName import Lang.Crucible.LLVM.Extension import Lang.Crucible.LLVM.Eval (callStackFromMemVar) -import Lang.Crucible.LLVM.Globals (registerFunPtr) +import Lang.Crucible.LLVM.Functions (registerFunPtr, bindLLVMFunc) import Lang.Crucible.LLVM.MemModel import Lang.Crucible.LLVM.MemModel.CallStack (CallStack) import qualified Lang.Crucible.LLVM.Intrinsics.Cast as Cast @@ -270,41 +266,6 @@ register_llvm_override llvmOverride requestedDecl llvmctx = do ] else do_register_llvm_override llvmctx llvmOverride --- | Bind a function handle, and also bind the function to the global function --- allocation in the LLVM memory. -bind_llvm_handle :: - (IsSymInterface sym, HasPtrWidth wptr) => - GlobalVar Mem -> - L.Symbol -> - FnHandle args ret -> - FnState p sym ext args ret -> - OverrideSim p sym ext rtp l a () -bind_llvm_handle mvar nm hdl impl = do - bindFnHandle hdl impl - mem <- readGlobal mvar - mem' <- ovrWithBackend $ \bak -> liftIO $ bindLLVMFunPtr bak nm hdl mem - writeGlobal mvar mem' - --- | Low-level function to register LLVM functions. --- --- Creates and binds a function handle, and also binds the function to the --- global function allocation in the LLVM memory. -bind_llvm_func :: - (IsSymInterface sym, HasPtrWidth wptr) => - GlobalVar Mem -> - L.Symbol -> - Ctx.Assignment TypeRepr args -> - TypeRepr ret -> - FnState p sym ext args ret -> - OverrideSim p sym ext rtp l a () -bind_llvm_func mvar nm args ret impl = do - let L.Symbol strNm = nm - let fnm = functionNameFromText (Text.pack strNm) - ctx <- use stateContext - let ha = simHandleAllocator ctx - h <- liftIO $ mkHandle' ha fnm args ret - bind_llvm_handle mvar nm h impl - -- | Low-level function to register LLVM overrides. -- -- Type-checks the LLVM override against the 'L.Declare' it contains, adapting @@ -334,7 +295,7 @@ do_register_llvm_override llvmctx llvmOverride = do llvmDeclToFunHandleRepr' decl $ \args ret -> do o <- build_llvm_override fnm overrideArgs overrideRet args ret (\asgn -> llvmOverride_def llvmOverride mvar asgn) - bind_llvm_func mvar (L.decName decl) args ret (UseOverride o) + bindLLVMFunc mvar (L.decName decl) args ret (UseOverride o) -- | Create an allocation for an override and register it. -- diff --git a/crucible-llvm/src/Lang/Crucible/LLVM/MemModel.hs b/crucible-llvm/src/Lang/Crucible/LLVM/MemModel.hs index ff73594c7..e1f878902 100644 --- a/crucible-llvm/src/Lang/Crucible/LLVM/MemModel.hs +++ b/crucible-llvm/src/Lang/Crucible/LLVM/MemModel.hs @@ -87,7 +87,6 @@ module Lang.Crucible.LLVM.MemModel , loadMaybeString , strLen , uncheckedMemcpy - , bindLLVMFunPtr -- * \"Raw\" operations with LLVMVal , LLVMVal(..) @@ -720,25 +719,12 @@ doMallocSize sz bak allocType mut loc mem alignment = do else pure mem' return (ptr, mem'') - - -bindLLVMFunPtr :: - (IsSymBackend sym bak, HasPtrWidth wptr) => - bak -> - L.Symbol -> - FnHandle args ret -> - MemImpl sym -> - IO (MemImpl sym) -bindLLVMFunPtr bak nm h mem - | (_ Ctx.:> VectorRepr AnyRepr) <- handleArgTypes h - - = do ptr <- doResolveGlobal bak mem nm - doInstallHandle bak ptr (VarargsFnHandle h) mem - - | otherwise - = do ptr <- doResolveGlobal bak mem nm - doInstallHandle bak ptr (SomeFnHandle h) mem - +-- | Associate a function handle with an existing allocation. +-- +-- This can overwrite existing allocation/handle associations, and is used to do +-- so when registering lazily-translated CFGs. +-- +-- See also "Lang.Crucible.LLVM.Functions". doInstallHandle :: (Typeable a, IsSymBackend sym bak) => bak @@ -758,7 +744,9 @@ doInstallHandle _bak ptr x mem = ] -- | Allocate a memory region for the given handle. -doMallocHandle +-- +-- See also "Lang.Crucible.LLVM.Functions". +doMallocHandle -- TODO(lb): unused, delete? :: (Typeable a, IsSymInterface sym, HasPtrWidth wptr) => sym -> G.AllocType {- ^ stack, heap, or global -} From 20504dcbdd5bed05fcc3b0ae61af5cb08353422e Mon Sep 17 00:00:00 2001 From: Langston Barrett Date: Fri, 26 Apr 2024 09:55:47 -0400 Subject: [PATCH 2/3] llvm: Respond to review comments --- crucible-llvm/CHANGELOG.md | 4 ++++ .../src/Lang/Crucible/LLVM/Functions.hs | 7 +++--- .../src/Lang/Crucible/LLVM/MemModel.hs | 22 ------------------- 3 files changed, 8 insertions(+), 25 deletions(-) diff --git a/crucible-llvm/CHANGELOG.md b/crucible-llvm/CHANGELOG.md index 79635a25e..a3e48e0af 100644 --- a/crucible-llvm/CHANGELOG.md +++ b/crucible-llvm/CHANGELOG.md @@ -1,5 +1,9 @@ # next +* The `doMallocHandle` function was removed. +* The `bindLLVMFunPtr` function was removed, instead use `doResolveGlobal` + to resolve a global symbol to a pointer, `someFnHandle` to construct a + `SomeFnHandle`, and pass both to `doInstallHandle`. * The `RegOverrideM` monad was replaced by the `MakeOverride` function newtype. * Several type parameters were removed from `OverrideTemplate`, and the `ext` parameter was added. This had downstream effects in `basic_llvm_override`, diff --git a/crucible-llvm/src/Lang/Crucible/LLVM/Functions.hs b/crucible-llvm/src/Lang/Crucible/LLVM/Functions.hs index 9b16b4506..efe994225 100644 --- a/crucible-llvm/src/Lang/Crucible/LLVM/Functions.hs +++ b/crucible-llvm/src/Lang/Crucible/LLVM/Functions.hs @@ -13,7 +13,7 @@ -- -- * Create a 'FnHandle' and a 'FnState' (a translated CFG or an override) -- * Bind the 'FnHandle' to the 'FnState' ('OverrideSim.bindFnHandle') --- * Create a (global, immutable, zero-sized) allocation coressponding to the +-- * Create a (global, immutable, zero-sized) allocation corresponding to the -- function in the 'MemImpl' ('allocFunPtr') -- * Register the correspondence between the function\'s name (and any aliases) -- and its global allocation ('registerGlobal', or via 'registerFunPtr') @@ -49,6 +49,7 @@ module Lang.Crucible.LLVM.Functions , allocLLVMFunPtr , allocLLVMFunPtrs , registerFunPtr + , someFnHandle , bindLLVMHandle , bindLLVMCFG , bindLLVMFunc @@ -172,7 +173,7 @@ allocLLVMFunPtrs bak llvmCtx mem0 llvmMod = do let allocLLVMFunPtr' bak' lctx mem decl = snd <$> allocLLVMFunPtr bak' lctx mem decl foldM (allocLLVMFunPtr' bak llvmCtx) mem0 decls --- Not exported +-- | Turn a 'FnHandle' into a 'SomeFnHandle', for use with 'doInstallHandle'. someFnHandle :: FnHandle args ret -> SomeFnHandle someFnHandle h = case handleArgTypes h of @@ -228,7 +229,7 @@ mkHandle :: Ctx.Assignment TypeRepr args -> -- | Return type TypeRepr ret -> - OverrideSim p sym ext rtp l a (FnHandle args ret) + OverrideSim p sym ext rtp l a (FnHandle args ret) mkHandle nm args ret = do let L.Symbol strNm = nm let fnm = functionNameFromText (Text.pack strNm) diff --git a/crucible-llvm/src/Lang/Crucible/LLVM/MemModel.hs b/crucible-llvm/src/Lang/Crucible/LLVM/MemModel.hs index e1f878902..c271ff16f 100644 --- a/crucible-llvm/src/Lang/Crucible/LLVM/MemModel.hs +++ b/crucible-llvm/src/Lang/Crucible/LLVM/MemModel.hs @@ -66,7 +66,6 @@ module Lang.Crucible.LLVM.MemModel , doMallocUnbounded , G.AllocType(..) , G.Mutability(..) - , doMallocHandle , ME.FuncLookupError(..) , ME.ppFuncLookupError , doLookupHandle @@ -743,27 +742,6 @@ doInstallHandle _bak ptr x mem = , " " ++ show (ppPtr ptr) ] --- | Allocate a memory region for the given handle. --- --- See also "Lang.Crucible.LLVM.Functions". -doMallocHandle -- TODO(lb): unused, delete? - :: (Typeable a, IsSymInterface sym, HasPtrWidth wptr) - => sym - -> G.AllocType {- ^ stack, heap, or global -} - -> String {- ^ source location for use in error messages -} - -> MemImpl sym - -> a {- ^ handle -} - -> IO (LLVMPtr sym wptr, MemImpl sym) -doMallocHandle sym allocType loc mem x = do - blkNum <- nextBlock (memImplBlockSource mem) - blk <- natLit sym blkNum - z <- bvZero sym PtrWidth - - let heap' = G.allocMem allocType blkNum (Just z) noAlignment G.Immutable loc (memImplHeap mem) - let hMap' = Map.insert blkNum (toDyn x) (memImplHandleMap mem) - let ptr = LLVMPointer blk z - return (ptr, mem{ memImplHeap = heap', memImplHandleMap = hMap' }) - -- | Look up the handle associated with the given pointer, if any. doLookupHandle :: (Typeable a, IsSymInterface sym) From 50dcfad25bee5c119474e6ab9c0c777649bcfa41 Mon Sep 17 00:00:00 2001 From: Langston Barrett Date: Fri, 26 Apr 2024 10:23:20 -0400 Subject: [PATCH 3/3] llvm: Reinstate `bindLLVMFunPtr` --- crucible-llvm/CHANGELOG.md | 3 -- .../src/Lang/Crucible/LLVM/Functions.hs | 31 ++++++++++++++++--- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/crucible-llvm/CHANGELOG.md b/crucible-llvm/CHANGELOG.md index a3e48e0af..f5233fc0d 100644 --- a/crucible-llvm/CHANGELOG.md +++ b/crucible-llvm/CHANGELOG.md @@ -1,9 +1,6 @@ # next * The `doMallocHandle` function was removed. -* The `bindLLVMFunPtr` function was removed, instead use `doResolveGlobal` - to resolve a global symbol to a pointer, `someFnHandle` to construct a - `SomeFnHandle`, and pass both to `doInstallHandle`. * The `RegOverrideM` monad was replaced by the `MakeOverride` function newtype. * Several type parameters were removed from `OverrideTemplate`, and the `ext` parameter was added. This had downstream effects in `basic_llvm_override`, diff --git a/crucible-llvm/src/Lang/Crucible/LLVM/Functions.hs b/crucible-llvm/src/Lang/Crucible/LLVM/Functions.hs index efe994225..004678694 100644 --- a/crucible-llvm/src/Lang/Crucible/LLVM/Functions.hs +++ b/crucible-llvm/src/Lang/Crucible/LLVM/Functions.hs @@ -49,7 +49,6 @@ module Lang.Crucible.LLVM.Functions , allocLLVMFunPtr , allocLLVMFunPtrs , registerFunPtr - , someFnHandle , bindLLVMHandle , bindLLVMCFG , bindLLVMFunc @@ -173,7 +172,7 @@ allocLLVMFunPtrs bak llvmCtx mem0 llvmMod = do let allocLLVMFunPtr' bak' lctx mem decl = snd <$> allocLLVMFunPtr bak' lctx mem decl foldM (allocLLVMFunPtr' bak llvmCtx) mem0 decls --- | Turn a 'FnHandle' into a 'SomeFnHandle', for use with 'doInstallHandle'. +-- Not exported someFnHandle :: FnHandle args ret -> SomeFnHandle someFnHandle h = case handleArgTypes h of @@ -185,6 +184,29 @@ someFnHandle h = -- -- This can overwrite existing allocation/handle associations, and is used to do -- so when registering lazily-translated CFGs. +-- +-- For a stateful version in 'OverrideSim', see 'bindLLVMHandle'. +bindLLVMFunPtr :: + (IsSymBackend sym bak, HasPtrWidth wptr) => + bak -> + -- | Function name + L.Symbol -> + -- | Function implementation (CFG or override) + FnHandle args ret -> + -- | LLVM memory + MemImpl sym -> + IO (MemImpl sym) +bindLLVMFunPtr bak nm h mem = do + ptr <- doResolveGlobal bak mem nm + doInstallHandle bak ptr (someFnHandle h) mem + +-- | Look up an existing global function allocation by name and bind a handle +-- to it. +-- +-- This can overwrite existing allocation/handle associations, and is used to do +-- so when registering lazily-translated CFGs. +-- +-- For a less stateful version in 'IO', see 'bindLLVMHandle'. bindLLVMHandle :: (IsSymInterface sym, HasPtrWidth wptr) => GlobalVar Mem -> @@ -198,9 +220,8 @@ bindLLVMHandle :: bindLLVMHandle mvar nm hdl impl = do OverrideSim.bindFnHandle hdl impl mem <- OverrideSim.readGlobal mvar - mem' <- OverrideSim.ovrWithBackend $ \bak -> do - ptr <- liftIO (doResolveGlobal bak mem nm) - liftIO $ doInstallHandle bak ptr (someFnHandle hdl) mem + mem' <- OverrideSim.ovrWithBackend $ \bak -> + liftIO (bindLLVMFunPtr bak nm hdl mem) OverrideSim.writeGlobal mvar mem' -- | Look up an existing global function allocation by name and bind a CFG to