packages feed

crucible 0.9 → 0.10

raw patch · 55 files changed

+1479/−1157 lines, 55 filesdep +microlensdep +microlens-mtldep +microlens-thdep −lensdep ~basedep ~parameterized-utilsdep ~th-abstractionPVP ok

version bump matches the API change (PVP)

Dependencies added: microlens, microlens-mtl, microlens-th

Dependencies removed: lens

Dependency ranges changed: base, parameterized-utils, th-abstraction

API changes (from Hackage documentation)

- Lang.Crucible.Analysis.ForwardDataflow: Concrete :: SymDom
- Lang.Crucible.Analysis.ForwardDataflow: Dead :: SymDom
- Lang.Crucible.Analysis.ForwardDataflow: Ignore :: a -> Ignore a (b :: k)
- Lang.Crucible.Analysis.ForwardDataflow: KP :: a tp -> c -> KildallPair (a :: k -> Type) c (tp :: k)
- Lang.Crucible.Analysis.ForwardDataflow: KildallForward :: (forall (tp :: CrucibleType). () => a tp -> a tp -> a tp) -> (forall (tp :: CrucibleType). () => a tp) -> (c -> c -> c) -> c -> (forall (tp :: CrucibleType). () => a tp -> a tp -> Bool) -> (c -> c -> Bool) -> (forall (ctx :: Ctx CrucibleType). () => Reg ctx BoolType -> a BoolType -> c -> (c, c)) -> (forall (ctx :: Ctx CrucibleType) (tp :: CrucibleType). () => TypeRepr tp -> Reg ctx (MaybeType tp) -> a (MaybeType tp) -> c -> (c, a tp, c)) -> !forall (ctx :: Ctx CrucibleType) (tp :: CrucibleType). () => TypeRepr tp -> Reg ctx tp -> Assignment a ctx -> a tp -> !forall (ctx :: Ctx CrucibleType) (tp :: CrucibleType). () => TypeRepr tp -> Expr ext ctx tp -> Assignment a ctx -> a tp -> (forall (ctx :: Ctx CrucibleType) (args :: Ctx CrucibleType) (ret :: CrucibleType). () => CtxRepr args -> TypeRepr ret -> Reg ctx (FunctionHandleType args ret) -> a (FunctionHandleType args ret) -> Assignment a args -> a ret) -> (forall (tp :: CrucibleType). () => GlobalVar tp -> a tp) -> (forall (ctx :: Ctx CrucibleType). () => BlockID blocks ctx -> (Assignment a ctx, c) -> (Assignment a ctx, c)) -> KildallForward ext (blocks :: Ctx (Ctx CrucibleType)) (a :: CrucibleType -> Type) c
- Lang.Crucible.Analysis.ForwardDataflow: Symbolic :: SymDom
- Lang.Crucible.Analysis.ForwardDataflow: [ignoreOut] :: Ignore a (b :: k) -> a
- Lang.Crucible.Analysis.ForwardDataflow: [kfwd_bot] :: KildallForward ext (blocks :: Ctx (Ctx CrucibleType)) (a :: CrucibleType -> Type) c -> forall (tp :: CrucibleType). () => a tp
- Lang.Crucible.Analysis.ForwardDataflow: [kfwd_br] :: KildallForward ext (blocks :: Ctx (Ctx CrucibleType)) (a :: CrucibleType -> Type) c -> forall (ctx :: Ctx CrucibleType). () => Reg ctx BoolType -> a BoolType -> c -> (c, c)
- Lang.Crucible.Analysis.ForwardDataflow: [kfwd_call] :: KildallForward ext (blocks :: Ctx (Ctx CrucibleType)) (a :: CrucibleType -> Type) c -> forall (ctx :: Ctx CrucibleType) (args :: Ctx CrucibleType) (ret :: CrucibleType). () => CtxRepr args -> TypeRepr ret -> Reg ctx (FunctionHandleType args ret) -> a (FunctionHandleType args ret) -> Assignment a args -> a ret
- Lang.Crucible.Analysis.ForwardDataflow: [kfwd_cbot] :: KildallForward ext (blocks :: Ctx (Ctx CrucibleType)) (a :: CrucibleType -> Type) c -> c
- Lang.Crucible.Analysis.ForwardDataflow: [kfwd_club] :: KildallForward ext (blocks :: Ctx (Ctx CrucibleType)) (a :: CrucibleType -> Type) c -> c -> c -> c
- Lang.Crucible.Analysis.ForwardDataflow: [kfwd_csame] :: KildallForward ext (blocks :: Ctx (Ctx CrucibleType)) (a :: CrucibleType -> Type) c -> c -> c -> Bool
- Lang.Crucible.Analysis.ForwardDataflow: [kfwd_expr] :: KildallForward ext (blocks :: Ctx (Ctx CrucibleType)) (a :: CrucibleType -> Type) c -> !forall (ctx :: Ctx CrucibleType) (tp :: CrucibleType). () => TypeRepr tp -> Expr ext ctx tp -> Assignment a ctx -> a tp
- Lang.Crucible.Analysis.ForwardDataflow: [kfwd_lub] :: KildallForward ext (blocks :: Ctx (Ctx CrucibleType)) (a :: CrucibleType -> Type) c -> forall (tp :: CrucibleType). () => a tp -> a tp -> a tp
- Lang.Crucible.Analysis.ForwardDataflow: [kfwd_maybe] :: KildallForward ext (blocks :: Ctx (Ctx CrucibleType)) (a :: CrucibleType -> Type) c -> forall (ctx :: Ctx CrucibleType) (tp :: CrucibleType). () => TypeRepr tp -> Reg ctx (MaybeType tp) -> a (MaybeType tp) -> c -> (c, a tp, c)
- Lang.Crucible.Analysis.ForwardDataflow: [kfwd_onentry] :: KildallForward ext (blocks :: Ctx (Ctx CrucibleType)) (a :: CrucibleType -> Type) c -> forall (ctx :: Ctx CrucibleType). () => BlockID blocks ctx -> (Assignment a ctx, c) -> (Assignment a ctx, c)
- Lang.Crucible.Analysis.ForwardDataflow: [kfwd_rdglobal] :: KildallForward ext (blocks :: Ctx (Ctx CrucibleType)) (a :: CrucibleType -> Type) c -> forall (tp :: CrucibleType). () => GlobalVar tp -> a tp
- Lang.Crucible.Analysis.ForwardDataflow: [kfwd_reg] :: KildallForward ext (blocks :: Ctx (Ctx CrucibleType)) (a :: CrucibleType -> Type) c -> !forall (ctx :: Ctx CrucibleType) (tp :: CrucibleType). () => TypeRepr tp -> Reg ctx tp -> Assignment a ctx -> a tp
- Lang.Crucible.Analysis.ForwardDataflow: [kfwd_same] :: KildallForward ext (blocks :: Ctx (Ctx CrucibleType)) (a :: CrucibleType -> Type) c -> forall (tp :: CrucibleType). () => a tp -> a tp -> Bool
- Lang.Crucible.Analysis.ForwardDataflow: data KildallForward ext (blocks :: Ctx Ctx CrucibleType) (a :: CrucibleType -> Type) c
- Lang.Crucible.Analysis.ForwardDataflow: data KildallPair (a :: k -> Type) c (tp :: k)
- Lang.Crucible.Analysis.ForwardDataflow: data SymDom
- Lang.Crucible.Analysis.ForwardDataflow: instance GHC.Classes.Eq Lang.Crucible.Analysis.ForwardDataflow.SymDom
- Lang.Crucible.Analysis.ForwardDataflow: instance GHC.Classes.Ord Lang.Crucible.Analysis.ForwardDataflow.SymDom
- Lang.Crucible.Analysis.ForwardDataflow: instance GHC.Show.Show Lang.Crucible.Analysis.ForwardDataflow.SymDom
- Lang.Crucible.Analysis.ForwardDataflow: instance GHC.Show.Show a => Data.Parameterized.Classes.ShowF (Lang.Crucible.Analysis.ForwardDataflow.Ignore a)
- Lang.Crucible.Analysis.ForwardDataflow: instance forall a k (b :: k). GHC.Classes.Eq a => GHC.Classes.Eq (Lang.Crucible.Analysis.ForwardDataflow.Ignore a b)
- Lang.Crucible.Analysis.ForwardDataflow: instance forall a k (b :: k). GHC.Classes.Ord a => GHC.Classes.Ord (Lang.Crucible.Analysis.ForwardDataflow.Ignore a b)
- Lang.Crucible.Analysis.ForwardDataflow: instance forall k (a :: k -> GHC.Types.Type) c (tp :: k). (Data.Parameterized.Classes.ShowF a, GHC.Show.Show c) => GHC.Show.Show (Lang.Crucible.Analysis.ForwardDataflow.KildallPair a c tp)
- Lang.Crucible.Analysis.ForwardDataflow: instance forall k (a :: k -> GHC.Types.Type) c. (Data.Parameterized.Classes.ShowF a, GHC.Show.Show c) => Data.Parameterized.Classes.ShowF (Lang.Crucible.Analysis.ForwardDataflow.KildallPair a c)
- Lang.Crucible.Analysis.ForwardDataflow: instance forall k a (tp :: k). GHC.Show.Show a => GHC.Show.Show (Lang.Crucible.Analysis.ForwardDataflow.Ignore a tp)
- Lang.Crucible.Analysis.ForwardDataflow: kildall_forward :: forall ext a c (blocks :: Ctx (Ctx CrucibleType)) (ret :: CrucibleType) (init :: Ctx CrucibleType). KildallForward ext blocks a c -> CFG ext blocks init ret -> (Assignment a init, c) -> (Assignment (KildallPair (Assignment a) c) blocks, a ret, c)
- Lang.Crucible.Analysis.ForwardDataflow: kildall_transfer :: forall ext a c (blocks :: Ctx (Ctx CrucibleType)) (ret :: CrucibleType) (ctx :: Ctx CrucibleType). KildallForward ext blocks a c -> TypeRepr ret -> Block ext blocks ret ctx -> (Assignment a ctx, c) -> State (Assignment (KildallPair (Assignment a) c) blocks, a ret, c) (Set (Some (BlockID blocks)))
- Lang.Crucible.Analysis.ForwardDataflow: newtype Ignore a (b :: k)
- Lang.Crucible.Analysis.ForwardDataflow: sym_call_transfer :: forall (args :: Ctx CrucibleType) (ret :: CrucibleType) (ctx :: Ctx CrucibleType) (a :: CrucibleType -> Type). CtxRepr args -> TypeRepr ret -> Reg ctx (FunctionHandleType args ret) -> Ignore SymDom (FunctionHandleType args ret) -> Assignment a args -> Ignore SymDom ret
- Lang.Crucible.Analysis.ForwardDataflow: sym_expr_transfer :: forall ext (ctx :: Ctx CrucibleType) (tp :: CrucibleType). IsSyntaxExtension ext => Expr ext ctx tp -> Assignment (Ignore SymDom :: CrucibleType -> Type) ctx -> SymDom
- Lang.Crucible.Analysis.ForwardDataflow: sym_reg_transfer :: forall (ctx :: Ctx CrucibleType) (tp :: CrucibleType). Reg ctx tp -> Assignment (Ignore SymDom :: CrucibleType -> Type) ctx -> SymDom
- Lang.Crucible.Analysis.ForwardDataflow: symbolicAnalysis :: forall ext (blocks :: Ctx (Ctx CrucibleType)). IsSyntaxExtension ext => KildallForward ext blocks (Ignore SymDom :: CrucibleType -> Type) SymDom
- Lang.Crucible.Analysis.ForwardDataflow: symbolicResults :: forall ext (blocks :: Ctx (Ctx CrucibleType)) (init :: Ctx CrucibleType) (ret :: CrucibleType). IsSyntaxExtension ext => CFG ext blocks init ret -> String
- Lang.Crucible.Analysis.ForwardDataflow: symlub :: SymDom -> SymDom -> SymDom
- Lang.Crucible.Analysis.Postdom: breakpointPostdomInfo :: forall ext (b :: Ctx (Ctx CrucibleType)) (i :: Ctx CrucibleType) (r :: CrucibleType). CFG ext b i r -> [BreakpointName] -> CFGPostdom b
- Lang.Crucible.CFG.Common: BreakpointName :: Text -> BreakpointName
- Lang.Crucible.CFG.Common: [breakpointNameText] :: BreakpointName -> Text
- Lang.Crucible.CFG.Common: instance GHC.Classes.Eq Lang.Crucible.CFG.Common.BreakpointName
- Lang.Crucible.CFG.Common: instance GHC.Classes.Ord Lang.Crucible.CFG.Common.BreakpointName
- Lang.Crucible.CFG.Common: instance GHC.Show.Show Lang.Crucible.CFG.Common.BreakpointName
- Lang.Crucible.CFG.Common: instance Prettyprinter.Internal.Pretty Lang.Crucible.CFG.Common.BreakpointName
- Lang.Crucible.CFG.Common: newtype BreakpointName
- Lang.Crucible.CFG.Core: [cfgBreakpoints] :: CFG ext (blocks :: Ctx (Ctx CrucibleType)) (init :: Ctx CrucibleType) (ret :: CrucibleType) -> !Bimap BreakpointName (Some (BlockID blocks))
- Lang.Crucible.CFG.Generator: Breakpoint :: BreakpointName -> !Assignment (Value s) args -> Stmt ext s
- Lang.Crucible.CFG.Generator: BreakpointName :: Text -> BreakpointName
- Lang.Crucible.CFG.Generator: [breakpointNameText] :: BreakpointName -> Text
- Lang.Crucible.CFG.Generator: addBreakpointStmt :: forall (m :: Type -> Type) ext s (args :: Ctx CrucibleType) (t :: Type -> Type) (r :: CrucibleType). (Monad m, IsSyntaxExtension ext) => Text -> Assignment (Value s) args -> Generator ext s t r m ()
- Lang.Crucible.CFG.Generator: newtype BreakpointName
- Lang.Crucible.CFG.Reg: Breakpoint :: BreakpointName -> !Assignment (Value s) args -> Stmt ext s
- Lang.Crucible.Simulator: SimError :: !ProgramLoc -> !SimErrorReason -> SimError
- Lang.Crucible.Simulator: [simErrorLoc] :: SimError -> !ProgramLoc
- Lang.Crucible.Simulator: [simErrorReason] :: SimError -> !SimErrorReason
- Lang.Crucible.Simulator.Breakpoint: breakAndReturn :: forall sym ext (blocks :: Ctx (Ctx CrucibleType)) (init :: Ctx CrucibleType) (ret :: CrucibleType) (args :: Ctx CrucibleType) p rtp. (IsSymInterface sym, IsSyntaxExtension ext) => CFG ext blocks init ret -> BreakpointName -> Assignment TypeRepr args -> TypeRepr ret -> OverrideSim p sym ext rtp args ret (RegValue sym ret) -> HashMap SomeHandle [BreakpointName] -> IO (ExecutionFeature p sym ext rtp)
- Lang.Crucible.Simulator.CallFrame: setFrameBreakpointPostdomInfo :: forall sym ext (blocks :: Ctx (Ctx CrucibleType)) (ret :: CrucibleType) (ctx :: Ctx CrucibleType). [BreakpointName] -> CallFrame sym ext blocks ret ctx -> CallFrame sym ext blocks ret ctx
- Lang.Crucible.Simulator.SimError: SimError :: !ProgramLoc -> !SimErrorReason -> SimError
- Lang.Crucible.Simulator.SimError: [simErrorLoc] :: SimError -> !ProgramLoc
- Lang.Crucible.Simulator.SimError: [simErrorReason] :: SimError -> !SimErrorReason
+ Lang.Crucible.Analysis.Postdom: cutpointPostdomInfo :: forall ext (b :: Ctx (Ctx CrucibleType)) (i :: Ctx CrucibleType) (r :: CrucibleType). CFG ext b i r -> [CutpointName] -> CFGPostdom b
+ Lang.Crucible.Backend: getExceptionContext :: IsSymBackend sym bak => bak -> Maybe ProgramStack
+ Lang.Crucible.Backend: withExceptionContext :: IsSymBackend sym bak => bak -> ProgramStack -> bak
+ Lang.Crucible.CFG.Common: CutpointName :: Text -> CutpointName
+ Lang.Crucible.CFG.Common: [cutpointNameText] :: CutpointName -> Text
+ Lang.Crucible.CFG.Common: instance GHC.Classes.Eq Lang.Crucible.CFG.Common.CutpointName
+ Lang.Crucible.CFG.Common: instance GHC.Classes.Ord Lang.Crucible.CFG.Common.CutpointName
+ Lang.Crucible.CFG.Common: instance GHC.Show.Show Lang.Crucible.CFG.Common.CutpointName
+ Lang.Crucible.CFG.Common: instance Prettyprinter.Internal.Pretty Lang.Crucible.CFG.Common.CutpointName
+ Lang.Crucible.CFG.Common: newtype CutpointName
+ Lang.Crucible.CFG.Core: [cfgCutpoints] :: CFG ext (blocks :: Ctx (Ctx CrucibleType)) (init :: Ctx CrucibleType) (ret :: CrucibleType) -> !Bimap CutpointName (Some (BlockID blocks))
+ Lang.Crucible.CFG.Expr: [FloatRound] :: forall (fi :: FloatInfo) (f :: CrucibleType -> Type) ext. !FloatInfoRepr fi -> !RoundingMode -> !f (FloatType fi) -> App ext f ('FloatType fi)
+ Lang.Crucible.CFG.Expr: [SequenceReverse] :: forall (tp1 :: CrucibleType) (f :: CrucibleType -> Type) ext. !TypeRepr tp1 -> !f (SequenceType tp1) -> App ext f ('SequenceType tp1)
+ Lang.Crucible.CFG.Generator: Cut :: CutpointName -> !Assignment (Value s) args -> Stmt ext s
+ Lang.Crucible.CFG.Generator: CutpointName :: Text -> CutpointName
+ Lang.Crucible.CFG.Generator: [cutpointNameText] :: CutpointName -> Text
+ Lang.Crucible.CFG.Generator: addCutStmt :: forall (m :: Type -> Type) ext s (args :: Ctx CrucibleType) (t :: Type -> Type) (r :: CrucibleType). (Monad m, IsSyntaxExtension ext) => Text -> Assignment (Value s) args -> Generator ext s t r m ()
+ Lang.Crucible.CFG.Generator: newtype CutpointName
+ Lang.Crucible.CFG.Reg: Cut :: CutpointName -> !Assignment (Value s) args -> Stmt ext s
+ Lang.Crucible.Simulator: ECCLimited :: Int -> ExceptionContextConfig
+ Lang.Crucible.Simulator: ECCNoLimit :: ExceptionContextConfig
+ Lang.Crucible.Simulator: ECCNone :: ExceptionContextConfig
+ Lang.Crucible.Simulator: SimErrorWithContext :: !ProgramLoc -> !SimErrorReason -> !Maybe ProgramStack -> SimError
+ Lang.Crucible.Simulator: [_exceptionContextConfig] :: SimContext p sym ext -> ExceptionContextConfig
+ Lang.Crucible.Simulator: data ExceptionContextConfig
+ Lang.Crucible.Simulator: exceptionContextConfig :: forall p sym ext f. Functor f => (ExceptionContextConfig -> f ExceptionContextConfig) -> SimContext p sym ext -> f (SimContext p sym ext)
+ Lang.Crucible.Simulator: parseExceptionContextConfig :: String -> Either String ExceptionContextConfig
+ Lang.Crucible.Simulator: pattern SimError :: ProgramLoc -> SimErrorReason -> SimError
+ Lang.Crucible.Simulator.CallFrame: frameStackLoc :: forall sym ext f (a :: Maybe (Ctx CrucibleType)). SimFrame sym ext f a -> Maybe ProgramLoc
+ Lang.Crucible.Simulator.CallFrame: setFrameCutpointPostdomInfo :: forall sym ext (blocks :: Ctx (Ctx CrucibleType)) (ret :: CrucibleType) (ctx :: Ctx CrucibleType). [CutpointName] -> CallFrame sym ext blocks ret ctx -> CallFrame sym ext blocks ret ctx
+ Lang.Crucible.Simulator.Cut: cutAndReturn :: forall sym ext (blocks :: Ctx (Ctx CrucibleType)) (init :: Ctx CrucibleType) (ret :: CrucibleType) (args :: Ctx CrucibleType) p rtp. (IsSymInterface sym, IsSyntaxExtension ext) => CFG ext blocks init ret -> CutpointName -> Assignment TypeRepr args -> TypeRepr ret -> OverrideSim p sym ext rtp args ret (RegValue sym ret) -> HashMap SomeHandle [CutpointName] -> IO (ExecutionFeature p sym ext rtp)
+ Lang.Crucible.Simulator.ExecutionTree: ECCLimited :: Int -> ExceptionContextConfig
+ Lang.Crucible.Simulator.ExecutionTree: ECCNoLimit :: ExceptionContextConfig
+ Lang.Crucible.Simulator.ExecutionTree: ECCNone :: ExceptionContextConfig
+ Lang.Crucible.Simulator.ExecutionTree: [_exceptionContextConfig] :: SimContext p sym ext -> ExceptionContextConfig
+ Lang.Crucible.Simulator.ExecutionTree: data ExceptionContextConfig
+ Lang.Crucible.Simulator.ExecutionTree: exceptionContextConfig :: forall p sym ext f. Functor f => (ExceptionContextConfig -> f ExceptionContextConfig) -> SimContext p sym ext -> f (SimContext p sym ext)
+ Lang.Crucible.Simulator.ExecutionTree: instance GHC.Classes.Eq Lang.Crucible.Simulator.ExecutionTree.ExceptionContextConfig
+ Lang.Crucible.Simulator.ExecutionTree: instance GHC.Classes.Ord Lang.Crucible.Simulator.ExecutionTree.ExceptionContextConfig
+ Lang.Crucible.Simulator.ExecutionTree: instance GHC.Read.Read Lang.Crucible.Simulator.ExecutionTree.ExceptionContextConfig
+ Lang.Crucible.Simulator.ExecutionTree: instance GHC.Show.Show Lang.Crucible.Simulator.ExecutionTree.ExceptionContextConfig
+ Lang.Crucible.Simulator.ExecutionTree: parseExceptionContextConfig :: String -> Either String ExceptionContextConfig
+ Lang.Crucible.Simulator.ExecutionTree: stateProgramStack :: forall p sym ext r f (args :: Maybe (Ctx CrucibleType)). SimState p sym ext r f args -> ProgramStack
+ Lang.Crucible.Simulator.ExecutionTree: withStateBackend :: forall p sym ext rtp f (args :: Maybe (Ctx CrucibleType)) a. SimState p sym ext rtp f args -> (forall bak. IsSymBackend sym bak => bak -> a) -> a
+ Lang.Crucible.Simulator.RecordAndReplay: getConcreteRecordedTrace :: IsExprBuilder sym => SymGlobalState sym -> RecordState p sym ext rtp -> sym -> (Pred sym -> IO Bool) -> IO (RecordedTrace sym)
+ Lang.Crucible.Simulator.SimError: ProgramStack :: Int -> [ProgramLoc] -> ProgramStack
+ Lang.Crucible.Simulator.SimError: SimErrorWithContext :: !ProgramLoc -> !SimErrorReason -> !Maybe ProgramStack -> SimError
+ Lang.Crucible.Simulator.SimError: [psFrameOmitCount] :: ProgramStack -> Int
+ Lang.Crucible.Simulator.SimError: [psFrames] :: ProgramStack -> [ProgramLoc]
+ Lang.Crucible.Simulator.SimError: data ProgramStack
+ Lang.Crucible.Simulator.SimError: mkSimError :: ProgramLoc -> SimErrorReason -> Maybe ProgramStack -> SimError
+ Lang.Crucible.Simulator.SimError: pattern SimError :: ProgramLoc -> SimErrorReason -> SimError
+ Lang.Crucible.Simulator.SimError: ppProgramStack :: ProgramStack -> Doc ann
+ Lang.Crucible.Simulator.SimError: simErrorContext :: SimError -> Maybe ProgramStack
+ Lang.Crucible.Simulator.SimError: simErrorLoc :: SimError -> ProgramLoc
+ Lang.Crucible.Simulator.SimError: simErrorReason :: SimError -> SimErrorReason
+ Lang.Crucible.Simulator.SymSequence: reverseSymSequence :: sym -> SymSequence sym a -> IO (SymSequence sym a)
- Lang.Crucible.Backend.Prove: onlineProve :: forall m solver sym t (st :: Type -> Type) fs r. (MonadIO m, SMTReadWriter solver, sym ~ ExprBuilder t st fs, IsSymExprBuilder sym) => SolverProcess t solver -> Assumptions sym -> Assertion sym -> ProofConsumer sym t r -> m (SubgoalResult r)
+ Lang.Crucible.Backend.Prove: onlineProve :: forall m solver sym t (st :: Type -> Type) fs r. (MonadIO m, SMTReadWriter solver, sym ~ ExprBuilder t st fs, IsSymExprBuilder sym) => sym -> SolverProcess t solver -> Assumptions sym -> Assertion sym -> ProofConsumer sym t r -> m (SubgoalResult r)
- Lang.Crucible.CFG.Core: CFG :: FnHandle init ret -> !BlockMap ext blocks ret -> !BlockID blocks init -> !Bimap BreakpointName (Some (BlockID blocks)) -> CFG ext (blocks :: Ctx (Ctx CrucibleType)) (init :: Ctx CrucibleType) (ret :: CrucibleType)
+ Lang.Crucible.CFG.Core: CFG :: FnHandle init ret -> !BlockMap ext blocks ret -> !BlockID blocks init -> !Bimap CutpointName (Some (BlockID blocks)) -> CFG ext (blocks :: Ctx (Ctx CrucibleType)) (init :: Ctx CrucibleType) (ret :: CrucibleType)
- Lang.Crucible.Simulator: SimContext :: !SomeBackend sym -> !forall a. () => IsSymInterfaceProof sym a -> !IntrinsicTypes sym -> !HandleAllocator -> !Handle -> ExtensionImpl p sym ext -> !FunctionBindings p sym ext -> !p -> !Map Text (Metric p sym ext) -> SimContext p sym ext
+ Lang.Crucible.Simulator: SimContext :: !SomeBackend sym -> !forall a. () => IsSymInterfaceProof sym a -> !IntrinsicTypes sym -> !HandleAllocator -> !Handle -> ExtensionImpl p sym ext -> !FunctionBindings p sym ext -> !p -> !Map Text (Metric p sym ext) -> ExceptionContextConfig -> SimContext p sym ext
- Lang.Crucible.Simulator: ctxSymInterface :: forall p sym ext f. (Contravariant f, Functor f) => (sym -> f sym) -> SimContext p sym ext -> f (SimContext p sym ext)
+ Lang.Crucible.Simulator: ctxSymInterface :: forall p sym ext r. Getting r (SimContext p sym ext) sym
- Lang.Crucible.Simulator.CallFrame: frameFunctionName :: forall sym ext f1 (a :: Maybe (Ctx CrucibleType)) f2. (Contravariant f2, Functor f2) => (FunctionName -> f2 FunctionName) -> SimFrame sym ext f1 a -> f2 (SimFrame sym ext f1 a)
+ Lang.Crucible.Simulator.CallFrame: frameFunctionName :: forall sym ext f (a :: Maybe (Ctx CrucibleType)) r. Getting r (SimFrame sym ext f a) FunctionName
- Lang.Crucible.Simulator.ExecutionTree: SimContext :: !SomeBackend sym -> !forall a. () => IsSymInterfaceProof sym a -> !IntrinsicTypes sym -> !HandleAllocator -> !Handle -> ExtensionImpl p sym ext -> !FunctionBindings p sym ext -> !p -> !Map Text (Metric p sym ext) -> SimContext p sym ext
+ Lang.Crucible.Simulator.ExecutionTree: SimContext :: !SomeBackend sym -> !forall a. () => IsSymInterfaceProof sym a -> !IntrinsicTypes sym -> !HandleAllocator -> !Handle -> ExtensionImpl p sym ext -> !FunctionBindings p sym ext -> !p -> !Map Text (Metric p sym ext) -> ExceptionContextConfig -> SimContext p sym ext
- Lang.Crucible.Simulator.ExecutionTree: ctxSymInterface :: forall p sym ext f. (Contravariant f, Functor f) => (sym -> f sym) -> SimContext p sym ext -> f (SimContext p sym ext)
+ Lang.Crucible.Simulator.ExecutionTree: ctxSymInterface :: forall p sym ext r. Getting r (SimContext p sym ext) sym
- Lang.Crucible.Simulator.ExecutionTree: stateConfiguration :: forall p sym ext r f1 (args :: Maybe (Ctx CrucibleType)) f2. (Contravariant f2, Functor f2) => (Config -> f2 Config) -> SimState p sym ext r f1 args -> f2 (SimState p sym ext r f1 args)
+ Lang.Crucible.Simulator.ExecutionTree: stateConfiguration :: forall p sym ext r1 f (args :: Maybe (Ctx CrucibleType)) r2. Getting r2 (SimState p sym ext r1 f args) Config
- Lang.Crucible.Simulator.ExecutionTree: stateIntrinsicTypes :: forall p sym ext r f1 (args :: Maybe (Ctx CrucibleType)) f2. (Contravariant f2, Functor f2) => (IntrinsicTypes sym -> f2 (IntrinsicTypes sym)) -> SimState p sym ext r f1 args -> f2 (SimState p sym ext r f1 args)
+ Lang.Crucible.Simulator.ExecutionTree: stateIntrinsicTypes :: forall p sym ext r1 f (args :: Maybe (Ctx CrucibleType)) r2. Getting r2 (SimState p sym ext r1 f args) (IntrinsicTypes sym)
- Lang.Crucible.Simulator.ExecutionTree: stateLocation :: forall p sym ext r f1 (a :: Maybe (Ctx CrucibleType)) f2. (Contravariant f2, Functor f2) => (Maybe ProgramLoc -> f2 (Maybe ProgramLoc)) -> SimState p sym ext r f1 a -> f2 (SimState p sym ext r f1 a)
+ Lang.Crucible.Simulator.ExecutionTree: stateLocation :: forall p sym ext r1 f (a :: Maybe (Ctx CrucibleType)) r2. Getting r2 (SimState p sym ext r1 f a) (Maybe ProgramLoc)
- Lang.Crucible.Simulator.ExecutionTree: stateSymInterface :: forall p sym ext r f1 (a :: Maybe (Ctx CrucibleType)) f2. (Contravariant f2, Functor f2) => (sym -> f2 sym) -> SimState p sym ext r f1 a -> f2 (SimState p sym ext r f1 a)
+ Lang.Crucible.Simulator.ExecutionTree: stateSymInterface :: forall p sym ext r1 f (a :: Maybe (Ctx CrucibleType)) r2. Getting r2 (SimState p sym ext r1 f a) sym
- Lang.Crucible.Simulator.RecordAndReplay: getRecordedTrace :: IsExprBuilder sym => SymGlobalState sym -> RecordState p sym ext rtp -> sym -> (Pred sym -> IO Bool) -> IO (RecordedTrace sym)
+ Lang.Crucible.Simulator.RecordAndReplay: getRecordedTrace :: SymGlobalState sym -> RecordState p sym ext rtp -> sym -> IO (RecordedTrace sym)

Files

CHANGELOG.md view
@@ -1,3 +1,40 @@+# 0.10 -- 2026-09-10++* Add support for GHC 9.12 (at 9.12.2) and bump from 9.10.1 to 9.10.3.+* Fix `uniquelyConcRegMap` blocking clause: use disjunction (OR) instead of+  conjunction (AND). The old code would falsely report a `RegMap` as uniquely+  concretized whenever any single component was unique, even if other components+  had multiple possible values.+* **BREAKING:** Rename various bits associated with the "breakpoint"+  feature in accordance with renaming the feature to "cut" or+  "cutpoint".+  Exported Haskell symbols renamed:+  - `Lang.Crucible.Simulator.Breakpoint` -> `Lang.Crucible.Simulator.Cut`+  - `BreakpointName` -> `CutpointName`+  - `Breakpoint` -> `Cut`+  - `addBreakpointStmt` -> `addCutStmt`+  - `breakAndReturn` -> `cutAndReturn`+  - `breakpointPostdomInfo` -> `cutpointPostdomInfo`+  - `cfgBreakpoints` -> `cfgCutpoints`+  - `setFrameBreakpointPostdomInfo` -> `setFrameCutpointPostdomInfo`+* Add `reverseSymSequence` to `Lang.Crucible.Simulator.SymSequence`+* **BREAKING:** Add `FloatRound` constructor tp `App` in+  `Lang.Crucible.CFG.Expr` for rounding floating-point values to the nearest+  representable integral value.+* **BREAKING:** Add `SequenceReverse` constructor to `App` in+  `Lang.Crucible.CFG.Expr` for reversing symbolic sequences.+* **BREAKING:** Change the signature of `getRecordedTrace` in+  `Lang.Crucible.Simulator.RecordAndReplay` to remove the `evalBool` parameter,+  as the implementation no longer concretizes the trace.+* Add `Lang.Crucible.Simulator.RecordAndReplay.getConcreteRecordedTrace` for+  performant trace reversal when concretization is desired.+* Add `withStateBackend` and additional infrastructure for including stack+  traces in `SimError` and `IsSymBackend`+* Fix `onlineProve` to properly negate goals before checking satisfiability+* Avoid sending trivially-true goals to the solver in `Backend.Prove`.+* Fix bug in `execResultGlobals` that caused it to erroneously always return the+  non-aborted branch of a `FinishedResult ... (PartialRes ...)`.+ # 0.9 -- 2026-01-29  # 0.8.0 -- 2025-11-09
crucible.cabal view
@@ -1,6 +1,6 @@ Cabal-version: 2.2 Name:          crucible-Version:       0.9+Version:       0.10 Author:        Galois Inc. Maintainer:    rscott@galois.com, kquick@galois.com, langston@galois.com Copyright:     (c) Galois, Inc 2014-2022@@ -34,12 +34,120 @@   Default: True  common bldflags-  ghc-options: -Wall-               -Werror=incomplete-patterns-               -Werror=missing-methods-               -Werror=overlapping-patterns-               -Wpartial-fields-               -Wincomplete-uni-patterns+  -- Note [Export lists]+  -- -------------------+  --+  -- We don't allow modules without export lists.+  --+  -- From the GHC docs:+  --+  --     Declaring an explicit export list [...] enables GHC dead code analysis,+  --     prevents accidental export of names and can ease optimizations like+  --     inlining.+  --+  -- It also makes it easier to organize the Haddocks using section headers, and+  -- allows for internal/hidden definitions and constructors.+  --+  -- We can't use -Werror=missing-export-lists here because it interferes with+  -- ghcid. However, we enable it in CI, see ../cabal.project.ci.+  ghc-options:+    -Wmissing-export-lists++  -- Specifying -Wall and -Werror can cause the project to fail to build on+  -- newer versions of GHC simply due to new warnings being added to -Wall. To+  -- prevent this from happening we manually list which warnings should be+  -- considered errors. We also list some warnings that are not in -Wall, though+  -- try to avoid "opinionated" warnings (though this judgement is clearly+  -- subjective).+  --+  -- Warnings are grouped by the GHC version that introduced them, and then+  -- alphabetically.+  --+  -- A list of warnings and the GHC version in which they were introduced is+  -- available here:+  -- https://ghc.gitlab.haskell.org/ghc/doc/users_guide/using-warnings.html++  -- Since GHC 9.6 or earlier:+  ghc-options:+    -Wall+    -Werror=ambiguous-fields+    -Werror=deferred-type-errors+    -Werror=deprecated-flags+    -Werror=deprecations+    -Werror=deriving-defaults+    -Werror=deriving-typeable+    -Werror=dodgy-foreign-imports+    -Werror=duplicate-exports+    -Werror=empty-enumerations+    -Werror=gadt-mono-local-binds+    -Werror=identities+    -Werror=inaccessible-code+    -Werror=incomplete-patterns+    -Werror=incomplete-record-updates+    -Werror=incomplete-uni-patterns+    -Werror=inline-rule-shadowing+    -Werror=misplaced-pragmas+    -Werror=missed-extra-shared-lib+    -Werror=missing-exported-signatures+    -Werror=missing-fields+    -Werror=missing-home-modules+    -Werror=missing-methods+    -Werror=missing-pattern-synonym-signatures+    -Werror=missing-signatures+    -Werror=name-shadowing+    -Werror=noncanonical-monad-instances+    -Werror=noncanonical-monoid-instances+    -Werror=operator-whitespace+    -Werror=operator-whitespace-ext-conflict+    -Werror=orphans+    -Werror=overflowed-literals+    -Werror=overlapping-patterns+    -Werror=partial-fields+    -Werror=partial-type-signatures+    -Werror=redundant-bang-patterns+    -Werror=redundant-record-wildcards+    -Werror=redundant-strictness-flags+    -Werror=simplifiable-class-constraints+    -Werror=star-binder+    -Werror=star-is-type+    -Werror=tabs+    -Werror=type-defaults+    -Werror=typed-holes+    -Werror=type-equality-out-of-scope+    -Werror=type-equality-requires-operators+    -Werror=unicode-bidirectional-format-characters+    -Werror=unrecognised-pragmas+    -Werror=unrecognised-warning-flags+    -Werror=unsupported-calling-conventions+    -Werror=unsupported-llvm-version+    -Werror=unused-do-bind+    -Werror=unused-imports+    -Werror=unused-record-wildcards+    -Werror=warnings-deprecations+    -Werror=wrong-do-bind++  if impl(ghc < 9.8)+    ghc-options:+      -Werror=forall-identifier++  if impl(ghc >= 9.8)+    ghc-options:+      -Werror=incomplete-export-warnings+      -Werror=inconsistent-flags++  if impl(ghc >= 9.10)+    ghc-options:+      -Werror=badly-staged-types+      -Werror=data-kinds-tc+      -Werror=incomplete-record-selectors+              +  if impl(ghc < 9.12)+    ghc-options:+      -Werror=compat-unqualified-imports++  -- TODO(#1308): Enable and fix this warning when GHC 9.6 is dropped from CI+  -- -Werror=deprecated-type-abstractions+   ghc-prof-options: -O2 -fprof-auto-exported   default-language: Haskell2010 @@ -48,7 +156,7 @@   import: bldflags   build-depends:     async,-    base >= 4.13 && < 4.21,+    base >= 4.13 && < 4.22,     bimap,     bv-sized >= 1.0.0 && < 1.1,     containers >= 0.5.9.0,@@ -56,15 +164,17 @@     fgl,     hashable,     json >= 0.9 && < 1.0,-    lens,+    microlens >= 0.5,+    microlens-mtl,+    microlens-th,     mtl,     panic >= 0.3,-    parameterized-utils >= 1.0.8 && < 2.2,+    parameterized-utils >= 2.3 && < 2.4,     prettyprinter >= 1.7.0,     template-haskell,     text,     time >= 1.8 && < 2.0,-    th-abstraction >=0.1 && <0.7,+    th-abstraction >=0.1 && <0.8,     transformers,     unordered-containers,     vector,@@ -81,7 +191,6 @@    exposed-modules:     Lang.Crucible.Analysis.DFS-    Lang.Crucible.Analysis.ForwardDataflow     Lang.Crucible.Analysis.Fixpoint     Lang.Crucible.Analysis.Fixpoint.Components     Lang.Crucible.Analysis.Postdom@@ -106,10 +215,10 @@     Lang.Crucible.FunctionHandle     Lang.Crucible.README     Lang.Crucible.Simulator-    Lang.Crucible.Simulator.Breakpoint     Lang.Crucible.Simulator.BoundedExec     Lang.Crucible.Simulator.BoundedRecursion     Lang.Crucible.Simulator.CallFrame+    Lang.Crucible.Simulator.Cut     Lang.Crucible.Simulator.Evaluation     Lang.Crucible.Simulator.EvalStmt     Lang.Crucible.Simulator.ExecutionTree@@ -170,12 +279,14 @@   hs-source-dirs: test/helpers   other-modules:     SymSequence+    SymSequence.Properties+    SymSequence.Reverse   main-is: Main.hs   build-depends: base,                  hspec >= 2.5,                  crucible,                  hedgehog,-                 lens,+                 microlens,                  panic >= 0.3,                  parameterized-utils,                  tasty >= 0.10,
src/Lang/Crucible/Analysis/Fixpoint.hs view
@@ -51,11 +51,13 @@   ) where  import           Control.Applicative-import           Control.Lens.Operators ( (^.), (%=), (.~), (&), (%~) ) import qualified Control.Monad.State.Strict as St+import           Data.Function ((&)) import qualified Data.Functor.Identity as I import           Data.Kind import qualified Data.Set as S+import           Lens.Micro ((^.), (.~), (%~))+import           Lens.Micro.Mtl ((%=)) import           Text.Printf  import           Prelude@@ -68,6 +70,7 @@ import           Lang.Crucible.CFG.Core import           Lang.Crucible.CFG.Extension import           Lang.Crucible.Analysis.Fixpoint.Components+import           Lang.Crucible.Panic (panic)  -- | A wrapper around widening strategies data WideningStrategy = WideningStrategy (Int -> Bool)@@ -472,14 +475,14 @@           let assignment' = interpWriteGlobal interp gv reg assignment           in maybe assignment (joinPointAbstractions dom assignment) assignment' -        FreshConstant{} -> error "transferStmt: FreshConstant not supported"-        FreshFloat{} -> error "transferStmt: FreshFloat not supported"-        FreshNat{} -> error "transferStmt: FreshNat not supported"-        NewEmptyRefCell{} -> error "transferStmt: NewEmptyRefCell not supported"-        NewRefCell {} -> error "transferStmt: NewRefCell not supported"-        ReadRefCell {} -> error "transferStmt: ReadRefCell not supported"-        WriteRefCell {} -> error "transferStmt: WriteRefCell not supported"-        DropRefCell {} -> error "transferStmt: DropRefCell not supported"+        FreshConstant{} -> panic "transferStmt" ["FreshConstant not supported"]+        FreshFloat{} -> panic "transferStmt" ["FreshFloat not supported"]+        FreshNat{} -> panic "transferStmt" ["FreshNat not supported"]+        NewEmptyRefCell{} -> panic "transferStmt" ["NewEmptyRefCell not supported"]+        NewRefCell {} -> panic "transferStmt" ["NewRefCell not supported"]+        ReadRefCell {} -> panic "transferStmt" ["ReadRefCell not supported"]+        WriteRefCell {} -> panic "transferStmt" ["WriteRefCell not supported"]+        DropRefCell {} -> panic "transferStmt" ["DropRefCell not supported"]      -- Transfer a block terminator statement.     transferTerm :: forall ctx'@@ -528,7 +531,7 @@           isRetAbstr %= domJoin dom absVal           return S.empty -        VariantElim {} -> error "transferTerm: VariantElim terminator not supported"+        VariantElim {} -> panic "transferTerm" ["VariantElim terminator not supported"]       transferJump :: forall ctx'
src/Lang/Crucible/Analysis/Fixpoint/Components.hs view
@@ -40,6 +40,7 @@ import           Data.Parameterized.Some (Some(Some)) import           Lang.Crucible.CFG.Core (CFG, BlockID) import qualified Lang.Crucible.CFG.Core as CFG+import           Lang.Crucible.Panic (panic)  -- | Compute a weak topological ordering over a control flow graph. --@@ -109,7 +110,7 @@                   -- Otherwise, unwind the stack and add a full component                 unwindStack elt v                 makeComponent v-        Nothing -> error "Pop attempted on empty stack (Components:visit)"+        Nothing -> panic "visit" ["Pop attempted on empty stack"]   -- We return the least label in the strongly-connected component   -- containing this vertex, which is used if we have to unwind back   -- to the SCC head vertex.
− src/Lang/Crucible/Analysis/ForwardDataflow.hs
@@ -1,309 +0,0 @@---------------------------------------------------------------------------- |--- Module      : Lang.Crucible.Analysis.ForwardDataflow--- Description : Forward dataflow analysis framework based on Kildall's algorithm--- Copyright   : (c) Galois, Inc 2015--- License     : BSD3--- Maintainer  : Rob Dockins <rdockins@galois.com>--- Stability   : provisional------ This module defines a generic framework for forward dataflow analysis,--- with some additional control-flow data on the side.------ We calculate a fixpoint of a given analysis via the straightforward--- method of iterating the transfer function until no more updates occur.------ Our current method for doing this is quite naive, and more efficient--- methods exist.---------------------------------------------------------------------------{-# LANGUAGE CPP #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE PolyKinds #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE Rank2Types #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE TypeSynonymInstances #-}--module Lang.Crucible.Analysis.ForwardDataflow-{-# DEPRECATED "Lang.Crucible.Analysis.Fixpoint is a better implementation of these ideas" #-}-where--import           Control.Lens-import           Control.Monad.State.Strict-import           Data.Kind-import           Data.Parameterized.Context ( Assignment )-import qualified Data.Parameterized.Context as Ctx-import           Data.Parameterized.TraversableFC-import           Data.Set (Set)-import qualified Data.Set as Set-import           Prelude hiding (foldr)-import           Prettyprinter---import           Lang.Crucible.Types-import           Lang.Crucible.CFG.Core-import           Lang.Crucible.CFG.Expr--import qualified Debug.Trace as Debug--------------------------data SymDom = Dead | Symbolic | Concrete-  deriving (Eq, Ord, Show)--symbolicResults-   :: IsSyntaxExtension ext-   => CFG ext blocks init ret-   -- -> Assignment (Ignore SymDom) init-   -> String-   -- -> (Assignment (KildallPair (Assignment (Ignore SymDom)) SymDom) blocks, Ignore SymDom ret, SymDom)-symbolicResults cfg = show $ kildall_forward symbolicAnalysis cfg (begin, Concrete)- where sz = Ctx.size (blockInputs (getBlock (cfgEntryBlockID cfg) (cfgBlockMap cfg)))-       begin = Ctx.generate sz (\_ -> Ignore Symbolic)---symlub :: SymDom -> SymDom -> SymDom-symlub Dead x = x-symlub x Dead = x-symlub Symbolic _ = Symbolic-symlub _ Symbolic = Symbolic-symlub Concrete Concrete = Concrete--sym_reg_transfer :: Reg ctx tp -> Assignment (Ignore SymDom) ctx -> SymDom-sym_reg_transfer reg asgn = ignoreOut $ asgn Ctx.! (regIndex reg)--sym_expr_transfer :: IsSyntaxExtension ext => Expr ext ctx tp -> Assignment (Ignore SymDom) ctx -> SymDom-sym_expr_transfer (App a) asgn-  = foldApp (\r z -> symlub z $ sym_reg_transfer r asgn) Dead a---- FIXME this whole shabang is bogus, and should be replace by something that works...--- we assume every function other than "matlabFunctionHandle" returns a symbolic--- output, but does not have control flow that depends on symbolic data...-sym_call_transfer-  :: CtxRepr args-  -> TypeRepr ret-  -> Reg ctx (FunctionHandleType args ret)-  -> Ignore SymDom (FunctionHandleType args ret)-  -> Assignment a args-  -> Ignore SymDom ret-sym_call_transfer _ _ ex _ _-  = Debug.trace (show $ pretty ex) $ Ignore Symbolic--symbolicAnalysis :: IsSyntaxExtension ext => KildallForward ext blocks (Ignore SymDom) SymDom-symbolicAnalysis =-  KildallForward-  { kfwd_lub = \(Ignore x) (Ignore y) -> Ignore (symlub x y)-  , kfwd_bot = Ignore Dead-  , kfwd_club = symlub-  , kfwd_cbot = Dead-  , kfwd_same = \(Ignore x) (Ignore y) -> x == y-  , kfwd_csame = \x y -> x == y-  , kfwd_br = \_ (Ignore x) y -> let z = symlub x y in (z, z)-  , kfwd_maybe = \_ _ (Ignore x) y -> let z = symlub x y in (z, Ignore x, z)-  , kfwd_reg  = \_ ex asgn -> Ignore $ sym_reg_transfer ex asgn-  , kfwd_expr = \_ ex asgn -> Ignore $ sym_expr_transfer ex asgn-  , kfwd_call = sym_call_transfer-  , kfwd_rdglobal = \_ -> Ignore Symbolic-             -- FIXME, here we make the totally pessimistic assumption-             -- that every global variable read is symbolic-  , kfwd_onentry = \_ x -> x-  }-----------------------data KildallPair (a::k -> Type) (c :: Type) (tp::k) = KP (a tp) c--instance (ShowF a, Show c) => Show (KildallPair a c tp) where-  show (KP x y) = "(" ++ showF x ++ ", " ++ show y ++ ")"--instance (ShowF a, Show c) => ShowF (KildallPair a c)--newtype Ignore a (b::k) = Ignore { ignoreOut :: a }- deriving (Eq, Ord)--instance Show a => Show (Ignore a tp) where-  show (Ignore x) = show x--instance Show a => ShowF (Ignore a)---data KildallForward ext blocks (a :: CrucibleType -> Type) c-  = KildallForward-    { kfwd_lub      :: forall tp. a tp -> a tp -> a tp-    , kfwd_bot      :: forall tp. a tp-    , kfwd_club     :: c -> c -> c-    , kfwd_cbot     :: c-    , kfwd_same     :: forall tp. a tp -> a tp -> Bool-    , kfwd_csame    :: c -> c -> Bool-    , kfwd_br       :: forall ctx. Reg ctx BoolType -> a BoolType -> c -> (c, c)-    , kfwd_maybe    :: forall ctx tp. TypeRepr tp -> Reg ctx (MaybeType tp) -> a (MaybeType tp) -> c -> (c, a tp, c)-    , kfwd_reg      :: !(forall ctx tp. TypeRepr tp -> Reg ctx tp  -> Assignment a ctx -> a tp)-    , kfwd_expr     :: !(forall ctx tp. TypeRepr tp -> Expr ext ctx tp -> Assignment a ctx -> a tp)-    , kfwd_call     :: forall ctx args ret. CtxRepr args-                                         -> TypeRepr ret-                                         -> Reg ctx (FunctionHandleType args ret)-                                         -> a (FunctionHandleType args ret)-                                         -> Assignment a args-                                         -> a ret-    , kfwd_rdglobal :: forall tp. GlobalVar tp -> a tp-    , kfwd_onentry  :: forall ctx. BlockID blocks ctx -> (Assignment a ctx, c) -> (Assignment a ctx, c)-    }--kildall_transfer-   :: forall ext a c blocks ret ctx-    . KildallForward ext blocks a c-   -> TypeRepr ret-   -> Block ext blocks ret ctx-   -> (Assignment a ctx, c)-   -> State (Assignment (KildallPair (Assignment a) c) blocks, a ret, c) (Set (Some (BlockID blocks)))-kildall_transfer analysis retRepr blk = transfer_seq (_blockStmts blk)- where transfer_seq :: forall ctx'-                     . StmtSeq ext blocks ret ctx'-                    -> (Assignment a ctx', c)-                    -> State (Assignment (KildallPair (Assignment a) c) blocks, a ret, c) (Set (Some (BlockID blocks)))--       transfer_seq (ConsStmt _loc stmt ss) x = transfer_seq ss (transfer_stmt stmt x)-       transfer_seq (TermStmt _loc term) x = transfer_term term x--       transfer_stmt :: forall ctx1 ctx2. Stmt ext ctx1 ctx2 -> (Assignment a ctx1, c) -> (Assignment a ctx2, c)-       transfer_stmt (SetReg tp ex) (asgn, c) = (Ctx.extend asgn (kfwd_expr analysis tp ex asgn), c)-       transfer_stmt (CallHandle rettp ex argstp actuals) (asgn, c) =-           let xs = Ctx.zipWith (\tp act -> kfwd_reg analysis tp act asgn) argstp actuals-               ex_sh = kfwd_reg analysis (FunctionHandleRepr argstp rettp) ex asgn-               a' = kfwd_call analysis argstp rettp ex ex_sh xs-            in (Ctx.extend asgn a', c)-       transfer_stmt (Print _) asgn = asgn-       transfer_stmt (ReadGlobal gv) (asgn, c) = (Ctx.extend asgn (kfwd_rdglobal analysis gv), c)-       transfer_stmt FreshConstant{} _ = error "forward dataflow: fresh constant!"-       transfer_stmt FreshFloat{} _ = error "forward dataflow: fresh float!"-       transfer_stmt FreshNat{} _ = error "forward dataflow: fresh nat!"-       transfer_stmt ExtendAssign{} _ = error "extension statement!"-       transfer_stmt NewRefCell{} _ = error "forward dataflow: reference cell!"-       transfer_stmt NewEmptyRefCell{} _ = error "forward dataflow: reference cell!"-       transfer_stmt ReadRefCell{} _ = error "forward dataflow: reference cell!"-       transfer_stmt WriteRefCell{} _ = error "forward dataflow: reference cell!"-       transfer_stmt DropRefCell{} _ = error "forward dataflow: reference cell!"-       transfer_stmt (WriteGlobal _ _) asgnc = asgnc -- FIXME? need to check something here, perhaps?-       transfer_stmt (Assert _ _) asgnc = asgnc -- FIXME? is it useful to remember assertions some way?-       transfer_stmt (Assume _ _) asgnc = asgnc -- FIXME? is it useful to remember assertions some way?--       transfer_term :: forall ctx'-                      . TermStmt blocks ret ctx'-                     -> (Assignment a ctx', c)-                     -> State (Assignment (KildallPair (Assignment a) c) blocks, a ret, c) (Set (Some (BlockID blocks)))--       transfer_term (ErrorStmt _) _ = return Set.empty--       transfer_term (Jump tgt) x = transfer_jump tgt x--       transfer_term (Br ex tgt1 tgt2) (asgn,c) = do-           let a = kfwd_reg analysis knownRepr ex asgn-           let (c1,c2) = kfwd_br analysis ex a c-           s1 <- transfer_jump tgt1 (asgn,c1)-           s2 <- transfer_jump tgt2 (asgn,c2)-           return (Set.union s1 s2)--       transfer_term (Return ex) (asgn, c) = do-           let a = kfwd_reg analysis retRepr ex asgn-           modify (\ (x,r,rc) -> (x, kfwd_lub analysis r a, kfwd_club analysis rc c))-           return Set.empty--       transfer_term (TailCall fn callargs actuals) (asgn, c) = do-           let xs = Ctx.zipWith (\tp act -> kfwd_reg analysis tp act asgn) callargs actuals-           let fn_sh = kfwd_reg analysis (FunctionHandleRepr callargs retRepr) fn asgn-           let a' = kfwd_call analysis callargs retRepr fn fn_sh xs-           modify (\ (x,r,rc) -> (x, kfwd_lub analysis r a', kfwd_club analysis rc c))-           return Set.empty--       transfer_term (MaybeBranch tp ex swtgt jmptgt) (asgn, c) = do-           let a = kfwd_reg analysis (MaybeRepr tp) ex asgn-           let (c1, a1, c2) = kfwd_maybe analysis tp ex a c-           s1 <- transfer_switch swtgt a1 (asgn, c1)-           s2 <- transfer_jump jmptgt (asgn, c2)-           return (Set.union s1 s2)--       transfer_term (VariantElim _ctx _ex _switch) (_asgn, _c) = do-           error "FIXME: transfer_term for VariantElim not implemented"--       transfer_switch :: forall ctx' tp-                        . SwitchTarget blocks ctx' tp-                       -> a tp-                       -> (Assignment a ctx', c)-                       -> State (Assignment (KildallPair (Assignment a) c) blocks, a ret, c) (Set (Some (BlockID blocks)))-       transfer_switch (SwitchTarget tgt argstp actuals) a1 (asgn, c) = do-           let xs = Ctx.zipWith (\tp act -> kfwd_reg analysis tp act asgn) argstp actuals-           let xs' = Ctx.extend xs a1-           transfer_target tgt (xs', c)--       transfer_jump :: forall ctx'-                      . JumpTarget blocks ctx'-                     -> (Assignment a ctx', c)-                     -> State (Assignment (KildallPair (Assignment a) c) blocks, a ret, c) (Set (Some (BlockID blocks)))--       transfer_jump (JumpTarget tgt argstp actuals) (asgn, c) = do-           let xs = Ctx.zipWith (\tp act -> kfwd_reg analysis tp act asgn) argstp actuals-           transfer_target tgt (xs, c)--       transfer_target :: forall ctx'-                        . BlockID blocks ctx'-                       -> (Assignment a ctx', c)-                       -> State (Assignment (KildallPair (Assignment a) c) blocks, a ret, c) (Set (Some (BlockID blocks)))-       transfer_target tgt@(BlockID idx) (asgn, c) = do-           (x,r,rc) <- get-           let KP old oldc = x Ctx.! idx-           let new = Ctx.zipWith (\a b -> kfwd_lub analysis a b) old asgn-           let zipsame = Ctx.zipWith (\a b -> Ignore $ kfwd_same analysis a b) old new-           let samex = foldlFC (\a (Ignore b) -> a && b) True zipsame-           let newc = kfwd_club analysis c oldc-           let same = samex && kfwd_csame analysis oldc newc-           if same-               then return Set.empty-               else do put (x & ixF idx .~ KP new newc, r, rc)-                       return (Set.singleton (Some tgt))----kildall_forward-  :: forall ext a c blocks ret init-   . KildallForward ext blocks a c-  -> CFG ext blocks init ret-  -> (Assignment a init, c)-  -> (Assignment (KildallPair (Assignment a) c) blocks, a ret, c)-kildall_forward analysis cfg (asgn0,c0) =-    let initblk@(BlockID idx) = cfgEntryBlockID cfg--        freshAsgn :: Ctx.Index blocks ctx -> Assignment a ctx-        freshAsgn i = fmapFC (\_ -> kfwd_bot analysis)-                             (blockInputs (getBlock (BlockID i) (cfgBlockMap cfg)))--     in execState (loop (Set.singleton (Some initblk)))-                  ( Ctx.generate (Ctx.size (cfgBlockMap cfg)) $ \i ->-                      case testEquality i idx of-                        Just Refl -> KP asgn0 c0-                        Nothing -> KP (freshAsgn i) (kfwd_cbot analysis)-                  , kfwd_bot analysis-                  , kfwd_cbot analysis-                  )--  where visit :: Block ext blocks ret ctx-              -> (Assignment a ctx, c)-              -> Set (Some (BlockID blocks))-              -> State (Assignment (KildallPair (Assignment a) c) blocks, a ret, c) ()-        visit blk start worklist = do-            s <- kildall_transfer analysis (cfgReturnType cfg) blk start-            loop (Set.union s worklist)--        loop worklist =-           case Set.minView worklist of-              Nothing -> return ()-              Just (Some tgt@(BlockID idx), worklist') ->-                  do (x,_,_) <- get-                     let (KP a c) = x Ctx.! idx-                         (a',c') = kfwd_onentry analysis tgt (a,c)-                     visit (getBlock tgt (cfgBlockMap cfg)) (a',c') worklist'
src/Lang/Crucible/Analysis/Postdom.hs view
@@ -15,7 +15,7 @@ {-# LANGUAGE TupleSections #-} module Lang.Crucible.Analysis.Postdom   ( postdomInfo-  , breakpointPostdomInfo+  , cutpointPostdomInfo   , validatePostdom   ) where @@ -49,12 +49,12 @@     Just l -> (\(Some n) -> toNode n `reverseEdge` b) <$> l  inEdgeGraph :: BlockMap ext blocks ret -> [Some (BlockID blocks)] -> G.UGr-inEdgeGraph m breakpointIds = G.mkGraph ((,()) <$> nodes) edges+inEdgeGraph m cutpointIds = G.mkGraph ((,()) <$> nodes) edges   where nodes = 0 : toListFC (toNode . blockID) m         cfgEdges = foldMapFC inEdges m-        breakpointEdges = map (\(Some bid) -> reverseEdge 0 (getBlock bid m))-                              breakpointIds-        edges = cfgEdges ++ breakpointEdges+        cutpointEdges = map (\(Some bid) -> reverseEdge 0 (getBlock bid m))+                              cutpointIds+        edges = cfgEdges ++ cutpointEdges  -- | Return subgraph of nodes reachable from given node. reachableSubgraph :: G.Node -> G.UGr -> G.UGr@@ -76,8 +76,8 @@             . BlockMap ext blocks ret            -> [Some (BlockID blocks)]            -> Map (Some (BlockID blocks)) [Some (BlockID blocks)]-postdomMap m breakpointIds = r-  where g0 = inEdgeGraph m breakpointIds+postdomMap m cutpointIds = r+  where g0 = inEdgeGraph m cutpointIds         g = reachableSubgraph 0 g0          idMap = nodeToBlockIDMap m@@ -98,8 +98,8 @@                    . BlockMap ext blocks ret                   -> [Some (BlockID blocks)]                   -> CFGPostdom blocks-postdomAssignment m breakpointIds = fmapFC go m-  where pd = postdomMap m breakpointIds+postdomAssignment m cutpointIds = fmapFC go m+  where pd = postdomMap m cutpointIds         go :: Block ext blocks ret c -> Const [Some (BlockID blocks)] c         go b = Const $ fromMaybe [] (Map.lookup (Some (blockID b)) pd) @@ -107,9 +107,9 @@ postdomInfo :: CFG ext b i r -> CFGPostdom b postdomInfo g = postdomAssignment (cfgBlockMap g) [] -breakpointPostdomInfo :: CFG ext b i r -> [BreakpointName] -> CFGPostdom b-breakpointPostdomInfo g breakpointNames = postdomAssignment (cfgBlockMap g) $-  mapMaybe (\nm -> Bimap.lookup nm (cfgBreakpoints g)) breakpointNames+cutpointPostdomInfo :: CFG ext b i r -> [CutpointName] -> CFGPostdom b+cutpointPostdomInfo g cutpointNames = postdomAssignment (cfgBlockMap g) $+  mapMaybe (\nm -> Bimap.lookup nm (cfgCutpoints g)) cutpointNames  blockEndsWithError :: Block ext blocks ret args -> Bool blockEndsWithError b =
src/Lang/Crucible/Analysis/Reachable.hs view
@@ -98,7 +98,7 @@ exploreReachable' _ [] r = r exploreReachable' m (Some h:l) r =   case Map.lookup (Some h) r of-    Just c -> exploreReachable' m l (Map.insert (Some h) (c+1) r)+    Just c -> exploreReachable' m l (Map.insert (Some h) (c + 1) r)     Nothing -> do       let b = getBlock h m       exploreReachable' m (nextBlocks b ++ l) (Map.insert (Some h) 1 r)@@ -119,11 +119,11 @@                  SomeCFG g'         where oldToNew = mkOldMap newToOld               new_map = remapBlockMap oldToNew newToOld-              new_breakpoints = Bimap.mapR (mapSome $ remapBlockID oldToNew) (cfgBreakpoints g)+              new_cutpoints = Bimap.mapR (mapSome $ remapBlockID oldToNew) (cfgCutpoints g)               g' = CFG { cfgHandle = cfgHandle g                        , cfgBlockMap = new_map                        , cfgEntryBlockID = remapBlockID oldToNew entry_id-                       , cfgBreakpoints = new_breakpoints+                       , cfgCutpoints = new_cutpoints                        }   where old_map = cfgBlockMap g         entry_id = cfgEntryBlockID g
src/Lang/Crucible/Backend.hs view
@@ -85,13 +85,13 @@   ) where  import           Control.Exception(Exception(..), throwIO)-import           Control.Lens ((^.)) import           Control.Monad import           Control.Monad.IO.Class import           Data.Foldable (toList) import           Data.Set (Set)-import qualified Prettyprinter as PP import           GHC.Stack+import           Lens.Micro ((^.))+import qualified Prettyprinter as PP  import           Data.Parameterized.Map (MapF) @@ -318,6 +318,12 @@   -- In contrast to 'saveAssumptionState', this also includes the goals.   getBackendState :: bak -> IO (AssumptionState sym) +  -- | An additional exception context for more detailed SimErrors+  getExceptionContext :: bak -> Maybe ProgramStack++  -- | Make a backend just like this but with a different error context+  withExceptionContext :: bak -> ProgramStack -> bak + assertThenAssumeConfigOption :: ConfigOption BaseBoolType assertThenAssumeConfigOption = configOption knownRepr "assertThenAssume" @@ -375,7 +381,8 @@ assert bak p msg =   do let sym = backendGetSym bak      loc <- getCurrentProgramLoc sym-     addAssertion bak (LabeledPred p (SimError loc msg))+     let ctx = getExceptionContext bak+     addAssertion bak (LabeledPred p (mkSimError loc msg ctx))  -- | Add a proof obligation for False. This always aborts execution -- of the current path, because after asserting false, we get to assume it,@@ -385,7 +392,8 @@ addFailedAssertion bak msg =   do let sym = backendGetSym bak      loc <- getCurrentProgramLoc sym-     let err = SimError loc msg+     let ctx = getExceptionContext bak+     let err = mkSimError loc msg ctx      addProofObligation bak (LabeledPred (falsePred sym) err)      abortExecBecause (AssertionFailure err) @@ -424,7 +432,8 @@ readPartExpr bak (PE p v) msg = do   let sym = backendGetSym bak   loc <- getCurrentProgramLoc sym-  addAssertion bak (LabeledPred p (SimError loc msg))+  let ctx = getExceptionContext bak+  addAssertion bak (LabeledPred p (mkSimError loc msg ctx))   return v  @@ -496,7 +505,7 @@   ppGl =    PP.indent 2 $-   PP.vsep [ppSimError (gl^.labeledPredMsg), printSymExpr (gl^.labeledPred)]+   PP.vsep [ppSimError (gl ^. labeledPredMsg), printSymExpr (gl ^. labeledPred)]  -- | Pretty-printer for 'AssumptionState'. ppAssumptionState ::
src/Lang/Crucible/Backend/AssumptionStack.hs view
@@ -176,7 +176,7 @@     case gcPop gc of       Left (ident', _assumes, mg, gc1)         | ident == ident' -> (gc',n)-        | otherwise -> go (n+1) gc'+        | otherwise -> go (n + 1) gc'        where gc' = case mg of                      Nothing -> gc1                      Just g  -> gcAddGoals g gc1
src/Lang/Crucible/Backend/Assumptions.hs view
@@ -46,14 +46,14 @@   ) where  -import           Control.Lens (Traversal, folded) import           Data.Kind (Type) import qualified Data.Foldable as F-import           Data.Functor.Identity import           Data.Functor.Const+import           Data.Functor.Identity import qualified Data.Parameterized.TraversableF as TF-import qualified Data.Sequence as Seq import           Data.Sequence (Seq)+import qualified Data.Sequence as Seq+import           Lens.Micro (Traversal, folded) import qualified Prettyprinter as PP  import           What4.Expr.Builder
src/Lang/Crucible/Backend/Online.hs view
@@ -78,20 +78,19 @@   , withSTPOnlineBackend   ) where -import           Control.Lens ( (^.) ) import           Control.Monad-import           Control.Monad.Fix (mfix) import           Control.Monad.Catch+import           Control.Monad.Fix (mfix) import           Control.Monad.IO.Class import           Data.Bits import           Data.Data (Data) import           Data.Foldable import           Data.IORef-import           Data.Typeable (Typeable)-import           GHC.Generics (Generic)-import           System.IO import qualified Data.Text as Text+import           GHC.Generics (Generic)+import           Lens.Micro ((^.)) import qualified Prettyprinter as PP+import           System.IO  import           What4.Config import           What4.Concrete@@ -184,6 +183,8 @@     -- ^ action for checking if online features are currently enabled    , onlineExprBuilder :: B.ExprBuilder scope st fs++  , onlineExceptionContext :: !(Maybe ProgramStack)   }  newOnlineBackend ::@@ -209,6 +210,7 @@                    , currentFeatures = featref                    , onlineEnabled = getOpt enableOpt                    , onlineExprBuilder = sym+                   , onlineExceptionContext = Nothing                    }  -- | Do something with an online backend.@@ -433,6 +435,9 @@    getBackendState bak = readIORef (AS.proofObligations (assumptionStack bak)) +  getExceptionContext = onlineExceptionContext+  withExceptionContext bak ec = bak { onlineExceptionContext = Just ec }+ -------------------------------------------------------------------------------- -- Branch satisfiability @@ -450,7 +455,7 @@      -- | The context before considering the given predicate was already      --   unsatisfiable.    | UnsatisfiableContext-   deriving (Data, Eq, Generic, Ord, Typeable)+   deriving (Data, Eq, Generic, Ord)  considerSatisfiability ::   OnlineSolver solver =>
src/Lang/Crucible/Backend/Prove.hs view
@@ -73,11 +73,11 @@   , proveCurrentObligations   ) where -import           Control.Lens ((^.)) import           Control.Monad.Catch (MonadMask) import           Control.Monad.Error.Class (MonadError, liftEither) import           Control.Monad.IO.Class (MonadIO(liftIO)) import qualified Control.Monad.Reader as Reader+import           Lens.Micro ((^.))  import qualified What4.Interface as W4 import qualified What4.Expr as WE@@ -111,19 +111,21 @@ consumeGoalsWithAssumptions ::   forall asmp goal a.   Monoid asmp =>-  -- | Consume a 'Prove'+  -- | What to do at 'Assuming' nodes (e.g., call 'proverAssume')+  (asmp -> a -> a) ->+  -- | Consume a 'Prove' with accumulated assumptions   (asmp -> goal -> a) ->   -- | Consume a 'ProveConj'   (a -> a -> a) ->   CB.Goals asmp goal ->   a-consumeGoalsWithAssumptions onGoal onConj goals =+consumeGoalsWithAssumptions onAssumption onGoal onConj goals =   Reader.runReader (go goals) mempty   where   go :: CB.Goals asmp goal -> Reader.Reader asmp a   go =     consumeGoals-      (\asmp gl -> Reader.local (<> asmp) gl)+      (\asmp gl -> onAssumption asmp <$> Reader.local (<> asmp) gl)       (\gl -> Reader.asks (\asmps -> onGoal asmps gl))       (\g1 g2 -> onConj <$> g1 <*> g2) @@ -255,6 +257,44 @@ --------------------------------------------------------------------- -- *** Offline +-- | Check if a goal is trivially true without calling the solver.+--+-- Returns a @Right@ with proof result if the goal is trivially true, or+-- @Left (asmps and not goal)@ if consulting the solver is needed. See the+-- module-level Haddock for intepreting @asmps and not goal@.+--+-- We don't optimize trivially false goals because we need the solver to provide+-- concrete counterexample values ('WE.GroundEvalFn') for debugging and error+-- reporting.+--+-- You might wonder if this is redundant with e.g., the check in @Backend@'s+-- @addProofObligation@ or with 'Crucible.Backend.Assumption.trivialAssumption'.+-- It is not. Consider a situation with fresh booleans @p@ and @q@ and+-- assumptions @p@ and @not p@ and goal @q@. What4's simplifications allow us+-- to conclude that the conjunction of the assumptions and the negation of the+-- goal is trivially unsatisfiable, even though each assumption and the goal are+-- individually nontrivial.+checkTrivialGoal ::+  W4.IsSymExprBuilder sym =>+  sym ->+  Assumptions sym ->+  CB.Assertion sym ->+  ProofConsumer sym t r ->+  IO (Either (W4.Pred sym) (SubgoalResult r))+checkTrivialGoal sym asmps goal (ProofConsumer k) = do+  -- See module Haddock for intepreting (asmps and not goal)+  asmpsPred <- CB.assumptionsPred sym asmps+  notGoal <- W4.notPred sym (goal ^. CB.labeledPred)+  asmpsAndNotGoal <- W4.andPred sym asmpsPred notGoal++  case W4.asConstantPred asmpsAndNotGoal of+    Just False ->  -- false = definitely unsat = proved+      let r' = Proved in+      Right <$> (SubgoalResult (isProved r') <$> k (CB.ProofGoal asmps goal) r')+    _ ->+      -- return this so that offlineProve doesn't need to re-compute it+      pure (Left asmpsAndNotGoal)+ -- Not exported offlineProveIO ::   (sym ~ WE.ExprBuilder t st fs) =>@@ -266,17 +306,18 @@   CB.Assertion sym ->   ProofConsumer sym t r ->   IO (SubgoalResult r)-offlineProveIO sym ld adapter asmps goal (ProofConsumer k) = do-  let goalPred = goal ^. CB.labeledPred-  asmsPred <- CB.assumptionsPred sym asmps-  notGoal <- W4.notPred sym goalPred-  WSA.solver_adapter_check_sat adapter sym ld [asmsPred, notGoal] $ \r ->-    let r' =-          case r of-            W4R.Sat (gfn, binds) -> Disproved gfn binds-            W4R.Unsat () -> Proved-            W4R.Unknown -> Unknown-    in SubgoalResult (isProved r') <$> k (CB.ProofGoal asmps goal) r'+offlineProveIO sym ld adapter asmps goal k@(ProofConsumer kFn) =+  checkTrivialGoal sym asmps goal k >>=+    \case+      Right result -> pure result+      Left asmpsAndNotGoal ->+        WSA.solver_adapter_check_sat adapter sym ld [asmpsAndNotGoal] $ \r ->+          let r' =+                case r of+                  W4R.Sat (gfn, binds) -> Disproved gfn binds+                  W4R.Unsat () -> Proved+                  W4R.Unknown -> Unknown+          in SubgoalResult (isProved r') <$> kFn (CB.ProofGoal asmps goal) r'  -- | Prove a goal using an \"offline\" solver (i.e., one process per goal). --@@ -353,19 +394,27 @@   W4SMT.SMTReadWriter solver =>   (sym ~ WE.ExprBuilder t st fs) =>   W4.IsSymExprBuilder sym =>+  sym ->   WPO.SolverProcess t solver ->   Assumptions sym ->   CB.Assertion sym ->   ProofConsumer sym t r ->   m (SubgoalResult r)-onlineProve sProc asmps goal (ProofConsumer k) =-  liftIO $ WPO.checkSatisfiableWithModel sProc "prove" (goal ^. CB.labeledPred) $ \r ->-    let r' =-          case r of-            W4R.Sat gfn -> Disproved gfn Nothing-            W4R.Unsat () -> Proved-            W4R.Unknown -> Unknown-    in SubgoalResult (isProved r') <$> k (CB.ProofGoal asmps goal) r'+onlineProve sym sProc asmps goal k@(ProofConsumer kFn) =+  liftIO (checkTrivialGoal sym asmps goal k) >>=+    \case+      Right result -> pure result+      Left _ -> liftIO $ do+        -- Note: assumptions are established via proverAssume before this is called+        let goalPred = goal ^. CB.labeledPred+        notGoal <- W4.notPred sym goalPred+        WPO.checkSatisfiableWithModel sProc "prove" notGoal $ \r ->+          let r' =+                case r of+                  W4R.Sat gfn -> Disproved gfn Nothing+                  W4R.Unsat () -> Proved+                  W4R.Unknown -> Unknown+          in SubgoalResult (isProved r') <$> kFn (CB.ProofGoal asmps goal) r'  -- | Add an assumption by @push@ing a new frame ('WPO.inNewFrame'). onlineAssume :: @@ -404,7 +453,7 @@   Prover sym m t r onlineProver sym sProc =   Prover-  { proverProve = onlineProve sProc+  { proverProve = onlineProve sym sProc   , proverAssume = onlineAssume sym sProc   } @@ -421,6 +470,7 @@ proveGoals (ProofStrategy prover (Combiner comb)) goals k =   fmap subgoalResult $     consumeGoalsWithAssumptions+      (proverAssume prover)       (\asmps gl -> proverProve prover asmps gl k)       comb       goals
src/Lang/Crucible/Backend/Simple.hs view
@@ -30,9 +30,9 @@   , B.Flags   ) where -import           Control.Lens ( (^.) ) import           Control.Monad (void) import           Data.IORef (readIORef)+import           Lens.Micro ((^.))  import           What4.Config import           What4.Interface@@ -56,8 +56,10 @@   SimpleBackend   { sbAssumptionStack :: AS t   , sbExprBuilder :: B.ExprBuilder t st fs+  , sbExceptionContext :: Maybe ProgramStack   } + newSimpleBackend ::   B.ExprBuilder t st fs ->   IO (SimpleBackend t st fs)@@ -67,6 +69,7 @@      return SimpleBackend             { sbAssumptionStack = as             , sbExprBuilder = sym+            , sbExceptionContext = Nothing             }  instance HasSymInterface (B.ExprBuilder t st fs) (SimpleBackend t st fs) where@@ -114,3 +117,6 @@     AS.restoreAssumptionStack newstk (sbAssumptionStack bak)    getBackendState bak = readIORef (AS.proofObligations (sbAssumptionStack bak))++  withExceptionContext bak ec = bak { sbExceptionContext = Just ec }+  getExceptionContext = sbExceptionContext
src/Lang/Crucible/CFG/Common.hs view
@@ -15,7 +15,7 @@   ( -- * Global variables     GlobalVar(..)   , freshGlobalVar-  , BreakpointName(..)+  , CutpointName(..)   ) where  import           Data.Text (Text)@@ -65,8 +65,8 @@          , globalType  = tp          } -newtype BreakpointName = BreakpointName { breakpointNameText :: Text }+newtype CutpointName = CutpointName { cutpointNameText :: Text }   deriving (Eq, Ord, Show) -instance Pretty BreakpointName where-  pretty = pretty . breakpointNameText+instance Pretty CutpointName where+  pretty = pretty . cutpointNameText
src/Lang/Crucible/CFG/Core.hs view
@@ -91,7 +91,6 @@   ) where  import Control.Applicative-import Control.Lens import Data.Bimap (Bimap) import Data.Maybe (fromMaybe) import Data.Kind (Type)@@ -100,6 +99,7 @@ import Data.Parameterized.Some import Data.Parameterized.TraversableFC import Data.String+import Lens.Micro ((^.), Lens', lens) import Prettyprinter  import What4.ProgramLoc@@ -673,19 +673,19 @@              -- ^ The sequence of statements in this block            } -blockStmts :: Simple Lens (Block ext b r c) (StmtSeq ext b r c)+blockStmts :: Lens' (Block ext b r c) (StmtSeq ext b r c) blockStmts = lens _blockStmts (\b s -> b { _blockStmts = s })  -- | Return location of start of block. blockLoc :: Block ext blocks ret ctx -> ProgramLoc-blockLoc b = firstStmtLoc (b^.blockStmts)+blockLoc b = firstStmtLoc (b ^. blockStmts)  -- | Get the terminal statement of a basic block.  This is implemented -- in a CPS style due to the block context. withBlockTermStmt :: Block ext blocks ret args                   -> (forall ctx . ProgramLoc -> TermStmt blocks ret ctx -> r)                   -> r-withBlockTermStmt b f = getConst (stmtSeqTermStmt (Const . uncurry f) (b^.blockStmts))+withBlockTermStmt b f = getConst (stmtSeqTermStmt (Const . uncurry f) (b ^. blockStmts))  nextBlocks :: Block ext b r a -> [Some (BlockID b)] nextBlocks b =@@ -709,7 +709,7 @@            -- ^ Block to print.         -> Doc ann ppBlock ppLineNumbers ppBlockArgs mPda b = do-  let stmts = ppStmtSeq ppLineNumbers (blockInputCount b) (b^.blockStmts)+  let stmts = ppStmtSeq ppLineNumbers (blockInputCount b) (b ^. blockStmts)   let mPostdom = flip fmap mPda $ \ pda ->         let Const pd = pda ! blockIDIndex (blockID b)         in if Prelude.null pd@@ -781,7 +781,7 @@    = CFG { cfgHandle :: FnHandle init ret          , cfgBlockMap :: !(BlockMap ext blocks ret)          , cfgEntryBlockID :: !(BlockID blocks init)-         , cfgBreakpoints :: !(Bimap BreakpointName (Some (BlockID blocks)))+         , cfgCutpoints :: !(Bimap CutpointName (Some (BlockID blocks)))          }  cfgArgTypes :: CFG ext blocks init ret -> CtxRepr init
src/Lang/Crucible/CFG/EarlyMergeLoops.hs view
@@ -56,7 +56,7 @@  import           Lang.Crucible.CFG.Expr import           Lang.Crucible.CFG.Reg-import           Lang.Crucible.Panic+import           Lang.Crucible.Panic (panic) import           Lang.Crucible.Types  --------------------------@@ -342,7 +342,7 @@    Print {}       -> orig    Assert {}      -> orig    Assume {}      -> orig-   Breakpoint {}  -> orig+   Cut {}         -> orig    where     orig = pure (Seq.fromList [st])@@ -380,7 +380,7 @@     Print {}       -> lowerAtomReads ng pvals atomsToLower st     Assert {}      -> lowerAtomReads ng pvals atomsToLower st     Assume {}      -> lowerAtomReads ng pvals atomsToLower st-    Breakpoint {}  -> lowerAtomReads ng pvals atomsToLower st+    Cut {}         -> lowerAtomReads ng pvals atomsToLower st   where     atomsToLower :: [Some (Atom s)]     atomsToLower = Set.toList (foldStmtInputs addIfLowered (pos_val st) mempty)@@ -758,7 +758,7 @@           | Just Refl <- testEquality (lambdaId ll) (lambdaId l1) -> Output l1 (lambdaAtom l2)         (_, _:rest) -> bidToTerm origOut rest         _ ->-          error "Output blocks mismatched in routePaths"+          panic "routePaths" ["Output blocks mismatched"]        mkMapping = Ctx.generateM sz $ \idx ->       do n <- freshNonce ng
src/Lang/Crucible/CFG/Expr.hs view
@@ -402,6 +402,11 @@     -> !RoundingMode     -> !(f (FloatType fi'))     -> App ext f (FloatType fi)+  FloatRound+    :: !(FloatInfoRepr fi)+    -> !RoundingMode+    -> !(f (FloatType fi))+    -> App ext f (FloatType fi)   FloatFromBinary     :: !(FloatInfoRepr fi)     -> !(f (BVType (FloatInfoToBitWidth fi)))@@ -530,6 +535,11 @@                  -> !(f (SequenceType tp))                  -> App ext f (MaybeType (StructType (EmptyCtx ::> tp ::> SequenceType tp))) +  -- Reverse a sequence+  SequenceReverse :: !(TypeRepr tp)+                  -> !(f (SequenceType tp))+                  -> App ext f (SequenceType tp)+   ----------------------------------------------------------------------   -- Vector @@ -577,7 +587,7 @@   -- Create a closure that captures the last argument.   Closure :: !(CtxRepr args)           -> !(TypeRepr ret)-          -> !(f (FunctionHandleType (args::>tp) ret))+          -> !(f (FunctionHandleType (args ::> tp) ret))           -> !(TypeRepr tp)           -> !(f tp)           -> App ext f (FunctionHandleType args ret)@@ -628,12 +638,12 @@   BVLit :: (1 <= w) => NatRepr w -> BV.BV w -> App ext f (BVType w)    -- concatenate two bitvectors-  BVConcat :: (1 <= u, 1 <= v, 1 <= u+v)+  BVConcat :: (1 <= u, 1 <= v, 1 <= u + v)            => !(NatRepr u)            -> !(NatRepr v)            -> !(f (BVType u))       -- Most significant bits            -> !(f (BVType v))       -- Least significant bits-           -> App ext f (BVType (u+v))+           -> App ext f (BVType (u + v))    -- BVSelect idx n bv chooses bits [idx, .. , idx+n-1] from bitvector bv.   -- The resulting bitvector will have width n.@@ -645,19 +655,19 @@            -> !(f (BVType w))            -> App ext f (BVType len) -  BVTrunc :: (1 <= r, r+1 <= w)+  BVTrunc :: (1 <= r, r + 1 <= w)           => !(NatRepr r)           -> !(NatRepr w)           -> !(f (BVType w))           -> App ext f (BVType r) -  BVZext :: (1 <= w, 1 <= r, w+1 <= r)+  BVZext :: (1 <= w, 1 <= r, w + 1 <= r)          => !(NatRepr r)          -> !(NatRepr w)          -> !(f (BVType w))          -> App ext f (BVType r) -  BVSext :: (1 <= w, 1 <= r, w+1 <= r)+  BVSext :: (1 <= w, 1 <= r, w + 1 <= r)          => !(NatRepr r)          -> !(NatRepr w)          -> !(f (BVType w))@@ -1176,6 +1186,7 @@     FloatFpApart{} -> knownRepr     FloatIte fi _ _ _ -> FloatRepr fi     FloatCast fi _ _ -> FloatRepr fi+    FloatRound fi _ _ -> FloatRepr fi     FloatFromBinary fi _ -> FloatRepr fi     FloatToBinary fi _ -> case floatInfoToBVTypeRepr fi of       BaseBVRepr w -> BVRepr w@@ -1227,6 +1238,7 @@       MaybeRepr (StructRepr (Ctx.Empty Ctx.:> tpr Ctx.:> SequenceRepr tpr))     SequenceLength{} -> knownRepr     SequenceTail tpr _ -> MaybeRepr (SequenceRepr tpr)+    SequenceReverse tpr _ -> SequenceRepr tpr      ----------------------------------------------------------------------     -- SymbolicArrayType
src/Lang/Crucible/CFG/ExtractSubgraph.hs view
@@ -17,19 +17,20 @@   ( extractSubgraph   ) where -import           Control.Lens import qualified Data.Bimap as Bimap import           Data.Parameterized.Context as Ctx import           Data.Parameterized.Map as MapF import           Data.Set as S import qualified Data.Map as Map import           Debug.Trace+import           Lens.Micro ((^.))  import           What4.FunctionName import           What4.ProgramLoc  import           Lang.Crucible.CFG.Core import           Lang.Crucible.FunctionHandle+import           Lang.Crucible.Panic (panic)  -- | Given a CFG @cfg@, a set of blocks @cuts@ that take the return type as their sole -- argument, and a block @bi@ that takes the CFG's init type as its sole argument,@@ -43,7 +44,7 @@                 -> BlockID blocks init                 -> HandleAllocator                 -> IO (Maybe (SomeCFG ext init ret))-extractSubgraph (CFG{cfgBlockMap = orig, cfgBreakpoints = breakpoints}) cuts bi halloc =+extractSubgraph (CFG{cfgBlockMap = orig, cfgCutpoints = cutpoints}) cuts bi halloc =   extractSubgraphFirst orig cuts MapF.empty zeroSize bi $     \(SubgraphIntermediate finalMap finalInitMap _sz entryID cb) -> do         hn <- mkHandle halloc startFunctionName@@ -53,9 +54,9 @@             { cfgBlockMap = bm             , cfgEntryBlockID = entryID             , cfgHandle = hn-            , cfgBreakpoints = Bimap.fromList $ Map.toList $+            , cfgCutpoints = Bimap.fromList $ Map.toList $                 Map.mapMaybe (viewSome $ \bid -> Some <$> MapF.lookup bid finalMap) $-                Bimap.toMap breakpoints+                Bimap.toMap cutpoints             }  -- | Type for carrying intermediate results through subraph extraction@@ -95,7 +96,7 @@             visitChildNode orig cuts bi1 sgi1               $ \sgi2 -> visitChildNode orig cuts bi2 sgi2 f           Return _ -> f-          _ -> error "extractSubgraph': unexpected case!")+          _ -> panic "extractSubgraph'" ["unexpected case!"])                 (SubgraphIntermediate                   (MapF.insert bi (BlockID $ nextIndex sz) (MapF.map extendBlockID mapF))                   (MapF.map extendBlockID initMap)@@ -126,7 +127,7 @@             visitChildNode orig cuts bi1 sgi1               $ \sgi2 -> visitChildNode orig cuts bi2 sgi2 f           Return _ -> f-          _ -> error "extractSubgraphFirst: unexpected case!")+          _ -> panic "extractSubgraphFirst" ["unexpected case!"])                 (SubgraphIntermediate                   (if case S.minView cuts of                       Just (bi', _) -> case testEquality (blockInputs block) (blockInputs $ orig Ctx.! blockIDIndex bi') of@@ -194,7 +195,7 @@ cloneBlock :: MapF (BlockID old) (BlockID new)            -> BlockID new ctx -> Block ext old ret ctx -> Maybe (Block ext new ret ctx) cloneBlock mapF newID b = do-  stmts' <- cloneStmtSeq mapF (b^.blockStmts)+  stmts' <- cloneStmtSeq mapF (b ^. blockStmts)   return Block{ blockID       = newID               , blockInputs   = blockInputs b               , _blockStmts   = stmts'@@ -215,7 +216,7 @@   jt2' <- cloneJumpTarget mapF jt2   return $ Br reg jt1' jt2' cloneTerm _mapF (Return reg) = Just $ Return reg-cloneTerm _ _ = error "cloneTerm: unexpected case!"+cloneTerm _ _ = panic "cloneTerm" ["unexpected case!"]  cloneJumpTarget :: MapF (BlockID blocks1) (BlockID blocks2)                 -> JumpTarget blocks1 t
src/Lang/Crucible/CFG/Generator.hs view
@@ -60,7 +60,7 @@   , assertExpr   , assumeExpr   , addPrintStmt-  , addBreakpointStmt+  , addCutStmt   , extensionStmt   , mkAtom   , mkFresh@@ -109,7 +109,6 @@   , module Lang.Crucible.CFG.EarlyMergeLoops   ) where -import           Control.Lens hiding (Index) import           Control.Monad ((>=>)) import qualified Control.Monad.Fail as F import           Control.Monad.IO.Class (MonadIO(..))@@ -117,6 +116,7 @@ import           Control.Monad.Trans.Class (MonadTrans(..)) import           Control.Monad.Catch import qualified Data.Foldable as Fold+import           Data.Function ((&)) import           Data.Kind import           Data.Parameterized.Context as Ctx import           Data.Parameterized.Nonce@@ -127,6 +127,8 @@ import qualified Data.Set as Set import           Data.Text (Text) import           Data.Void+import           Lens.Micro ((^.), (.~), (%~), Lens', Lens, SimpleGetter, lens, to)+import           Lens.Micro.Mtl (use, (.=), (%=))  import           What4.ProgramLoc import           What4.Symbol@@ -162,7 +164,7 @@       }  -- | Statements translated so far in this block.-cbsStmts :: Simple Lens (CurrentBlockState ext s) (StmtSeq ext s)+cbsStmts :: Lens' (CurrentBlockState ext s) (StmtSeq ext s) cbsStmts = lens _cbsStmts (\s v -> s { _cbsStmts = v })  ------------------------------------------------------------------------@@ -186,14 +188,14 @@   IxGeneratorState ext s t ret m ()  -- | Label for entry block.-gsEntryLabel :: Getter (IxGeneratorState ext s t ret m i) (Label s)+gsEntryLabel :: SimpleGetter (IxGeneratorState ext s t ret m i) (Label s) gsEntryLabel = to _gsEntryLabel  -- | List of previously processed blocks.-gsBlocks :: Simple Lens (IxGeneratorState ext s t ret m i) (Seq (Block ext s ret))+gsBlocks :: Lens' (IxGeneratorState ext s t ret m i) (Seq (Block ext s ret)) gsBlocks = lens _gsBlocks (\s v -> s { _gsBlocks = v }) -gsNonceGen :: Getter (IxGeneratorState ext s t ret m i) (NonceGenerator m s)+gsNonceGen :: SimpleGetter (IxGeneratorState ext s t ret m i) (NonceGenerator m s) gsNonceGen = to _gsNonceGen  -- | Information about current block.@@ -201,15 +203,15 @@ gsCurrent = lens _gsCurrent (\s v -> s { _gsCurrent = v })  -- | Current source position.-gsPosition :: Simple Lens (IxGeneratorState ext s t ret m i) Position+gsPosition :: Lens' (IxGeneratorState ext s t ret m i) Position gsPosition = lens _gsPosition (\s v -> s { _gsPosition = v })  -- | User state for current block. This gets reset between blocks.-gsState :: Simple Lens (IxGeneratorState ext s t ret m i) (t s)+gsState :: Lens' (IxGeneratorState ext s t ret m i) (t s) gsState = lens _gsState (\s v -> s { _gsState = v })  -- | List of functions seen by current generator.-seenFunctions :: Simple Lens (IxGeneratorState ext s t ret m i) [AnyCFG ext]+seenFunctions :: Lens' (IxGeneratorState ext s t ret m i) [AnyCFG ext] seenFunctions = lens _seenFunctions (\s v -> s { _seenFunctions = v })  ------------------------------------------------------------------------@@ -229,10 +231,10 @@   GeneratorState ext s t ret m ->   EndState ext s t ret m terminateBlock term gs =-  do let p = gs^.gsPosition-     let cbs = gs^.gsCurrent+  do let p = gs ^. gsPosition+     let cbs = gs ^. gsCurrent      -- Define block-     let b = mkBlock (cbsBlockID cbs) (cbsInputValues cbs) (cbs^.cbsStmts) (Posd p term)+     let b = mkBlock (cbsBlockID cbs) (cbsInputValues cbs) (cbs ^. cbsStmts) (Posd p term)      -- Store block      let gs' = gs & gsCurrent .~ ()                   & gsBlocks  %~ (Seq.|> b)@@ -455,13 +457,13 @@   do e_a <- mkAtom e      addStmt (Print e_a) --- | Add a breakpoint.-addBreakpointStmt ::+-- | Add a cutpoint.+addCutStmt ::   (Monad m, IsSyntaxExtension ext) =>-  Text {- ^ breakpoint name -} ->-  Assignment (Value s) args {- ^ breakpoint values -} ->+  Text {- ^ cutpoint name -} ->+  Assignment (Value s) args {- ^ cutpoint values -} ->   Generator ext s t r m ()-addBreakpointStmt nm args = addStmt $ Breakpoint (BreakpointName nm) args+addCutStmt nm args = addStmt $ Cut (CutpointName nm) args  -- | Add an assert statement. assertExpr ::@@ -565,8 +567,8 @@   do let gs1 = startBlock l (gs0 & gsCurrent .~ ())      gs2 <- runGenerator next gs1      -- Reset current block and state.-     let gs3 = gs2 & gsPosition .~ gs0^.gsPosition-                   & gsCurrent .~ gs0^.gsCurrent+     let gs3 = gs2 & gsPosition .~ gs0 ^. gsPosition+                   & gsCurrent .~ gs0 ^. gsCurrent      cont () gs3  -- | Define a block with an ordinary label.@@ -891,8 +893,8 @@                  -> CFG ext s init ret cfgFromGenerator h s =   CFG { cfgHandle = h-      , cfgEntryLabel = s^.gsEntryLabel-      , cfgBlocks = Fold.toList (s^.gsBlocks)+      , cfgEntryLabel = s ^. gsEntryLabel+      , cfgBlocks = Fold.toList (s ^. gsBlocks)       }  -- | Given the arguments, this returns the initial state, and an action for@@ -953,4 +955,4 @@               }   ts' <- runGenerator (action >>= returnFromFunction) $! ts   g   <- optPass ng (cfgFromGenerator h ts')-  return (SomeCFG g, ts'^.seenFunctions)+  return (SomeCFG g, ts' ^. seenFunctions)
src/Lang/Crucible/CFG/Reg.hs view
@@ -586,7 +586,7 @@    | Assert !(Atom s BoolType) !(Atom s (StringType Unicode))      -- | Assume the given expression.    | Assume !(Atom s BoolType) !(Atom s (StringType Unicode))-   | forall args . Breakpoint BreakpointName !(Assignment (Value s) args)+   | forall args . Cut CutpointName !(Assignment (Value s) args)  instance PrettyExt ext => Show (Stmt ext s) where   show = show . pretty@@ -602,7 +602,7 @@       Print  v   -> "print"  <+> pretty v       Assert c m -> "assert" <+> pretty c <+> pretty m       Assume c m -> "assume" <+> pretty c <+> pretty m-      Breakpoint nm args -> "breakpoint" <+> pretty nm <+> parens (commas (toListFC pretty args))+      Cut nm args -> "cut" <+> pretty nm <+> parens (commas (toListFC pretty args))  -- | Return local value assigned by this statement or @Nothing@ if this -- does not modify a register.@@ -617,7 +617,7 @@     Print{} -> Nothing     Assert{} -> Nothing     Assume{} -> Nothing-    Breakpoint{} -> Nothing+    Cut{} -> Nothing  -- | Fold all registers that are inputs tostmt. foldStmtInputs :: TraverseExt ext => (forall x . Value s x -> b -> b) -> Stmt ext s -> b -> b@@ -631,7 +631,7 @@     Print  e     -> f (AtomValue e) b     Assert c m   -> f (AtomValue c) (f (AtomValue m) b)     Assume c m   -> f (AtomValue c) (f (AtomValue m) b)-    Breakpoint _ args -> foldrFC' f b args+    Cut _ args   -> foldrFC' f b args  substStmt :: ( Applicative m, TraverseExt ext )           => (forall (x :: CrucibleType). Nonce s x -> m (Nonce s' x))@@ -647,7 +647,7 @@     Print e -> Print <$> substAtom f e     Assert c m -> Assert <$> substAtom f c <*> substAtom f m     Assume c m -> Assume <$> substAtom f c <*> substAtom f m-    Breakpoint nm args -> Breakpoint nm <$> traverseFC (substValue f) args+    Cut nm args -> Cut nm <$> traverseFC (substValue f) args  mapStmtAtom :: ( Applicative m, TraverseExt ext )           => (forall (x :: CrucibleType). Atom s x -> m (Atom s x))@@ -663,7 +663,7 @@     Print e -> Print <$> f e     Assert c m -> Assert <$> f c <*> f m     Assume c m -> Assume <$> f c <*> f m-    Breakpoint nm args -> Breakpoint nm <$> traverseFC (substValueAtom f) args+    Cut nm args -> Cut nm <$> traverseFC (substValueAtom f) args  substPosdStmt :: ( Applicative m, TraverseExt ext )               => (forall (x :: CrucibleType). Nonce s x -> m (Nonce s' x))@@ -922,7 +922,7 @@ cfgEntryBlock :: CFG ext s init ret -> Block ext s ret cfgEntryBlock g =   fromMaybe-    (error "Missing entry block")+    (panic "cfgEntryBlock" ["Missing entry block"])     (Fold.find (\b -> blockID b == LabelID (cfgEntryLabel g)) (cfgBlocks g))  cfgInputTypes :: CFG ext s init ret -> CtxRepr init
src/Lang/Crucible/CFG/SSAConversion.hs view
@@ -30,11 +30,11 @@   ) where  import           Control.Exception (assert)-import           Control.Lens ((&)) import           Control.Monad.State.Strict import           Data.Bimap (Bimap) import qualified Data.Bimap as Bimap import qualified Data.Foldable as Fold+import           Data.Function ((&)) import           Data.Map.Strict (Map) import qualified Data.Map.Strict as Map import           Data.Maybe (isJust, fromMaybe)@@ -129,11 +129,11 @@            , binputTerm       :: !(Posd (ExtendedTermStmt s blocks ret))            } --- The Breakpoint non-terminator statement becomes a jump during SSA conversion.--- This datatype temporarily adds breakpoint as a terminator statement.+-- The Cut non-terminator statement becomes a jump during SSA conversion.+-- This datatype temporarily adds cut as a terminator statement. data ExtendedTermStmt s blocks ret where   BaseTermStmt :: TermStmt s ret -> ExtendedTermStmt s blocks ret-  BreakStmt :: JumpInfo s blocks -> ExtendedTermStmt s blocks ret+  CutStmt :: JumpInfo s blocks -> ExtendedTermStmt s blocks ret  type BlockInputAssignment ext s blocks ret    = Assignment (BlockInput ext s blocks ret)@@ -144,21 +144,21 @@ extBlockInput ::   BlockInput ext s blocks ret args ->   BlockInput ext s (blocks ::> tp) ret arg-extBreakpoints ::-  Bimap BreakpointName (Some (C.BlockID blocks)) ->-  Bimap BreakpointName (Some (C.BlockID (blocks ::> tp)))+extCutpoints ::+  Bimap CutpointName (Some (C.BlockID blocks)) ->+  Bimap CutpointName (Some (C.BlockID (blocks ::> tp))) #ifdef UNSAFE_OPS extBlockInputAssignment = unsafeCoerce  extBlockInput = unsafeCoerce -extBreakpoints = unsafeCoerce+extCutpoints = unsafeCoerce #else extBlockInputAssignment = fmapFC extBlockInput  extBlockInput bi = bi { binputID = C.extendBlockID (binputID bi) } -extBreakpoints = Bimap.mapR (mapSome C.extendBlockID)+extCutpoints = Bimap.mapR (mapSome C.extendBlockID) #endif  ------------------------------------------------------------------------@@ -280,7 +280,7 @@       Just (SomeSwitchInfo tr si) -> Just $          case testEquality tr (typeOfAtom (lambdaAtom l)) of              Just Refl -> si-             Nothing   -> error "Lang.Crucible.SSAConversion.lookupSwitchInfo: type mismatch!"+             Nothing   -> panic "lookupSwitchInfo" ["type mismatch!"]  -- | Extend switch target extSwitchInfo :: SwitchInfo s blocks tp -> SwitchInfo s (blocks::>args) tp@@ -295,11 +295,11 @@   let blocks' = extBlockInputAssignment $ biBlocks bi   let jump_info' = extJumpInfoMap $ biJumpInfo bi   let switch_info' = extSwitchInfoMap $ biSwitchInfo bi-  let breakpoints' = extBreakpoints $ biBreakpoints bi+  let cutpoints' = extCutpoints $ biCutpoints bi   BI { biBlocks = extend blocks' binput      , biJumpInfo = jump_info'      , biSwitchInfo = switch_info'-     , biBreakpoints = breakpoints'+     , biCutpoints = cutpoints'      }  ------------------------------------------------------------------------@@ -393,7 +393,7 @@    = BI { biBlocks      :: !(Assignment (BlockInput ext s blocks ret) blocks)         , biJumpInfo    :: !(JumpInfoMap s blocks)         , biSwitchInfo  :: !(SwitchInfoMap s blocks)-        , biBreakpoints :: !(Bimap BreakpointName (Some (C.BlockID blocks)))+        , biCutpoints :: !(Bimap CutpointName (Some (C.BlockID blocks)))         }  -- | This infers the information given a set of blocks.@@ -403,7 +403,7 @@         bi0 = BI { biBlocks = empty                  , biJumpInfo = emptyJumpInfoMap                  , biSwitchInfo = emptySwitchInfoMap-                 , biBreakpoints = Bimap.empty+                 , biCutpoints = Bimap.empty                  }         resolveBlocks ::           BlockInfo ext s ret blocks ->@@ -432,7 +432,7 @@                   let bi' = extBlockInfo bi binput                   let ji = JumpInfo block_id crepr ra                   let bi'' = bi' { biJumpInfo = insertJumpInfo l ji (biJumpInfo bi') }-                  splitLastBlockInputOnBreakpoints bi'' rest+                  splitLastBlockInputOnCutpoints bi'' rest                 LambdaID l -> do                   let block_id = C.BlockID (nextIndex sz)                   let lastArg = AtomValue (lambdaAtom l)@@ -445,16 +445,16 @@                   let bi' = extBlockInfo bi binput                   let si = SwitchInfo block_id crepr ra                   let bi'' = bi' { biSwitchInfo = insertSwitchInfo l si (biSwitchInfo bi') }-                  splitLastBlockInputOnBreakpoints bi'' rest-        splitLastBlockInputOnBreakpoints ::+                  splitLastBlockInputOnCutpoints bi'' rest+        splitLastBlockInputOnCutpoints ::           BlockInfo ext s ret blocks ->           [Block ext s ret] ->           Some (BlockInfo ext s ret)-        splitLastBlockInputOnBreakpoints bi rest+        splitLastBlockInputOnCutpoints bi rest           | first_binputs :> last_binput <- biBlocks bi-          , (first_stmts, break_stmt Seq.:<| last_stmts) <--              Seq.breakl isBreakpoint (binputStmts last_binput)-          , Breakpoint nm args <- pos_val break_stmt = do+          , (first_stmts, cut_stmt Seq.:<| last_stmts) <-+              Seq.breakl isCut (binputStmts last_binput)+          , Cut nm args <- pos_val cut_stmt = do             let block_id = C.BlockID $ nextIndex $ size $ biBlocks bi              let first_binputs' = extBlockInputAssignment $ first_binputs@@ -462,7 +462,7 @@             let jump_info = JumpInfo block_id (fmapFC typeOfValue args) args             let last_binput' = (extBlockInput last_binput)                   { binputStmts = first_stmts-                  , binputTerm = break_stmt { pos_val = BreakStmt jump_info }+                  , binputTerm = cut_stmt { pos_val = CutStmt jump_info }                   }              let new_binput = (extBlockInput last_binput)@@ -471,23 +471,23 @@                   , binputStmts = last_stmts                   } -            let new_breakpoints = do-                  let try_new_breakpoints = Bimap.tryInsert nm (Some block_id) $-                        extBreakpoints $ biBreakpoints bi-                  if Bimap.pairMember (nm, (Some block_id)) try_new_breakpoints-                    then try_new_breakpoints-                    else error $ "Duplicate breakpoint: " ++ show nm+            let new_cutpoints = do+                  let try_new_cutpoints = Bimap.tryInsert nm (Some block_id) $+                        extCutpoints $ biCutpoints bi+                  if Bimap.pairMember (nm, (Some block_id)) try_new_cutpoints+                    then try_new_cutpoints+                    else error $ "Duplicate cutpoint: " ++ show nm             let bi' = BI                   { biBlocks = first_binputs' :> last_binput' :> new_binput                   , biJumpInfo = extJumpInfoMap $ biJumpInfo bi                   , biSwitchInfo = extSwitchInfoMap $ biSwitchInfo bi-                  , biBreakpoints = new_breakpoints+                  , biCutpoints = new_cutpoints                   }-            splitLastBlockInputOnBreakpoints bi' rest-        splitLastBlockInputOnBreakpoints bi rest = resolveBlocks bi rest-        isBreakpoint :: Posd (Stmt ext s) -> Bool-        isBreakpoint = \case-          Posd _ Breakpoint{} -> True+            splitLastBlockInputOnCutpoints bi' rest+        splitLastBlockInputOnCutpoints bi rest = resolveBlocks bi rest+        isCut :: Posd (Stmt ext s) -> Bool+        isCut = \case+          Posd _ Cut{} -> True           _ -> False  @@ -621,7 +621,7 @@                   -> C.JumpTarget blocks ctx resolveJumpTarget bi reg_map next_lbl = do   case lookupJumpInfo next_lbl (biJumpInfo bi) of-    Nothing -> error "Could not find label in resolveJumpTarget"+    Nothing -> panic "resolveJumpTarget" ["Could not find label"]     Just (JumpInfo next_id types inputs) -> do       let args = fmapFC (resolveReg reg_map) inputs       C.JumpTarget next_id types args@@ -634,7 +634,7 @@                     -> C.JumpTarget blocks ctx resolveLambdaAsJump bi reg_map next_lbl output =   case lookupSwitchInfo next_lbl (biSwitchInfo bi) of-    Nothing -> error "Could not find label in resolveLambdaAsJump"+    Nothing -> panic "resolveLambdaAsJump" ["Could not find label"]     Just (SwitchInfo block_id types inputs) -> do       let types' = types :> typeOfAtom (lambdaAtom next_lbl)       let args = fmapFC (resolveReg reg_map) inputs@@ -648,7 +648,7 @@                       -> C.SwitchTarget blocks ctx tp resolveLambdaAsSwitch bi reg_map next_lbl =   case lookupSwitchInfo next_lbl (biSwitchInfo bi) of-    Nothing -> error "Could not find label in resolveLambdaAsSwitch"+    Nothing -> panic "resolveLambdaAsSwitch" ["Could not find label"]     Just (SwitchInfo block_id types inputs) -> do       let args = fmapFC (resolveReg reg_map) inputs       C.SwitchTarget block_id types args@@ -695,7 +695,7 @@     ErrorStmt e -> C.ErrorStmt (resolveAtom reg_map e)      Output l e -> C.Jump (resolveLambdaAsJump bi reg_map l (resolveAtom reg_map e))-resolveTermStmt _ reg_map _ (BreakStmt (JumpInfo next_id types inputs)) = do+resolveTermStmt _ reg_map _ (CutStmt (JumpInfo next_id types inputs)) = do   let args = fmapFC (resolveReg reg_map) inputs   C.Jump $ C.JumpTarget next_id types args @@ -746,7 +746,7 @@      Nothing -> Nothing      Just (SomeReg tp r)         | Just Refl <- testEquality tp (C.appType app) -> Just r-     _ -> error "appRegMap_lookup: impossible!"+     _ -> panic "appRegMap_lookup" ["impossible!"]   appRegMap_empty :: AppRegMap ext ctx@@ -915,14 +915,14 @@                            (resolveAtom reg_map m))                  (resolveStmts nm bi sz reg_map bindings appMap rest t) -    -- breakpoint statements are eliminated during the inferBlockInfo phase-    Breakpoint{} -> error $-      "Unexpected breakpoint at position " ++ show p ++ ": " ++ show (Pretty.pretty s0)+    -- cut statements are eliminated during the inferBlockInfo phase+    Cut{} -> error $+      "Unexpected cut at position " ++ show p ++ ": " ++ show (Pretty.pretty s0)  data SomeBlockMap ext ret where   SomeBlockMap ::     Ctx.Index blocks tp ->-    Bimap BreakpointName (Some (C.BlockID blocks)) ->+    Bimap CutpointName (Some (C.BlockID blocks)) ->     C.BlockMap ext blocks ret ->     SomeBlockMap ext ret @@ -950,9 +950,9 @@   case inferBlockInfo blocks of     Some bi ->       case lookupJumpInfo entry (biJumpInfo bi) of-        Nothing -> error "Missing initial block."+        Nothing -> panic "resolveBlockMap" ["Missing initial block."]         Just (JumpInfo (C.BlockID idx) _ _) ->-          SomeBlockMap idx (biBreakpoints bi) $+          SomeBlockMap idx (biCutpoints bi) $             fmapFC (resolveBlock bi) (biBlocks bi)  ------------------------------------------------------------------------@@ -970,7 +970,7 @@   let entry = cfgEntryLabel g   let blocks = cfgBlocks g   case resolveBlockMap (handleName h) entry blocks of-    SomeBlockMap idx breakpoints block_map -> do+    SomeBlockMap idx cutpoints block_map -> do           let b = block_map ! idx           case C.blockInputs b `testEquality` initTypes of             Nothing -> error $@@ -981,6 +981,6 @@               let g' = C.CFG { C.cfgHandle = h                              , C.cfgBlockMap = block_map                              , C.cfgEntryBlockID = C.BlockID idx-                             , C.cfgBreakpoints = breakpoints+                             , C.cfgCutpoints = cutpoints                              }               reachableCFG g'
src/Lang/Crucible/Concretize.hs view
@@ -667,10 +667,11 @@                 pure (Const p)           let RM.RegMap mAssign = m           preds <- Ctx.zipWithM notEq concM mAssign+          -- not (modelA_1 == modelB_1) \/ ... \/ not (modelA_n == modelB_n)           p <-             foldlMFC-              (\p (Const p') -> W4I.andPred sym p p')-              (W4I.truePred sym)+              (\p (Const p') -> W4I.orPred sym p p')+              (W4I.falsePred sym)               preds            frm <- CB.pushAssumptionFrame bak
src/Lang/Crucible/FunctionHandle.hs view
@@ -195,7 +195,7 @@ -- FnHandleMap  data HandleElt (f :: Ctx CrucibleType -> CrucibleType -> Type) ctx where-  HandleElt :: FnHandle args ret -> f args ret -> HandleElt f (args::>ret)+  HandleElt :: FnHandle args ret -> f args ret -> HandleElt f (args ::> ret)  newtype FnHandleMap f = FnHandleMap (MapF (Nonce GlobalNonceGenerator) (HandleElt f)) 
src/Lang/Crucible/README.hs view
@@ -1,6 +1,7 @@ {- | This module is only for documentation purposes, and provides a high level overview of Crucible aimed at developers. -} {-# OPTIONS_GHC -Wno-unused-imports #-}+{-# OPTIONS_GHC -Wno-missing-export-lists #-} module Lang.Crucible.README where  import What4.Interface
src/Lang/Crucible/Simulator.hs view
@@ -87,11 +87,14 @@     -- ** SimContext record   , IsSymInterfaceProof   , SimContext(..)+  , ExceptionContextConfig(..)   , initSimContext   , ctxSymInterface   , functionBindings   , cruciblePersonality   , profilingMetrics+  , exceptionContextConfig+  , parseExceptionContextConfig      -- * SimState   , SimState
src/Lang/Crucible/Simulator/BoundedExec.hs view
@@ -30,8 +30,8 @@   ( boundedExecFeature   ) where -import           Control.Lens ( (^.), to, (&), (%~), (.~) ) import           Control.Monad ( when )+import           Data.Function ((&)) import           Data.IORef import           Data.Map (Map) import qualified Data.Map as Map@@ -40,7 +40,7 @@ import qualified Data.Sequence as Seq import qualified Data.Text as Text import           Data.Word-+import           Lens.Micro ((^.), to, (%~), (.~))  import qualified Data.Parameterized.Context as Ctx import qualified Data.Parameterized.Map as MapF@@ -82,13 +82,13 @@ buildWTOMap = snd . go 0 0 Map.empty  where  go :: Int -> Int -> Map Int (Int,Int) -> [WTOComponent (Some (BlockID blocks))] -> (Int, Map Int (Int,Int))- go !x !_ m [] = (x,m)- go !x !d m (Vertex (Some bid) : cs) =+ go !x !_ !m [] = (x,m)+ go x d m (Vertex (Some bid) : cs) =     let m' = Map.insert (Ctx.indexVal (blockIDIndex bid)) (x,d) m-     in go (x+1) d m' cs- go !x !d m (SCC scc : cs) =-    let m'  = viewSome (\hd -> Map.insert (Ctx.indexVal (blockIDIndex hd)) (x,d+1) m) (wtoHead scc)-        (x',m'') = go (x+1) (d+1) m' $ wtoComps scc+     in go (x + 1) d m' cs+ go x d m (SCC scc : cs) =+    let m'  = viewSome (\hd -> Map.insert (Ctx.indexVal (blockIDIndex hd)) (x,d + 1) m) (wtoHead scc)+        (x',m'') = go (x + 1) (d + 1) m' $ wtoComps scc      in go x' d m'' cs  @@ -100,8 +100,8 @@ incrementBoundCount cs depth =   case Seq.lookup depth cs of      Just n ->-       do let n' = n+1-          let cs' = Seq.update depth n' $ Seq.take (depth+1) cs+       do let n' = n + 1+          let cs' = Seq.update depth n' $ Seq.take (depth + 1) cs           n' `seq` cs' `seq` (cs', n')      Nothing ->        do let cs' = cs <> Seq.replicate (depth - Seq.length cs) 0 <> Seq.singleton 1@@ -236,7 +236,7 @@    SimState p sym ext rtp f args ->    ([Either FunctionName FrameBoundData] -> [Either FunctionName FrameBoundData]) ->    IO (ExecutionFeatureResult p sym ext rtp)- modifyStackState gvRef mkSt st f = do + modifyStackState gvRef mkSt st f = do     currGv <- readIORef gvRef     let err = panic "modifyStackState" ["Global variable not initialized"]     let gv = fromMaybe err currGv@@ -253,16 +253,15 @@    SimState p sym ext rtp (CrucibleLang blocks ret) ('Just a) ->    IO (ExecutionFeatureResult p sym ext rtp)  onTransition gvRef tgt_id res st = stateSolverProof st $-  do let sym = st^.stateSymInterface-     let simCtx = st^.stateContext-     (globals', overLimit) <- checkBackedge gvRef (st^.stateCrucibleFrame.frameBlockID) tgt_id (st^.stateGlobals)+  do let sym = st ^. stateSymInterface+     (globals', overLimit) <- checkBackedge gvRef (st ^. stateCrucibleFrame.frameBlockID) tgt_id (st ^. stateGlobals)      let st' = st & stateGlobals .~ globals'      case overLimit of        Just n ->          do let msg = "reached maximum number of loop iterations (" ++ show n ++ ")"-            let loc = st^.stateCrucibleFrame.to frameProgramLoc+            let loc = st ^. stateCrucibleFrame.to frameProgramLoc             let err = SimError loc (ResourceExhausted msg)-            when generateSideConditions $ withBackend simCtx $ \bak ->+            when generateSideConditions $ withStateBackend st $ \bak ->               addProofObligation bak (LabeledPred (falsePred sym) err)             return (ExecutionFeatureNewState (AbortState (AssertionFailure err) st'))        Nothing -> return (ExecutionFeatureModifiedState (ControlTransferState res st'))@@ -276,8 +275,8 @@    InitialState simctx globals ah ret cont ->      do let halloc = simHandleAllocator simctx         currGv <- readIORef gvRef-        ngv <- case currGv of -          Nothing -> do +        ngv <- case currGv of+          Nothing -> do             gv <- freshGlobalVar halloc (Text.pack "BoundedExecFrameData") knownRepr             writeIORef gvRef (Just gv)             pure gv
src/Lang/Crucible/Simulator/BoundedRecursion.hs view
@@ -32,13 +32,14 @@   ( boundedRecursionFeature   ) where -import           Control.Lens ( (^.), (&), (%~) ) import           Control.Monad (when)+import           Data.Function ((&)) import           Data.IORef+import qualified Data.Map.Strict as Map import           Data.Maybe import qualified Data.Text as Text import           Data.Word-import qualified Data.Map.Strict as Map+import           Lens.Micro ((^.), (%~))  import           Data.Parameterized.Ctx import qualified Data.Parameterized.Map as MapF@@ -109,26 +110,25 @@    SimState p sym ext rtp f args ->    IO (ExecutionFeatureResult p sym ext rtp)  pushFrame gvRef rebuildStack h mkSt st = stateSolverProof st $-     do let sym = st^.stateSymInterface-        let simCtx = st^.stateContext+     do let sym = st ^. stateSymInterface         currGv <- readIORef gvRef         let err = panic "pushFrame" ["Uninitialized global!"]         let gv = fromMaybe err currGv         case lookupGlobal gv (st ^. stateGlobals) of           Nothing -> panic "bounded recursion" ["global not defined!"]           Just [] -> panic "bounded recursion" ["empty stack!"]-          Just (x:xs) -> do +          Just (x:xs) -> do             mb <- getRecursionBound h             let v = 1 + fromMaybe 0 (Map.lookup h x)             case mb of-              Just b | v > b -> do +              Just b | v > b -> do                 loc <- getCurrentProgramLoc sym                 let msg = ("reached maximum number of recursive calls to function " ++ show h ++ " (" ++ show b ++ ")")                 let simerr = SimError loc (ResourceExhausted msg)-                when generateSideConditions $ withBackend simCtx $ \bak ->+                when generateSideConditions $ withStateBackend st $ \bak ->                   addProofObligation bak (LabeledPred (falsePred sym) simerr)                 return (ExecutionFeatureNewState (AbortState (AssertionFailure simerr) st))-              _ -> do +              _ -> do                 let x'  = Map.insert h v x                 let st' = st & stateGlobals %~ insertGlobal gv (rebuildStack x' x xs)                 x' `seq` return (ExecutionFeatureModifiedState (mkSt st'))@@ -143,9 +143,9 @@     InitialState simctx globals ah ret cont ->      do let halloc = simHandleAllocator simctx-        currGv <- readIORef gvRef -        gv <- case currGv of -          Just gv -> pure gv +        currGv <- readIORef gvRef+        gv <- case currGv of+          Just gv -> pure gv           Nothing -> do             gv <- freshGlobalVar halloc (Text.pack "BoundedRecursionData") knownRepr             writeIORef gvRef (Just gv)
− src/Lang/Crucible/Simulator/Breakpoint.hs
@@ -1,109 +0,0 @@--------------------------------------------------------------------------- |--- Module           : Lang.Crucible.Simulator.Breakpoint--- Description      : Support for symbolic execution breakpoints--- Copyright        : (c) Galois, Inc 2019--- License          : BSD3--- Maintainer       : Andrei Stefanescu <andrei@galois.com>--- Stability        : provisional------ This module provides execution features for changing the state on--- breakpoints.-------------------------------------------------------------------------{-# LANGUAGE GADTs #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE RecordWildCards #-}-module Lang.Crucible.Simulator.Breakpoint-  ( breakAndReturn-  ) where--import           Control.Lens-import           Control.Monad.Reader-import qualified Data.Bimap as Bimap-import           Data.HashMap.Strict (HashMap)-import qualified Data.HashMap.Strict as HashMap--import           Data.Parameterized.Classes-import qualified Data.Parameterized.Context as Ctx-import           Data.Parameterized.Some-import           Data.Parameterized.TraversableFC--import qualified Lang.Crucible.Backend as C-import qualified Lang.Crucible.CFG.Core as C-import qualified Lang.Crucible.CFG.Expr as C-import qualified Lang.Crucible.Simulator.CallFrame as C-import qualified Lang.Crucible.Simulator.EvalStmt as C-import qualified Lang.Crucible.Simulator.ExecutionTree as C-import qualified Lang.Crucible.Simulator.Operations as C-import qualified Lang.Crucible.Simulator.OverrideSim as C-import qualified Lang.Crucible.Simulator.RegValue as C-import qualified What4.FunctionName as W---- | This execution feature registers an override for a breakpoint.---   The override summarizes the execution from the breakpoint---   to the return from the function (similar to a tail call).---   This feature requires a map from each function handle---   to the list of breakpoints in the respective function with this---   execution feature.-breakAndReturn ::-  (C.IsSymInterface sym, C.IsSyntaxExtension ext) =>-  C.CFG ext blocks init ret ->-  C.BreakpointName ->-  Ctx.Assignment C.TypeRepr args ->-  C.TypeRepr ret ->-  C.OverrideSim p sym ext rtp args ret (C.RegValue sym ret) ->-  HashMap C.SomeHandle [C.BreakpointName] ->-  IO (C.ExecutionFeature p sym ext rtp)-breakAndReturn C.CFG{..} breakpoint_name arg_types ret_type override all_breakpoints =-  case Bimap.lookup breakpoint_name cfgBreakpoints of-    Just (Some breakpoint_block_id)-      | breakpoint_block <- C.getBlock breakpoint_block_id cfgBlockMap-      , Just Refl <- testEquality (C.blockInputs breakpoint_block) arg_types ->-        return $ C.ExecutionFeature $ \case-          C.RunningState (C.RunPostBranchMerge block_id) state-            | frame <- state ^. C.stateCrucibleFrame-            , C.SomeHandle cfgHandle == C.frameHandle frame-            , Just Refl <- testEquality-                (fmapFC C.blockInputs cfgBlockMap)-                (fmapFC C.blockInputs $ C.frameBlockMap frame)-            , Just Refl <- testEquality breakpoint_block_id block_id-            , Just Refl <- testEquality ret_type (C.frameReturnType frame) -> do-              let override_frame = C.OF $ C.OverrideFrame-                    { _override = W.functionNameFromText $-                        C.breakpointNameText breakpoint_name-                    , _overrideHandle = C.frameHandle frame-                    , _overrideRegMap = state ^.-                        C.stateCrucibleFrame . C.frameRegs-                    }-              result_state <- runReaderT (C.runOverrideSim ret_type override) $-                state & C.stateTree %~-                  C.pushCallFrame C.TailReturnToCrucible override_frame-              return $ C.ExecutionFeatureNewState result_state-          C.CallState return_handler (C.CrucibleCall block_id frame) state-            | Just breakpoints <- HashMap.lookup-                (C.frameHandle frame)-                all_breakpoints -> do-              let result_frame = C.setFrameBreakpointPostdomInfo-                    breakpoints-                    frame-              result_state <- runReaderT-                (C.performFunctionCall-                  return_handler-                  (C.CrucibleCall block_id result_frame))-                state-              return $ C.ExecutionFeatureNewState result_state-          C.TailCallState value_from_value (C.CrucibleCall block_id frame) state-            | Just breakpoints <- HashMap.lookup-                (C.frameHandle frame)-                all_breakpoints -> do-              let result_frame = C.setFrameBreakpointPostdomInfo-                    breakpoints-                    frame-              result_state <- runReaderT-                (C.performTailCall-                  value_from_value-                  (C.CrucibleCall block_id result_frame))-                state-              return $ C.ExecutionFeatureNewState result_state-          _ -> return C.ExecutionFeatureNoChange-    _ -> fail $ "unexpected breakpoint: " ++ show breakpoint_name
src/Lang/Crucible/Simulator/CallFrame.hs view
@@ -38,7 +38,7 @@   , framePostdom   , frameProgramLoc   , setFrameBlock-  , setFrameBreakpointPostdomInfo+  , setFrameCutpointPostdomInfo   , extendFrame   , updateFrame   , mergeCallFrame@@ -58,15 +58,17 @@   , fromCallFrame   , fromReturnFrame   , frameFunctionName+  , frameStackLoc   ) where -import           Control.Lens+import           Data.Functor.Const (getConst) import           Data.Kind import qualified Data.Parameterized.Context as Ctx+import           Lens.Micro ((^.), Lens', Lens, SimpleGetter, lens, to)  import           What4.FunctionName import           What4.Interface ( Pred )-import           What4.ProgramLoc ( ProgramLoc )+import           What4.ProgramLoc ( ProgramLoc, mkProgramLoc, Position(..) )  import           Lang.Crucible.Analysis.Postdom import           Lang.Crucible.CFG.Core@@ -129,22 +131,22 @@ frameReturnType :: CallFrame sym ext blocks ret ctx -> TypeRepr ret frameReturnType CallFrame { _frameCFG = g } = cfgReturnType g -framePostdomMap :: Simple Lens (CallFrame sym ext blocks ret ctx) (CFGPostdom blocks)+framePostdomMap :: Lens' (CallFrame sym ext blocks ret ctx) (CFGPostdom blocks) framePostdomMap = lens _framePostdomMap (\s x -> s{ _framePostdomMap = x }) -frameBlockID :: Simple Lens (CallFrame sym ext blocks ret ctx) (Some (BlockID blocks))+frameBlockID :: Lens' (CallFrame sym ext blocks ret ctx) (Some (BlockID blocks)) frameBlockID = lens _frameBlockID (\s v -> s { _frameBlockID = v })  -- | List of statements to execute next.-frameStmts :: Simple Lens (CallFrame sym ext blocks ret ctx) (StmtSeq ext blocks ret ctx)+frameStmts :: Lens' (CallFrame sym ext blocks ret ctx) (StmtSeq ext blocks ret ctx) frameStmts = lens _frameStmts (\s v -> s { _frameStmts = v }) {-# INLINE frameStmts #-} -frameRegs :: Simple Lens (CallFrame sym ext blocks ret args) (RegMap sym args)+frameRegs :: Lens' (CallFrame sym ext blocks ret args) (RegMap sym args) frameRegs = lens _frameRegs (\s v -> s { _frameRegs = v })  -- | List of statements to execute next.-framePostdom :: Simple Lens (CallFrame sym ext blocks ret ctx) (Some (CrucibleBranchTarget (CrucibleLang blocks ret)))+framePostdom :: Lens' (CallFrame sym ext blocks ret ctx) (Some (CrucibleBranchTarget (CrucibleLang blocks ret))) framePostdom = lens _framePostdom (\s v -> s { _framePostdom = v })  -- | Create a new call frame.@@ -171,7 +173,7 @@             , _framePostdomMap = pdInfo             , _frameBlockID  = Some bid             , _frameRegs     = args-            , _frameStmts    = b^.blockStmts+            , _frameStmts    = b ^. blockStmts             , _framePostdom  = mkFramePostdom pds             } @@ -182,7 +184,7 @@  -- | Return program location associated with frame. frameProgramLoc :: CallFrame sym ext blocks ret ctx -> ProgramLoc-frameProgramLoc cf = firstStmtLoc (cf^.frameStmts)+frameProgramLoc cf = firstStmtLoc (cf ^. frameStmts)  setFrameBlock :: BlockID blocks args               -> RegMap sym args@@ -190,20 +192,20 @@               -> CallFrame sym ext blocks ret args setFrameBlock bid@(BlockID block_id) args f = f'     where b = frameBlockMap f Ctx.! block_id-          pds = getConst $ (f^.framePostdomMap.ixF block_id)+          pds = getConst $ (f ^. framePostdomMap.ixF block_id)           f' = f { _frameBlockID = Some bid                  , _frameRegs =  args-                 , _frameStmts = b^.blockStmts+                 , _frameStmts = b ^. blockStmts                  , _framePostdom = mkFramePostdom pds                  } -setFrameBreakpointPostdomInfo ::-  [BreakpointName] ->+setFrameCutpointPostdomInfo ::+  [CutpointName] ->   CallFrame sym ext blocks ret ctx ->   CallFrame sym ext blocks ret ctx-setFrameBreakpointPostdomInfo breakpoints f = case f of+setFrameCutpointPostdomInfo cutpoints f = case f of   CallFrame{ _frameCFG = g, _frameBlockID = Some (BlockID block_id) } -> do-    let pdInfo = breakpointPostdomInfo g breakpoints+    let pdInfo = cutpointPostdomInfo g cutpoints     f { _framePostdomMap = pdInfo       , _framePostdom  = mkFramePostdom (getConst $ pdInfo Ctx.! block_id)       }@@ -257,10 +259,10 @@                      -- ^ Arguments to override.                    } -override :: Simple Lens (OverrideFrame sym ret args) FunctionName+override :: Lens' (OverrideFrame sym ret args) FunctionName override = lens _override (\o x -> o{ _override = x }) -overrideHandle :: Simple Lens (OverrideFrame sym ret args) SomeHandle+overrideHandle :: Lens' (OverrideFrame sym ret args) SomeHandle overrideHandle = lens _overrideHandle (\o x -> o { _overrideHandle = x })  overrideRegMap :: Lens (OverrideFrame sym ret args) (OverrideFrame sym ret args')@@ -323,8 +325,16 @@                 -> RegEntry sym (FrameRetType f) fromReturnFrame (RF _ x) = x -frameFunctionName :: Getter (SimFrame sym ext f a) FunctionName+frameFunctionName :: SimpleGetter (SimFrame sym ext f a) FunctionName frameFunctionName = to $ \case-  OF f -> f^.override+  OF f -> f ^. override   MF f -> case frameHandle f of SomeHandle h -> handleName h   RF n _ -> n++-- | Get a location for a stack frame, or Nothing if this is a return frame+frameStackLoc :: (SimFrame sym ext f a) -> Maybe ProgramLoc+frameStackLoc frame =+    case frame of+      sf@(OF _) -> Just $ mkProgramLoc (sf ^. frameFunctionName) InternalPos+      (MF f) -> Just $ frameProgramLoc f+      (RF _ _) -> Nothing
+ src/Lang/Crucible/Simulator/Cut.hs view
@@ -0,0 +1,110 @@+-----------------------------------------------------------------------+-- |+-- Module           : Lang.Crucible.Simulator.Cut+-- Description      : Support for symbolic execution cuts+-- Copyright        : (c) Galois, Inc 2019+-- License          : BSD3+-- Maintainer       : Andrei Stefanescu <andrei@galois.com>+-- Stability        : provisional+--+-- This module provides execution features for changing the state on+-- cutpoints.+-----------------------------------------------------------------------+{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE RecordWildCards #-}+module Lang.Crucible.Simulator.Cut+  ( cutAndReturn+  ) where++import           Control.Monad.Reader+import qualified Data.Bimap as Bimap+import           Data.Function ((&))+import           Data.HashMap.Strict (HashMap)+import qualified Data.HashMap.Strict as HashMap+import           Lens.Micro ((^.), (%~))++import           Data.Parameterized.Classes+import qualified Data.Parameterized.Context as Ctx+import           Data.Parameterized.Some+import           Data.Parameterized.TraversableFC++import qualified Lang.Crucible.Backend as C+import qualified Lang.Crucible.CFG.Core as C+import qualified Lang.Crucible.CFG.Expr as C+import qualified Lang.Crucible.Simulator.CallFrame as C+import qualified Lang.Crucible.Simulator.EvalStmt as C+import qualified Lang.Crucible.Simulator.ExecutionTree as C+import qualified Lang.Crucible.Simulator.Operations as C+import qualified Lang.Crucible.Simulator.OverrideSim as C+import qualified Lang.Crucible.Simulator.RegValue as C+import qualified What4.FunctionName as W++-- | This execution feature registers an override for a cutpoint.+--   The override summarizes the execution from the cutpoint+--   to the return from the function (similar to a tail call).+--   This feature requires a map from each function handle+--   to the list of cutpoints in the respective function with this+--   execution feature.+cutAndReturn ::+  (C.IsSymInterface sym, C.IsSyntaxExtension ext) =>+  C.CFG ext blocks init ret ->+  C.CutpointName ->+  Ctx.Assignment C.TypeRepr args ->+  C.TypeRepr ret ->+  C.OverrideSim p sym ext rtp args ret (C.RegValue sym ret) ->+  HashMap C.SomeHandle [C.CutpointName] ->+  IO (C.ExecutionFeature p sym ext rtp)+cutAndReturn C.CFG{..} cutpoint_name arg_types ret_type override all_cutpoints =+  case Bimap.lookup cutpoint_name cfgCutpoints of+    Just (Some cutpoint_block_id)+      | cutpoint_block <- C.getBlock cutpoint_block_id cfgBlockMap+      , Just Refl <- testEquality (C.blockInputs cutpoint_block) arg_types ->+        return $ C.ExecutionFeature $ \case+          C.RunningState (C.RunPostBranchMerge block_id) state+            | frame <- state ^. C.stateCrucibleFrame+            , C.SomeHandle cfgHandle == C.frameHandle frame+            , Just Refl <- testEquality+                (fmapFC C.blockInputs cfgBlockMap)+                (fmapFC C.blockInputs $ C.frameBlockMap frame)+            , Just Refl <- testEquality cutpoint_block_id block_id+            , Just Refl <- testEquality ret_type (C.frameReturnType frame) -> do+              let override_frame = C.OF $ C.OverrideFrame+                    { _override = W.functionNameFromText $+                        C.cutpointNameText cutpoint_name+                    , _overrideHandle = C.frameHandle frame+                    , _overrideRegMap = state ^.+                        C.stateCrucibleFrame . C.frameRegs+                    }+              result_state <- runReaderT (C.runOverrideSim ret_type override) $+                state & C.stateTree %~+                  C.pushCallFrame C.TailReturnToCrucible override_frame+              return $ C.ExecutionFeatureNewState result_state+          C.CallState return_handler (C.CrucibleCall block_id frame) state+            | Just cutpoints <- HashMap.lookup+                (C.frameHandle frame)+                all_cutpoints -> do+              let result_frame = C.setFrameCutpointPostdomInfo+                    cutpoints+                    frame+              result_state <- runReaderT+                (C.performFunctionCall+                  return_handler+                  (C.CrucibleCall block_id result_frame))+                state+              return $ C.ExecutionFeatureNewState result_state+          C.TailCallState value_from_value (C.CrucibleCall block_id frame) state+            | Just cutpoints <- HashMap.lookup+                (C.frameHandle frame)+                all_cutpoints -> do+              let result_frame = C.setFrameCutpointPostdomInfo+                    cutpoints+                    frame+              result_state <- runReaderT+                (C.performTailCall+                  value_from_value+                  (C.CrucibleCall block_id result_frame))+                state+              return $ C.ExecutionFeatureNewState result_state+          _ -> return C.ExecutionFeatureNoChange+    _ -> fail $ "unexpected cutpoint: " ++ show cutpoint_name
src/Lang/Crucible/Simulator/EvalStmt.hs view
@@ -45,15 +45,17 @@   ) where  import qualified Control.Exception as Ex-import           Control.Lens import           Control.Monad (foldM, when) import           Control.Monad.IO.Class (MonadIO(..))-import           Control.Monad.Reader (ReaderT(..), withReaderT)+import           Control.Monad.Reader (ReaderT(..), withReaderT, ask)+import           Data.Function ((&)) import           Data.Maybe (fromMaybe) import qualified Data.Parameterized.Context as Ctx import           Data.Parameterized.TraversableFC import qualified Data.Text as Text import           Data.Time.Clock+import           Lens.Micro ((^.), (.~), (%~), to)+import           Lens.Micro.Mtl (view) import           System.IO import           System.IO.Error as Ex import           Prettyprinter@@ -100,7 +102,7 @@   String ->   IO () evalLogFn verb s n msg = do-  let h = s^.stateContext.to printHandle+  let h = s ^. stateContext.to printHandle   if verb >= n then       do hPutStr h msg          hFlush h@@ -114,12 +116,11 @@   Expr ext ctx tp ->   ReaderT (CrucibleState p sym ext rtp blocks r ctx) IO (RegValue sym tp) evalExpr verb (App a) = ReaderT $ \s ->-  do let iteFns = s^.stateIntrinsicTypes-     let simCtx = s^.stateContext+  do let iteFns = s ^. stateIntrinsicTypes      let logFn = evalLogFn verb s-     r <- withBackend simCtx $ \bak ->+     r <- withStateBackend s $ \bak ->             evalApp bak iteFns logFn-              (extensionEval (extensionImpl (s^.stateContext)) bak iteFns logFn s)+              (extensionEval (extensionImpl (s ^. stateContext)) bak iteFns logFn s)               (\r -> runReaderT (evalReg r) s)               a      return $! r@@ -138,7 +139,7 @@   Monad m =>   Ctx.Assignment (Reg ctx) args ->   ReaderT (CrucibleState p sym ext rtp blocks r ctx) m (RegMap sym args)-evalArgs args = ReaderT $ \s -> return $! evalArgs' (s^.stateCrucibleFrame.frameRegs) args+evalArgs args = ReaderT $ \s -> return $! evalArgs' (s ^. stateCrucibleFrame.frameRegs) args {-# INLINE evalArgs #-}  -- | Resolve the arguments for a jump.@@ -207,8 +208,10 @@   StmtSeq ext blocks r ctx' {- ^ Remaining statements in the block -} ->   ExecCont p sym ext rtp (CrucibleLang blocks r) ('Just ctx) stepStmt verb stmt rest =-  do ctx <- view stateContext-     let sym = ctx^.ctxSymInterface++  do st <- ask+     ctx <- view stateContext+     let sym = ctx ^. ctxSymInterface      let iTypes = ctxIntrinsicTypes ctx      globals <- view (stateTree.actFrame.gpGlobals) @@ -217,7 +220,7 @@            ExecCont p sym ext rtp' f a          continueWith f = withReaderT f (checkConsTerm verb) -     withBackend ctx $ \bak ->+     withStateBackend st $ \bak ->        case stmt of          NewRefCell tpr x ->            do let halloc = simHandleAllocator ctx@@ -402,8 +405,8 @@  stepTerm _ (ErrorStmt msg) =   do msg' <- evalReg msg-     simCtx <- view stateContext-     withBackend simCtx $ \bak -> liftIO $+     st <- ask+     withStateBackend st $ \bak -> liftIO $        case asString msg' of          Just (UnicodeLiteral txt) ->                      addFailedAssertion bak@@ -421,9 +424,9 @@ checkConsTerm verb =      do cf <- view stateCrucibleFrame -        case cf^.frameStmts of+        case cf ^. frameStmts of           ConsStmt _ _ _ -> stepBasicBlock verb-          TermStmt _ _ -> continue (RunBlockEnd (cf^.frameBlockID))+          TermStmt _ _ -> continue (RunBlockEnd (cf ^. frameBlockID))  -- | Main evaluation operation for running a single step of --   basic block evaluation.@@ -435,15 +438,15 @@   ExecCont p sym ext rtp (CrucibleLang blocks r) ('Just ctx) stepBasicBlock verb =   do ctx <- view stateContext-     let sym = ctx^.ctxSymInterface+     let sym = ctx ^. ctxSymInterface      let h = printHandle ctx      cf <- view stateCrucibleFrame -     case cf^.frameStmts of+     case cf ^. frameStmts of        ConsStmt pl stmt rest ->          do liftIO $               do setCurrentProgramLoc sym pl-                 let sz = regMapSize (cf^.frameRegs)+                 let sz = regMapSize (cf ^. frameRegs)                  when (verb >= 4) $ ppStmtAndLoc h (frameHandle cf) pl (ppStmt sz stmt)             stepStmt verb stmt rest @@ -495,7 +498,7 @@          k cont st      AbortState rsn st ->-      let (AH handler) = st^.abortHandler in+      let (AH handler) = st ^. abortHandler in       k (handler rsn) st      OverrideState ovr st ->
src/Lang/Crucible/Simulator/Evaluation.hs view
@@ -35,14 +35,15 @@ import           Prelude hiding (pred)  import qualified Control.Exception as Ex-import           Control.Lens import           Control.Monad import qualified Data.BitVector.Sized as BV+import           Data.Function ((&)) import qualified Data.Map.Strict as Map import           Data.Maybe import qualified Data.Text as Text import qualified Data.Vector as V import           Data.Word+import           Lens.Micro ((.~)) import           Numeric ( showHex ) import           Numeric.Natural import           GHC.Stack@@ -80,7 +81,7 @@ -- Coercion functions  integerAsChar :: Integer -> Word16-integerAsChar i = fromInteger ((i `max` 0) `min` (2^(16::Int)-1))+integerAsChar i = fromInteger ((i `max` 0) `min` (2 ^ (16::Int)-1))  complexRealAsChar :: (MonadFail m, IsExpr val)                   => val BaseComplexType@@ -490,6 +491,8 @@       do xs' <- evalSub xs          mu <- unconsSymSequence sym (muxRegForType sym itefns tpr) xs'          traverse (\ (h,tl) -> pure (Ctx.Empty Ctx.:> RV h Ctx.:> RV tl)) mu+    SequenceReverse _tpr xs ->+      reverseSymSequence sym =<< evalSub xs      --------------------------------------------------------------------     -- Symbolic Arrays@@ -646,6 +649,8 @@       iFloatFpApart @_ @fi sym x y     FloatCast fi rm (x_expr :: f (FloatType fi')) ->       iFloatCast @_ @_ @fi' sym fi rm =<< evalSub x_expr+    FloatRound _ rm (x_expr :: f (FloatType fi)) ->+      iFloatRound @_ @fi sym rm =<< evalSub x_expr     FloatFromBinary fi x_expr -> iFloatFromBinary sym fi =<< evalSub x_expr     FloatToBinary fi x_expr -> iFloatToBinary sym fi =<< evalSub x_expr     FloatFromBV fi rm x_expr -> iBVToFloat sym fi rm =<< evalSub x_expr
src/Lang/Crucible/Simulator/ExecutionTree.hs view
@@ -116,12 +116,16 @@   , IsSymInterfaceProof   , SimContext(..)   , Metric(..)+  , ExceptionContextConfig(..)   , initSimContext   , withBackend+  , withStateBackend   , ctxSymInterface   , functionBindings   , cruciblePersonality   , profilingMetrics+  , exceptionContextConfig+  , parseExceptionContextConfig      -- * SimState   , SimState(..)@@ -143,18 +147,22 @@   , stateOverrideFrame   , stateGlobals   , stateConfiguration+  , stateProgramStack   ) where -import           Control.Lens import           Control.Monad.Reader+import           Data.Function ((&)) import           Data.Kind import           Data.Map.Strict (Map) import qualified Data.Map.Strict as Map+import           Data.Maybe(maybeToList) import           Data.Parameterized.Ctx import qualified Data.Parameterized.Context as Ctx import           Data.Text (Text)+import           Lens.Micro ((^.), (.~), Lens', Lens, SimpleGetter, Traversal', lens, to) import           System.Exit (ExitCode) import           System.IO+import           Text.Read(readMaybe) import qualified Prettyprinter as PP  import           What4.Config (Config)@@ -174,6 +182,7 @@ import           Lang.Crucible.Simulator.GlobalState (SymGlobalState) import           Lang.Crucible.Simulator.Intrinsics (IntrinsicTypes) import           Lang.Crucible.Simulator.RegMap (RegMap, emptyRegMap, RegValue, RegEntry)+import           Lang.Crucible.Simulator.SimError(ProgramStack(..)) import           Lang.Crucible.Types  ------------------------------------------------------------------------@@ -197,7 +206,7 @@ gpValue = lens _gpValue (\s v -> s { _gpValue = v })  -- | Access the globals stored in the global pair.-gpGlobals :: Simple Lens (GlobalPair sym u) (SymGlobalState sym)+gpGlobals :: Lens' (GlobalPair sym u) (SymGlobalState sym) gpGlobals = lens _gpGlobals (\s v -> s { _gpGlobals = v })  @@ -285,13 +294,13 @@ filterCrucibleFrames _ = Nothing  -- | Iterate over frames in the result.-arFrames :: Simple Traversal (AbortedResult sym ext) (SomeFrame (SimFrame sym ext))+arFrames :: Traversal' (AbortedResult sym ext) (SomeFrame (SimFrame sym ext)) arFrames h (AbortedExec e p) =   (\(SomeFrame f') -> AbortedExec e (p & gpValue .~ f'))-     <$> h (SomeFrame (p^.gpValue))+     <$> h (SomeFrame (p ^. gpValue)) arFrames h (AbortedExit ec p) =   (\(SomeFrame f') -> AbortedExit ec (p & gpValue .~ f'))-     <$> h (SomeFrame (p^.gpValue))+     <$> h (SomeFrame (p ^. gpValue)) arFrames h (AbortedBranch predicate loc r s) =   AbortedBranch predicate loc <$> arFrames h r                               <*> arFrames h s@@ -303,7 +312,7 @@  where    pp :: SomeFrame (SimFrame sym ext) -> PP.Doc ann    pp (SomeFrame (OF f)) =-      PP.pretty "When calling" PP.<+> PP.viaShow (f^.override)+      PP.pretty "When calling" PP.<+> PP.viaShow (f ^. override)    pp (SomeFrame (MF f)) =       PP.pretty "In" PP.<+> PP.viaShow (frameHandle f) PP.<+>       PP.pretty "at" PP.<+> PP.pretty (plSourceLoc (frameProgramLoc f))@@ -424,16 +433,16 @@ execStateContext :: ExecState p sym ext r -> SimContext p sym ext execStateContext = \case   ResultState res        -> execResultContext res-  AbortState _ st        -> st^.stateContext-  UnwindCallState _ _ st -> st^.stateContext-  CallState _ _ st       -> st^.stateContext-  TailCallState _ _ st   -> st^.stateContext-  ReturnState _ _ _ st   -> st^.stateContext-  ControlTransferState _ st -> st^.stateContext-  RunningState _ st      -> st^.stateContext-  SymbolicBranchState _ _ _ _ st -> st^.stateContext-  OverrideState _ st -> st^.stateContext-  BranchMergeState _ st -> st^.stateContext+  AbortState _ st        -> st ^. stateContext+  UnwindCallState _ _ st -> st ^. stateContext+  CallState _ _ st       -> st ^. stateContext+  TailCallState _ _ st   -> st ^. stateContext+  ReturnState _ _ _ st   -> st ^. stateContext+  ControlTransferState _ st -> st ^. stateContext+  RunningState _ st      -> st ^. stateContext+  SymbolicBranchState _ _ _ _ st -> st ^. stateContext+  OverrideState _ st -> st ^. stateContext+  BranchMergeState _ st -> st ^. stateContext   InitialState stctx _ _ _ _ -> stctx  setExecStateContext ::@@ -472,7 +481,7 @@  abortedGlobals ::   Monad f =>-  -- | How to handle 'AbortedBranch'.+  -- | How to handle branches (e.g., 'AbortedBranch', 'PartialRes').   --   -- Common options include concretizing the 'Pred' or returning a partial   -- result (e.g., 'Nothing').@@ -491,7 +500,7 @@ -- | Extract the 'SymGlobalState' from an 'ExecResult'. execResultGlobals ::   Monad f =>-  -- | How to handle 'AbortedBranch'.+  -- | How to handle branches (e.g., 'AbortedBranch', 'PartialRes').   --   -- Common options include concretizing the 'Pred' or returning a partial   -- result (e.g., 'Nothing').@@ -500,7 +509,13 @@   f (SymGlobalState sym) execResultGlobals handleBranch =   \case-    FinishedResult _ctx partial -> pure (partial ^. partialValue . gpGlobals)+    FinishedResult simCtx partial ->+      case partial of+        TotalRes gp -> pure (gp ^. gpGlobals)+        PartialRes loc p gp aborted -> do+          let l = gp ^. gpGlobals+          r <- abortedGlobals (handleBranch simCtx) aborted+          handleBranch simCtx loc p l r     TimeoutResult st -> execStateGlobals handleBranch st     AbortedResult simCtx aborted ->       abortedGlobals (handleBranch simCtx) aborted@@ -508,7 +523,7 @@ -- | Extract the 'SymGlobalState' from an 'ExecState'. execStateGlobals ::   Monad f =>-  -- | How to handle 'AbortedBranch'.+  -- | How to handle branches (e.g., 'AbortedBranch', 'PartialRes').   --   -- Common options include concretizing the 'Pred' or returning a partial   -- result (e.g., 'Nothing').@@ -1153,7 +1168,7 @@ activeFrames :: ActiveTree ctx sym ext root a args ->                 [SomeFrame (SimFrame sym ext)] activeFrames (ActiveTree ctx ar) =-  SomeFrame (ar^.partialValue^.gpValue) : parentFrames ctx+  SomeFrame (ar ^. partialValue ^. gpValue) : parentFrames ctx   ------------------------------------------------------------------------@@ -1265,6 +1280,24 @@     runMetric :: forall rtp f args. SimState p sym ext rtp f args -> IO Integer   } +data ExceptionContextConfig = +    ECCNone -- ^ do not include exceptions with context +  | ECCLimited Int+  | ECCNoLimit+  deriving(Eq, Ord, Show, Read)++parseExceptionContextConfig :: String -> Either String ExceptionContextConfig+parseExceptionContextConfig s =+  case s of+    "none" -> Right ECCNone+    "nolimit" -> Right ECCNoLimit+    _ | Just limit <- readMaybe s ->+      if limit > 0 +        then Right (ECCLimited limit)+        else Left "exception context frame limit cannot be 0 or less"+    _ -> Left "invalid exception context config - valid inputs are `none`, `nolimit`, and integers greater than 0"++ -- | Top-level state record for the simulator.  The state contained in this record --   remains persistent across all symbolic simulator actions.  In particular, it --   is not rolled back when the simulator returns previous program points to@@ -1277,19 +1310,20 @@ --   - @ext@: language extension, see "Lang.Crucible.CFG.Extension" type SimContext :: Type -> Type -> Type -> Type data SimContext p sym ext-   = SimContext { _ctxBackend            :: !(SomeBackend sym)+   = SimContext { _ctxBackend                :: !(SomeBackend sym)                   -- | Class dictionary for @'IsSymInterface' sym@-                , ctxSolverProof         :: !(forall a . IsSymInterfaceProof sym a)-                , ctxIntrinsicTypes      :: !(IntrinsicTypes sym)+                , ctxSolverProof             :: !(forall a . IsSymInterfaceProof sym a)+                , ctxIntrinsicTypes          :: !(IntrinsicTypes sym)                   -- | Allocator for function handles-                , simHandleAllocator     :: !(HandleAllocator)+                , simHandleAllocator         :: !(HandleAllocator)                   -- | Handle to write messages to.-                , printHandle            :: !Handle-                , extensionImpl          :: ExtensionImpl p sym ext-                , _functionBindings      :: !(FunctionBindings p sym ext)+                , printHandle                :: !Handle+                , extensionImpl              :: ExtensionImpl p sym ext+                , _functionBindings          :: !(FunctionBindings p sym ext)                   -- | See 'cruciblePersonality'.-                , _cruciblePersonality   :: !p-                , _profilingMetrics      :: !(Map Text (Metric p sym ext))+                , _cruciblePersonality       :: !p+                , _profilingMetrics          :: !(Map Text (Metric p sym ext))+                , _exceptionContextConfig    :: ExceptionContextConfig                 }  -- | Create a new 'SimContext' with the given bindings.@@ -1304,15 +1338,16 @@   personality {- ^ Initial value for custom user state -} ->   SimContext personality sym ext initSimContext bak muxFns halloc h bindings extImpl personality =-  SimContext { _ctxBackend          = SomeBackend bak-             , ctxSolverProof       = \a -> a-             , ctxIntrinsicTypes    = muxFns-             , simHandleAllocator   = halloc-             , printHandle          = h-             , extensionImpl        = extImpl-             , _functionBindings    = bindings-             , _cruciblePersonality = personality-             , _profilingMetrics    = Map.empty+  SimContext { _ctxBackend               = SomeBackend bak+             , ctxSolverProof            = \a -> a+             , ctxIntrinsicTypes         = muxFns+             , simHandleAllocator        = halloc+             , printHandle               = h+             , extensionImpl             = extImpl+             , _functionBindings         = bindings+             , _cruciblePersonality      = personality+             , _profilingMetrics         = Map.empty+             , _exceptionContextConfig   = ECCNone              }  withBackend ::@@ -1321,8 +1356,27 @@   a withBackend ctx f = case _ctxBackend ctx of SomeBackend bak -> f bak +-- | Get a backend from a SimState and populate the error context+-- from the current simulation state.  This differs from `withBackend`+-- because it can use the dynamic state of the simulator for things+-- like getting stack traces for exceptions and should be preferred+-- to `withBackend` where it is possible to use.+withStateBackend ::+  SimState p sym ext rtp f args ->+    (forall bak. IsSymBackend sym bak => bak -> a) -> a+withStateBackend st f = +  if shouldHaveContext then +    let ec = stateProgramStack st+    in withBackend (st ^. stateContext) $ \bak ->+        f (withExceptionContext bak ec)+  else +    withBackend (st ^. stateContext) f+  where+    shouldHaveContext = +      st ^. stateContext . exceptionContextConfig /= ECCNone+     -- | Access the symbolic backend inside a 'SimContext'.-ctxSymInterface :: Getter (SimContext p sym ext) sym+ctxSymInterface :: SimpleGetter (SimContext p sym ext) sym ctxSymInterface = to (\ctx ->   case _ctxBackend ctx of     SomeBackend bak -> backendGetSym bak)@@ -1361,6 +1415,9 @@ profilingMetrics :: Lens' (SimContext p sym ext) (Map Text (Metric p sym ext)) profilingMetrics = lens _profilingMetrics (\s v -> s { _profilingMetrics = v }) +exceptionContextConfig :: Lens' (SimContext p sym ext) ExceptionContextConfig+exceptionContextConfig = lens _exceptionContextConfig (\s v -> s { _exceptionContextConfig = v })+ ------------------------------------------------------------------------ -- SimState @@ -1436,23 +1493,23 @@        }  -stateLocation :: Getter (SimState p sym ext r f a) (Maybe ProgramLoc)+stateLocation :: SimpleGetter (SimState p sym ext r f a) (Maybe ProgramLoc) stateLocation = to f  where  f :: SimState p sym ext r f a -> Maybe ProgramLoc- f st = case st^.stateTree . actFrame . gpValue of+ f st = case st ^. stateTree . actFrame . gpValue of           MF cf -> Just $! (frameProgramLoc cf)           OF _ -> Nothing           RF _ _ -> Nothing   -- | Access the 'SimContext' inside a 'SimState'-stateContext :: Simple Lens (SimState p sym ext r f a) (SimContext p sym ext)+stateContext :: Lens' (SimState p sym ext r f a) (SimContext p sym ext) stateContext = lens _stateContext (\s v -> s { _stateContext = v }) {-# INLINE stateContext #-}  -- | Access the current abort handler of a state.-abortHandler :: Simple Lens (SimState p sym ext r f a) (AbortHandler p sym ext r)+abortHandler :: Lens' (SimState p sym ext r f a) (AbortHandler p sym ext r) abortHandler = lens _abortHandler (\s v -> s { _abortHandler = v })  -- | Access the active tree associated with a state.@@ -1483,21 +1540,49 @@ stateOverrideFrame = stateTree . actFrame . gpValue . overrideSimFrame  -- | Access the globals inside a 'SimState'-stateGlobals :: Simple Lens (SimState p sym ext q f args) (SymGlobalState sym)+stateGlobals :: Lens' (SimState p sym ext q f args) (SymGlobalState sym) stateGlobals = stateTree . actFrame . gpGlobals  -- | Get the symbolic interface out of a 'SimState'-stateSymInterface :: Getter (SimState p sym ext r f a) sym+stateSymInterface :: SimpleGetter (SimState p sym ext r f a) sym stateSymInterface = stateContext . ctxSymInterface  -- | Get the intrinsic type map out of a 'SimState'-stateIntrinsicTypes :: Getter (SimState p sym ext r f args) (IntrinsicTypes sym)+stateIntrinsicTypes :: SimpleGetter (SimState p sym ext r f args) (IntrinsicTypes sym) stateIntrinsicTypes = stateContext . to ctxIntrinsicTypes  -- | Get the configuration object out of a 'SimState'-stateConfiguration :: Getter (SimState p sym ext r f args) Config-stateConfiguration = to (\s -> stateSolverProof s (getConfiguration (s^.stateSymInterface)))+stateConfiguration :: SimpleGetter (SimState p sym ext r f args) Config+stateConfiguration = to (\s -> stateSolverProof s (getConfiguration (s ^. stateSymInterface)))  -- | Provide the 'IsSymInterface' typeclass dictionary from a 'SimState' stateSolverProof :: SimState p sym ext r f args -> (forall a . IsSymInterfaceProof sym a)-stateSolverProof s = ctxSolverProof (s^.stateContext)+stateSolverProof s = ctxSolverProof (s ^. stateContext)++-- | Get the program stack from a SimState+stateProgramStack :: SimState p sym ext r f args -> ProgramStack+stateProgramStack st = +  ProgramStack+    { psFrameOmitCount = length omitted+    , psFrames = relevantFrames+    }+  where+         +    (relevantFrames, omitted) = +      case eccConfig of+        ECCNoLimit -> (rawFrames, [])+        ECCLimited limit -> splitAt limit rawFrames+        ECCNone -> ([],[])++    eccConfig = st ^. stateContext . exceptionContextConfig++    isStartFrame (SomeFrame (OF frm)) = (frm ^. override) == startFunctionName +    isStartFrame _ = False+    removeStartFrame [] = []+    removeStartFrame [f] | isStartFrame f = []+    removeStartFrame (h:t) = h:removeStartFrame t++    rawFrames = +        [ loc | SomeFrame sf <- removeStartFrame $ activeFrames (st ^. stateTree) +        , loc <- maybeToList (frameStackLoc sf)+        ]
src/Lang/Crucible/Simulator/Operations.hs view
@@ -76,17 +76,19 @@ import Prelude hiding (pred)  import qualified Control.Exception as Ex-import           Control.Lens import           Control.Monad (when, void) import           Control.Monad.IO.Class (MonadIO(..))-import           Control.Monad.Reader (ReaderT(..), withReaderT)+import           Control.Monad.Reader (ReaderT(..), ask, withReaderT) import           Control.Monad.Trans.Class (MonadTrans(..))-import           Data.Maybe (fromMaybe)+import           Data.Function ((&)) import           Data.List (isPrefixOf)+import           Data.Maybe (fromMaybe) import qualified Data.Parameterized.Context as Ctx import           Data.Parameterized.Some-import qualified Data.Vector as V import           Data.Type.Equality hiding (sym)+import qualified Data.Vector as V+import           Lens.Micro ((^.), (.~), (%~), _2, to, traverseOf)+import           Lens.Micro.Mtl (view) import           System.IO import qualified Prettyprinter as PP @@ -116,8 +118,8 @@   MuxFn p (SymGlobalState sym) ->   MuxFn p (GlobalPair sym v) mergeGlobalPair merge_fn global_fn c x y =-  GlobalPair <$> merge_fn  c (x^.gpValue) (y^.gpValue)-             <*> global_fn c (x^.gpGlobals) (y^.gpGlobals)+  GlobalPair <$> merge_fn  c (x ^. gpValue) (y ^. gpValue)+             <*> global_fn c (x ^. gpGlobals) (y ^. gpGlobals)  mergeAbortedResult ::   ProgramLoc {- ^ Program location of control-flow branching -} ->@@ -156,12 +158,12 @@     BlockTarget _b_id -> do       let x = fromCallFrame x0       let y = fromCallFrame y0-      z <- mergeRegs sym muxFns p (x^.frameRegs) (y^.frameRegs)+      z <- mergeRegs sym muxFns p (x ^. frameRegs) (y ^. frameRegs)       pure $! MF (x & frameRegs .~ z)     ReturnTarget -> do       let x = fromReturnFrame x0       let y = fromReturnFrame y0-      RF (x0^.frameFunctionName) <$> muxRegEntry sym muxFns p x y+      RF (x0 ^. frameFunctionName) <$> muxRegEntry sym muxFns p x y   mergePartialResult ::@@ -170,8 +172,8 @@   CrucibleBranchTarget f args ->   MuxFn (Pred sym) (PartialResultFrame sym ext f args) mergePartialResult s tgt pred x y =-  let sym       = s^.stateSymInterface-      iteFns    = s^.stateIntrinsicTypes+  let sym       = s ^. stateSymInterface+      iteFns    = s ^. stateIntrinsicTypes       merge_val = mergeCrucibleFrame sym iteFns tgt       merge_fn  = mergeGlobalPair merge_val (globalMuxFn sym iteFns)   in@@ -254,7 +256,7 @@   SimFrame sym ext f a' ->   IO (SimFrame sym ext f a') abortCrucibleFrame sym intrinsicFns (BlockTarget _) (MF x') =-  do r' <- abortBranchRegs sym intrinsicFns (x'^.frameRegs)+  do r' <- abortBranchRegs sym intrinsicFns (x' ^. frameRegs)      return $! MF (x' & frameRegs .~ r')  abortCrucibleFrame sym intrinsicFns ReturnTarget (RF nm x') =@@ -268,8 +270,8 @@   PartialResultFrame sym ext f a' ->   IO (PartialResultFrame sym ext f a') abortPartialResult s tgt pr =-  let sym                    = s^.stateSymInterface-      muxFns                 = s^.stateIntrinsicTypes+  let sym                    = s ^. stateSymInterface+      muxFns                 = s ^. stateIntrinsicTypes       abtGp (GlobalPair v g) = GlobalPair <$> abortCrucibleFrame sym muxFns tgt v                                           <*> globalAbortBranch sym muxFns g   in partialValue abtGp pr@@ -367,7 +369,7 @@   resolvedCallName :: ResolvedCall p sym ext ret -> FunctionName-resolvedCallName (OverrideCall _ f) = f^.override+resolvedCallName (OverrideCall _ f) = f ^. override resolvedCallName (CrucibleCall _ f) = case frameHandle f of SomeHandle h -> handleName h  ---------------------------------------------------------------------@@ -404,11 +406,12 @@   SimState p sym ext rtp f args {- ^ Simulator state prior to the abort -} ->   IO (ExecState p sym ext rtp) runErrorHandler msg st =-  let ctx = st^.stateContext-      sym = ctx^.ctxSymInterface-   in withBackend ctx $ \bak ->+  let ctx = st ^. stateContext+      sym = ctx ^. ctxSymInterface+   in withStateBackend st $ \bak ->       do loc <- getCurrentProgramLoc sym-         let err = SimError loc msg+         let stk = stateProgramStack st+         let err = mkSimError loc msg (Just stk)          addProofObligation bak (LabeledPred (falsePred sym) err)          return (AbortState (AssertionFailure err) st) @@ -464,7 +467,7 @@   ExecCont p sym ext rtp (CrucibleLang blocks ret) ('Just ctx) conditionalBranch p xjmp yjmp = do   top_frame <- view (stateTree.actFrame)-  Some pd <- return (top_frame^.crucibleTopFrame.framePostdom)+  Some pd <- return (top_frame ^. crucibleTopFrame.framePostdom)    x_frame <- cruciblePausedFrame xjmp top_frame pd   y_frame <- cruciblePausedFrame yjmp top_frame pd@@ -495,7 +498,7 @@  variantCases ((p,jmp) : cs) =   do top_frame <- view (stateTree.actFrame)-     Some pd <- return (top_frame^.crucibleTopFrame.framePostdom)+     Some pd <- return (top_frame ^. crucibleTopFrame.framePostdom)       x_frame <- cruciblePausedFrame jmp top_frame pd      let y_frame = PausedFrame (TotalRes top_frame) (SwitchResumption cs) Nothing@@ -581,9 +584,9 @@  performIntraFrameMerge tgt = do   ActiveTree ctx0 er <- view stateTree-  simCtx <- view stateContext+  st <- ask   sym <- view stateSymInterface-  withBackend simCtx $ \bak ->+  withStateBackend st $ \bak ->     case ctx0 of       VFFBranch ctx assume_frame loc pred other_branch tgt' @@ -639,9 +642,9 @@                continue (RunPostBranchMerge bid)              ReturnTarget ->                handleSimReturn-                 (er^.partialValue.gpValue.frameFunctionName)+                 (er ^. partialValue.gpValue.frameFunctionName)                  (returnContext ctx0)-                 (er^.partialValue.gpValue.to fromReturnFrame)+                 (er ^. partialValue.gpValue.to fromReturnFrame)  --------------------------------------------------------------------- -- Abort handling@@ -701,9 +704,9 @@   AbortedResult sym ext {- ^ The execution that is being aborted. -} ->   ExecCont p sym ext r g args resumeValueFromFrameAbort ctx0 ar0 = do-  simCtx <- view stateContext+  st <- ask   sym <- view stateSymInterface-  withBackend simCtx $ \bak ->+  withStateBackend st $ \bak ->     case ctx0 of        -- This is the first abort.@@ -862,7 +865,7 @@   ExecCont p sym ext rtp (OverrideLang r) ('Just args) overrideSymbolicBranch p thn_args thn thn_pos els_args els els_pos =   do top_frm <- view (stateTree.actFrame)-     let fnm     = top_frm^.gpValue.overrideSimFrame.override+     let fnm     = top_frm ^. gpValue.overrideSimFrame.override      let thn_loc = mkProgramLoc fnm <$> thn_pos      let els_loc = mkProgramLoc fnm <$> els_pos      let thn_frm = PausedFrame (TotalRes top_frm) (OverrideResumption thn thn_args) thn_loc@@ -910,9 +913,9 @@  intra_branch p t_label f_label tgt = do   ctx <- asContFrame <$> view stateTree-  simCtx <- view stateContext+  st <- ask   sym <- view stateSymInterface-  withBackend simCtx $ \bak ->+  withStateBackend st $ \bak ->     case asConstantPred p of       Nothing ->         ReaderT $ return . SymbolicBranchState p t_label f_label tgt@@ -943,13 +946,13 @@   ExecCont p sym ext rtp f ('Just dc_args) performIntraFrameSplit p a_frame o_frame tgt =   do ctx <- asContFrame <$> view stateTree-     simCtx <- view stateContext+     st <- ask      sym <- view stateSymInterface      loc <- liftIO $ getCurrentProgramLoc sym      a_frame' <- pushPausedFrame a_frame      o_frame' <- pushPausedFrame o_frame -     assume_frame <- withBackend simCtx $ \bak ->+     assume_frame <- withStateBackend st $ \bak ->        liftIO $ assumeInNewFrame bak (BranchCondition loc (pausedLoc a_frame') p)       -- Create context for paused frame.@@ -1090,8 +1093,8 @@   ActiveTree p sym ext ret f args ->   ActiveTree p sym ext ret f args extractCurrentPath t =-  ActiveTree (vffSingleContext (t^.actContext))-             (TotalRes (t^.actFrame))+  ActiveTree (vffSingleContext (t ^. actContext))+             (TotalRes (t ^. actFrame))  vffSingleContext ::   ValueFromFrame p sym ext ret f ->@@ -1118,9 +1121,9 @@ -- -- | Return all branch conditions along path to this node. -- branchConditions :: ActiveTree ctx sym ext ret f args -> [Pred sym] -- branchConditions t =---   case t^.actResult of---     TotalRes _ -> vffBranchConditions (t^.actContext)---     PartialRes p _ _ -> p : vffBranchConditions (t^.actContext)+--   case t ^. actResult of+--     TotalRes _ -> vffBranchConditions (t ^. actContext)+--     PartialRes p _ _ -> p : vffBranchConditions (t ^. actContext)  -- vffBranchConditions :: ValueFromFrame p sym ext ret f --                     -> [Pred sym]
src/Lang/Crucible/Simulator/OverrideSim.hs view
@@ -84,7 +84,6 @@   ) where  import           Control.Exception-import           Control.Lens import           Control.Monad hiding (fail) import qualified Control.Monad.Catch as X import           Control.Monad.IO.Class (MonadIO(..))@@ -92,17 +91,19 @@ import           Control.Monad.ST import           Control.Monad.State.Strict (StateT(..)) import qualified Data.Foldable as Foldable+import           Data.Function ((&)) import qualified Data.Parameterized.Context as Ctx+import           Data.Parameterized.TraversableFC (fmapFC) import           Data.Proxy import qualified Data.Text as T import           Data.Traversable (for)+import           Lens.Micro ((^.), (.~), to)+import           Lens.Micro.Mtl (use, view, (.=), (%=)) import           Numeric.Natural (Natural) import           System.Exit import           System.IO import           System.IO.Error -import           Data.Parameterized.TraversableFC (fmapFC)- import           What4.Config import           What4.Interface import           What4.FunctionName@@ -165,7 +166,7 @@           TotalRes e -> e           PartialRes _loc _pred ex _ar1 -> ex   Sim $ StateContT $ \_c s ->-    return $ ResultState $ AbortedResult (s^.stateContext) (AbortedExit ec gp)+    return $ ResultState $ AbortedResult (s ^. stateContext) (AbortedExit ec gp)  bindOverrideSim ::   OverrideSim p sym ext rtp args r a ->@@ -224,13 +225,14 @@   (forall bak. IsSymBackend sym bak => bak -> OverrideSim p sym ext rtp args ret a) ->   OverrideSim p sym ext rtp args ret a ovrWithBackend k =-  do simCtx <- use stateContext-     ctxSolverProof simCtx (withBackend simCtx k)+  do simSt <- get+     simCtx <- use stateContext+     ctxSolverProof simCtx (withStateBackend simSt k)  instance MonadVerbosity (OverrideSim p sym ext rtp args ret) where   getVerbosity =     do ctx <- getContext-       let cfg = ctxSolverProof ctx (getConfiguration (ctx^.ctxSymInterface))+       let cfg = ctxSolverProof ctx (getConfiguration (ctx ^. ctxSymInterface))        v <- liftIO (getOpt =<< getOptionSetting verbosity cfg)        return (fromInteger v) @@ -580,7 +582,7 @@            go !i ((p,m,mpos):xs) =              let msg = T.pack ("after branch " ++ show i)                  m'  = ReaderT (runStateContT (unSim m) c')-              in overrideSymbolicBranch p all_args m' mpos old_args (go (i+1) xs) (Just (OtherPos msg))+              in overrideSymbolicBranch p all_args m' mpos old_args (go (i + 1) xs) (Just (OtherPos msg))        go (0::Integer) xs0  -- | Non-deterministically choose among several feasible branches.
src/Lang/Crucible/Simulator/PathSatisfiability.hs view
@@ -25,8 +25,8 @@   , BranchResult(..)   ) where -import           Control.Lens( (^.) ) import           Control.Monad.Reader+import           Lens.Micro ((^.)) import qualified Prettyprinter as PP  import           Lang.Crucible.Backend@@ -88,11 +88,11 @@           considerSatisfiability ploc p >>= \case                IndeterminateBranchResult ->                  return ExecutionFeatureNoChange-               NoBranch chosen_branch -> withBackend (st ^. stateContext) $ \bak ->+               NoBranch chosen_branch -> withStateBackend st $ \bak ->                  do p' <- if chosen_branch then return p else notPred sym p                     let frm = if chosen_branch then tp else fp                     addAssumption bak (BranchCondition loc (pausedLoc frm) p')-                    ExecutionFeatureNewState <$> runReaderT (resumeFrame frm (asContFrame (st^.stateTree))) st+                    ExecutionFeatureNewState <$> runReaderT (resumeFrame frm (asContFrame (st ^. stateTree))) st                UnsatisfiableContext ->                  return (ExecutionFeatureNewState (AbortState (InfeasibleBranch loc) st))    where
src/Lang/Crucible/Simulator/PathSplitting.hs view
@@ -35,12 +35,12 @@   , executeCrucibleDFSPaths   ) where -import           Control.Lens ( (^.) ) import           Control.Monad.Reader import           Data.IORef import           Data.Sequence( Seq ) import qualified Data.Sequence as Seq import           Data.Word+import           Lens.Micro ((^.))  import           What4.Interface import           What4.ProgramLoc@@ -97,8 +97,7 @@   IO (ExecState p sym ext rtp) restoreWorkItem (WorkItem branchPred loc frm st assumes) =   do let sym = st ^. stateSymInterface-     let simCtx = st ^. stateContext-     withBackend simCtx $ \bak ->+     withStateBackend st $ \bak ->       do setCurrentProgramLoc sym loc          restoreAssumptionState bak assumes          addAssumption bak (BranchCondition loc (pausedLoc frm) branchPred)@@ -117,7 +116,7 @@   ExecutionFeature p sym ext rtp pathSplittingFeature wl = ExecutionFeature $ \case   SymbolicBranchState p trueFrame falseFrame _bt st ->-    withBackend (st^.stateContext) $ \bak ->+    withStateBackend st $ \bak ->     do let sym = st ^. stateSymInterface        pnot <- notPred sym p        assumes <- saveAssumptionState bak
src/Lang/Crucible/Simulator/PositionTracking.hs view
@@ -21,8 +21,8 @@   ( positionTrackingFeature   ) where -import Control.Lens ((^.), to) import Control.Monad.IO.Class+import Lens.Micro ((^.), to)  import Lang.Crucible.Backend import Lang.Crucible.Simulator.CallFrame@@ -44,8 +44,7 @@      IO (ExecutionFeatureResult p sym ext rtp)    onStep exst@(RunningState (RunBlockStart _bid) st) =      do let loc = st ^. (stateCrucibleFrame.to frameProgramLoc)-        let simCtx = st ^. stateContext-        liftIO $ withBackend simCtx $ \bak ->+        liftIO $ withStateBackend st $ \bak ->           addAssumptions bak (singleEvent (LocationReachedEvent loc))         return (ExecutionFeatureModifiedState exst) 
src/Lang/Crucible/Simulator/Profiling.hs view
@@ -47,9 +47,9 @@   ) where  import qualified Control.Exception as Ex-import           Control.Lens import           Control.Monad ((<=<), when) import           Data.Foldable (toList)+import           Data.Functor.Identity (Identity(..), runIdentity) import           Data.Hashable import           Data.HashSet (HashSet) import qualified Data.HashSet as HashSet@@ -64,6 +64,7 @@ import           Data.Time.Clock import           Data.Time.Clock.POSIX import           Data.Time.Format+import           Lens.Micro ((^.)) import           System.IO (withFile, IOMode(..), hPutStrLn) import           Text.JSON import           GHC.Generics (Generic)@@ -210,7 +211,7 @@ symProUIString :: String -> String -> ProfilingTable -> IO String symProUIString nm source tbl =   do js <- symProUIJSON nm source tbl-     return ("data.receiveData("++ encode js ++ ");")+     return ("data.receiveData(" ++ encode js ++ ");")   symProUIJSON :: String -> String -> ProfilingTable -> IO JSValue@@ -348,7 +349,7 @@ nextEventID :: ProfilingTable -> IO Integer nextEventID tbl =   do i <- readIORef (eventIDRef tbl)-     writeIORef (eventIDRef tbl) $! (i+1)+     writeIORef (eventIDRef tbl) $! (i + 1)      return i  dedupEvent :: ProfilingTable -> EventDedup -> IO () -> IO ()@@ -456,18 +457,18 @@       InitialState _ _ _ _ _ ->         enterEvent tbl startFunctionName Nothing       CallState _rh call st ->-        enterEvent tbl (resolvedCallName call) (st^.stateLocation)+        enterEvent tbl (resolvedCallName call) (st ^. stateLocation)       ReturnState nm _ _ _ ->         exitEvent tbl nm       TailCallState _ call st ->-        do exitEvent tbl (st^.stateTree.actFrame.gpValue.frameFunctionName)-           enterEvent tbl (resolvedCallName call) (st^.stateLocation)+        do exitEvent tbl (st ^. stateTree.actFrame.gpValue.frameFunctionName)+           enterEvent tbl (resolvedCallName call) (st ^. stateLocation)       SymbolicBranchState{} ->         modifyIORef' (metricSplits (metrics tbl)) succ       AbortState{} ->         modifyIORef' (metricAborts (metrics tbl)) succ       UnwindCallState _ _ st ->-        exitEvent tbl (st^.stateTree.actFrame.gpValue.frameFunctionName)+        exitEvent tbl (st ^. stateTree.actFrame.gpValue.frameFunctionName)       BranchMergeState tgt st ->         when (isMergeState tgt st)              (modifyIORef' (metricMerges (metrics tbl)) succ)@@ -476,16 +477,16 @@   when (recordCoverage filt) $     case exst of       ControlTransferState res st ->-        let funcName = st^.stateTree.actFrame.gpValue.frameFunctionName in+        let funcName = st ^. stateTree.actFrame.gpValue.frameFunctionName in         case res of           ContinueResumption (ResolvedJump blk _) ->-            blockEvent tbl funcName (st^.stateLocation) (Some blk)+            blockEvent tbl funcName (st ^. stateLocation) (Some blk)           CheckMergeResumption (ResolvedJump blk _) ->-            blockEvent tbl funcName (st^.stateLocation) (Some blk)+            blockEvent tbl funcName (st ^. stateLocation) (Some blk)           _ -> return ()       RunningState (RunBlockEnd _) st ->-        let funcName = st^.stateTree.actFrame.gpValue.frameFunctionName in-        case st^.stateTree.actFrame.gpValue.crucibleSimFrame.frameStmts of+        let funcName = st ^. stateTree.actFrame.gpValue.frameFunctionName in+        case st ^. stateTree.actFrame.gpValue.crucibleSimFrame.frameStmts of           TermStmt loc term             | Just blocks <- termStmtNextBlocks term,               length blocks >= 2 ->@@ -498,7 +499,7 @@   SimState p sym ext root f args ->   Bool isMergeState tgt st =-  case st^.stateTree.actContext of+  case st ^. stateTree.actContext of     VFFBranch _ctx _assume_frame _loc _p other_branch tgt'       | Just Refl <- testEquality tgt tgt' ->           case other_branch of
src/Lang/Crucible/Simulator/RecordAndReplay.hs view
@@ -20,6 +20,7 @@   replayTraceLength,   RecordedTrace,   getRecordedTrace,+  getConcreteRecordedTrace,   recordFeature,   replayFeature,   initialTrace,@@ -28,22 +29,23 @@ ) where  import Control.Exception qualified as X-import Control.Lens ((%~), (&), (^.))-import Control.Lens qualified as Lens import Data.Foldable qualified as F+import Data.Function ((&)) import Data.Kind (Type)-import Data.Text qualified as Text import Data.Sequence qualified as Seq+import Data.Text qualified as Text import Lang.Crucible.Backend qualified as CB import Lang.Crucible.CFG.Core qualified as C import Lang.Crucible.FunctionHandle qualified as C-import Lang.Crucible.Panic (panic) import Lang.Crucible.Simulator qualified as C import Lang.Crucible.Simulator.EvalStmt qualified as C import Lang.Crucible.Simulator.ExecutionTree qualified as C import Lang.Crucible.Simulator.GlobalState qualified as C import Lang.Crucible.Simulator.SymSequence qualified as CSSS import Lang.Crucible.Types qualified as CT+import Lens.Micro ((^.), (%~))+import Lens.Micro qualified as Lens+import Lens.Micro.TH (makeLenses) import What4.Interface qualified as W4 import What4.Partial qualified as W4P @@ -83,7 +85,7 @@     , _initialTrace :: (RecordedTrace sym)     }     -- ^ constructor intentionally not exported-Lens.makeLenses ''ReplayState+makeLenses ''ReplayState  -- | Constructor for 'RecordState' mkRecordState ::@@ -254,10 +256,22 @@     -- API, but it could be exported in the future if necessary.  -- | Obtain a 'RecordedTrace' after execution.------ This currently requires concretizing the trace, because there is no efficient--- reverse operation for 'CSSS.SymSequence'. getRecordedTrace ::+  C.SymGlobalState sym ->+  RecordState p sym ext rtp ->+  sym ->+  IO (RecordedTrace sym)+getRecordedTrace globals (RecordState g) sym = do+  case C.lookupGlobal g globals of+    Nothing -> X.throw TraceGlobalNotDefined+    Just s -> RecordedTrace <$> CSSS.reverseSymSequence sym s++-- | Obtain a 'RecordedTrace' after execution using concrete evaluation.+--+-- When a concrete evaluation function for 'W4.Pred's is available and only the+-- concretized trace is desired, this is more performant than the more general+-- 'getRecordedTrace'.+getConcreteRecordedTrace ::   W4.IsExprBuilder sym =>   C.SymGlobalState sym ->   RecordState p sym ext rtp ->@@ -265,26 +279,15 @@   -- | Evaluation for booleans, usually a 'What4.Expr.GroundEval.GroundEvalFn'   (W4.Pred sym -> IO Bool) ->   IO (RecordedTrace sym)-getRecordedTrace globals (RecordState g) sym evalBool = do+getConcreteRecordedTrace globals (RecordState g) sym evalBool = do   case C.lookupGlobal g globals of     Nothing -> X.throw TraceGlobalNotDefined     Just s -> RecordedTrace <$> concretizeAndReverseTrace s   where     concretizeAndReverseTrace s = do-      concretized <- CSSS.concretizeSymSequence evalBool (evalStr sym) s+      concretized <- CSSS.concretizeSymSequence evalBool pure s       let reversed = Seq.reverse concretized-      symbolized <- mapM (W4.stringLit sym . W4.UnicodeLiteral) reversed-      CSSS.fromListSymSequence sym (F.toList symbolized)--    evalStr ::-      W4.IsExpr (W4.SymExpr sym) =>-      sym ->-      W4.SymString sym W4.Unicode ->-      IO Text.Text-    evalStr _sym s =-      case W4.asString s of-        Just (W4.UnicodeLiteral s') -> pure s'-        Nothing -> panic "getRecordedTrace" ["Non-literal trace element?"]+      CSSS.fromListSymSequence sym (F.toList reversed)  {- | Inserts a recorded trace into the state's replay trace variable The replay feature will follow this trace if it is enabled@@ -338,7 +341,7 @@             | stop -> badPath             | otherwise -> pure C.ExecutionFeatureNoChange           W4P.PE valid (expectedLoc, rest) ->-            C.withBackend (st ^. C.stateContext) $ \bak -> do+            C.withStateBackend st $ \bak -> do               let msg = "Trace must be valid"               CB.assert bak valid (C.AssertFailureSimError msg "") 
src/Lang/Crucible/Simulator/SimError.hs view
@@ -16,23 +16,30 @@ {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-}+{-# LANGUAGE PatternSynonyms #-} module Lang.Crucible.Simulator.SimError (     SimErrorReason(..)-  , SimError(..)+  , SimError(.., SimError)+  , ProgramStack(..)+  , mkSimError+  , simErrorReason+  , simErrorLoc+  , simErrorContext   , simErrorReasonMsg   , simErrorDetailsMsg   , ppSimError+  , ppProgramStack   ) where  import GHC.Stack (CallStack)  import Control.Exception import Data.String-import Data.Typeable import Prettyprinter  import What4.ProgramLoc + ------------------------------------------------------------------------ -- SimError @@ -49,15 +56,23 @@    | ResourceExhausted String       -- ^ A loop iteration count, or similar resource limit,       --   was exceeded.- deriving (Typeable) -data SimError-   = SimError-   { simErrorLoc :: !ProgramLoc-   , simErrorReason :: !SimErrorReason-   }- deriving (Typeable)+data SimError +   = SimErrorWithContext !ProgramLoc !SimErrorReason !(Maybe ProgramStack)+ +-- | This pattern synonym constructs SimErrors without a program stack context when used +-- as an expression and ignores the program stack when used as a pattern.  It exists+-- because SimError did not used to have a `ProgramStack`, and there are many usages+-- in the code of the previous constructor which is approximated by this pattern.+--+-- Using SimErrorWithContext should be preferred.+pattern SimError :: ProgramLoc -> SimErrorReason -> SimError+pattern SimError { simErrorLoc, simErrorReason } <- SimErrorWithContext simErrorLoc simErrorReason _+  where SimError loc reason = SimErrorWithContext loc reason Nothing +simErrorContext :: SimError -> Maybe ProgramStack+simErrorContext (SimErrorWithContext _ _ c) = c+ simErrorReasonMsg :: SimErrorReason -> String simErrorReasonMsg (GenericSimError msg) = msg simErrorReasonMsg (Unsupported _ msg) = "Unsupported feature: " ++ msg@@ -70,6 +85,9 @@ simErrorDetailsMsg (Unsupported stk _) = show stk simErrorDetailsMsg _ = "" +mkSimError :: ProgramLoc -> SimErrorReason -> Maybe ProgramStack -> SimError+mkSimError loc reason mbCtx = SimErrorWithContext loc reason mbCtx+ instance IsString SimErrorReason where   fromString = GenericSimError @@ -83,13 +101,38 @@ ppSimError er =   vcat $ [ pretty (plSourceLoc loc) <> pretty ": error: in" <+> pretty (plFunction loc)          , pretty (simErrorReasonMsg rsn)-         ] ++ if null details-              then []-              else [ pretty "Details:"-                   , indent 2 (vcat (pretty <$> lines details))-                   ]+         ] ++ (if null details+               then []+               else [ pretty "Details:"+                    , indent 2 (vcat (pretty <$> lines details))+                    ])+          ++ (case simErrorContext er of+                Nothing -> []+                Just (ProgramStack _ []) -> []+                Just ctx -> [ pretty "Context:"+                            , indent 2 (ppProgramStack ctx)+                            ])  where loc = simErrorLoc er        details = simErrorDetailsMsg rsn-       rsn = simErrorReason er+       rsn = simErrorReason er           +-- | Representation of the program stack for providing dynamic+-- context for SimErrors+data ProgramStack = ProgramStack +  { -- | Number of calling frames omitted in the stack trace+    psFrameOmitCount :: Int+    -- | The visible part of the stack strace+  , psFrames :: [ProgramLoc]+  }++ppProgramStack :: ProgramStack -> Doc ann+ppProgramStack (ProgramStack omittedCount frames) = vcat ((ppLoc <$> frames) ++ omitLine)+  where+    omitLine =+      if omittedCount <= 0+        then []+        else [ pretty "..."  <+> pretty omittedCount <+> pretty "calling frames omitted" ]+    ppLoc l = pretty (plSourceLoc l) <> pretty ":" <+> pretty (plFunction l)+ instance Exception SimError+
src/Lang/Crucible/Simulator/SymSequence.hs view
@@ -25,6 +25,7 @@ , traverseSymSequence , concreteizeSymSequence , concretizeSymSequence+, reverseSymSequence , prettySymSequence    -- * Low-level evaluation primitives@@ -34,6 +35,7 @@ ) where  import           Control.Monad.State+import           Data.Coerce (coerce) import           Data.Functor.Const import           Data.Kind (Type) import           Data.IORef@@ -195,6 +197,39 @@      pure (SymSequenceAppend n xs ys)  +-- | Reverse a 'SymSequence'+reverseSymSequence :: forall sym a. sym -> SymSequence sym a -> IO (SymSequence sym a)+reverseSymSequence sym = \s -> coerce (evalWithFreshCache f s)+  where+    f :: (SymSequence sym a -> IO (Const (SymSequence sym a) a))+      -> SymSequence sym a -> IO (Const (SymSequence sym a) a)+    f loop = \case+      SymSequenceNil -> pure (coerce SymSequenceNil)+      s@(SymSequenceCons{}) -> coerce (reverseConsSpine loop SymSequenceNil s)+      SymSequenceAppend _ xs ys ->+        do xs' <- coerce (loop xs)+           ys' <- coerce (loop ys)+           coerce (appendSymSequence sym ys' xs')+      SymSequenceMerge _ p xs ys ->+        do xs' <- coerce (loop xs)+           ys' <- coerce (loop ys)+           coerce (muxSymSequence sym p xs' ys')++    -- Walk a cons-spine with an accumulator, producing a flat cons-list.+    -- Falls back to cached 'loop' when a non-Cons node is reached.+    reverseConsSpine ::+      (SymSequence sym a -> IO (Const (SymSequence sym a) a)) ->+      SymSequence sym a ->+      SymSequence sym a ->+      IO (SymSequence sym a)+    reverseConsSpine loop acc = \case+      SymSequenceCons _ v tl -> do+        acc' <- consSymSequence sym v acc+        reverseConsSpine loop acc' tl+      other -> do+        otherReversed <- coerce (loop other)+        appendSymSequence sym otherReversed acc+ -- | Test if a sequence is nil (is empty) isNilSymSequence :: forall sym a.   IsExprBuilder sym =>@@ -458,7 +493,7 @@ computeOccMap = loop   where     visit n k m-      | Just i <- Map.lookup n m = Map.insert n (i+1) m+      | Just i <- Map.lookup n m = Map.insert n (i + 1) m       | otherwise = k (Map.insert n 1 m)      loop SymSequenceNil = id
src/Lang/Crucible/Syntax.hs view
@@ -85,18 +85,20 @@   , littleEndianStore   ) where -import           Control.Lens import qualified Data.BitVector.Sized as BV+import           Data.Function ((&)) import           Data.Kind import           Data.Parameterized.Classes import qualified Data.Parameterized.Context as Ctx import           Data.Parameterized.Some import           Data.Text (Text) import qualified Data.Vector as V+import           Lens.Micro ((.~)) import           Numeric.Natural  import           Lang.Crucible.CFG.Expr import           Lang.Crucible.FunctionHandle+import           Lang.Crucible.Panic (panic) import           Lang.Crucible.Types  import           What4.Utils.StringLiteral@@ -330,7 +332,7 @@            , KnownRepr TypeRepr ret            , KnownCtx  TypeRepr args            )-        => e (FunctionHandleType (args::>tp) ret)+        => e (FunctionHandleType (args ::> tp) ret)         -> e tp         -> e (FunctionHandleType args ret) closure h a = app (Closure knownRepr knownRepr h knownRepr a)@@ -408,7 +410,7 @@                   (app $ BVAdd addrWidth basePtr (app $ BVLit addrWidth (BV.mkBV addrWidth (toInteger (n-1)))))                   (app $ BVSelect idx cellWidth valWidth v)                   (go (n-1))-        go _ = error "bad size parameters in bigEndianStore!"+        go _ = panic "bigEndianStore" ["bad size parameters!"]  littleEndianStore    :: (IsExpr expr, 1 <= addrWidth, 1 <= valWidth, 1 <= cellWidth)@@ -429,7 +431,7 @@                   (app $ BVAdd addrWidth basePtr (app $ BVLit addrWidth (BV.mkBV addrWidth (toInteger (n-1)))))                   (app $ BVSelect idx cellWidth valWidth v)                   (go (n-1))-        go _ = error "bad size parameters in littleEndianStore!"+        go _ = panic "littleEndianStore" ["bad size parameters!"]  concatExprs :: forall w a expr             .  (IsExpr expr, 1 <= w)@@ -438,7 +440,7 @@             -> (forall w'. (1 <= w') => NatRepr w' -> expr (BVType w') -> a)             -> a -concatExprs _ [] = \_ -> error "Cannot concatenate 0 elements together"+concatExprs _ [] = \_ -> panic "concatExprs" ["Cannot concatenate 0 elements together"] concatExprs w (a:as) = go a as   where go :: (1 <= w)@@ -448,7 +450,7 @@           -> a        go x0 [] k     = k w x0        go x0 (x:xs) k = go x xs (\(w'::NatRepr w') z ->-            withLeqProof (leqAdd LeqProof w' :: LeqProof 1 (w+w'))+            withLeqProof (leqAdd LeqProof w' :: LeqProof 1 (w + w'))               (k (addNat w w') (app $ BVConcat w w' x0 z)))  bigEndianLoad@@ -470,7 +472,7 @@           concatExprs cellWidth segs $ \w x ->             case testEquality w valWidth of               Just Refl -> x-              Nothing -> error "bad size parameters in bigEndianLoad!"+              Nothing -> panic "bigEndianLoad" ["bad size parameters!"]   bigEndianLoadDef@@ -494,7 +496,7 @@           concatExprs cellWidth segs $ \w x ->             case testEquality w valWidth of               Just Refl -> x-              Nothing -> error "bad size parameters in bigEndianLoadDef!"+              Nothing -> panic "bigEndianLoadDef" ["bad size parameters!"]  littleEndianLoad    :: (IsExpr expr, 1 <= addrWidth, 1 <= valWidth, 1 <= cellWidth)@@ -515,7 +517,7 @@           concatExprs cellWidth segs $ \w x ->             case testEquality w valWidth of               Just Refl -> x-              Nothing -> error "bad size parameters in littleEndianLoad!"+              Nothing -> panic "littleEndianLoad" ["bad size parameters!"]  littleEndianLoadDef    :: (IsExpr expr, 1 <= addrWidth, 1 <= valWidth, 1 <= cellWidth)@@ -538,4 +540,4 @@           concatExprs cellWidth segs $ \w x ->             case testEquality w valWidth of               Just Refl -> x-              Nothing -> error "bad size parameters in littleEndianLoadDef!"+              Nothing -> panic "littleEndianLoadDef" ["bad size parameters!"]
src/Lang/Crucible/Types.hs view
@@ -383,9 +383,9 @@     StringMapRepr :: !(TypeRepr tp) -> TypeRepr (StringMapType tp) -   SymbolicArrayRepr :: !(Ctx.Assignment BaseTypeRepr (idx::>tp))+   SymbolicArrayRepr :: !(Ctx.Assignment BaseTypeRepr (idx ::> tp))                      -> !(BaseTypeRepr t)-                     -> TypeRepr (SymbolicArrayType (idx::>tp) t)+                     -> TypeRepr (SymbolicArrayType (idx ::> tp) t)     -- A reference to a symbolic struct.    SymbolicStructRepr :: Ctx.Assignment BaseTypeRepr ctx
src/Lang/Crucible/Utils/BitSet.hs view
@@ -12,6 +12,7 @@ -- built on top of GHC-native Integers. ------------------------------------------------------------------------ module Lang.Crucible.Utils.BitSet+{-# DEPRECATED "This module is deprecated" #-} ( BitSet , getBits , empty@@ -47,7 +48,7 @@ empty = BitSet zeroBits  null :: BitSet a -> Bool-null = (0==) . getBits+null = (0 ==) . getBits  singleton :: Enum a => a -> BitSet a singleton a = BitSet (bit (fromEnum a))@@ -81,19 +82,19 @@   where go :: Enum a => Integer -> Int -> [a]         go 0 _ = []         go x i-           | y .&. 0xffffffff == 0 = go (shiftR x 32) $! (i+32)-           | y .&. 0x0000ffff == 0 = go (shiftR x 16) $! (i+16)-           | y .&. 0x000000ff == 0 = go (shiftR x  8) $! (i+ 8)+           | y .&. 0xffffffff == 0 = go (shiftR x 32) $! (i + 32)+           | y .&. 0x0000ffff == 0 = go (shiftR x 16) $! (i + 16)+           | y .&. 0x000000ff == 0 = go (shiftR x  8) $! (i + 8)            | otherwise = concat-               [ if testBit y 0 then [toEnum (i+0)] else []-               , if testBit y 1 then [toEnum (i+1)] else []-               , if testBit y 2 then [toEnum (i+2)] else []-               , if testBit y 3 then [toEnum (i+3)] else []-               , if testBit y 4 then [toEnum (i+4)] else []-               , if testBit y 5 then [toEnum (i+5)] else []-               , if testBit y 6 then [toEnum (i+6)] else []-               , if testBit y 7 then [toEnum (i+7)] else []-               , go (shiftR x 8) $! (i+8)+               [ if testBit y 0 then [toEnum (i + 0)] else []+               , if testBit y 1 then [toEnum (i + 1)] else []+               , if testBit y 2 then [toEnum (i + 2)] else []+               , if testBit y 3 then [toEnum (i + 3)] else []+               , if testBit y 4 then [toEnum (i + 4)] else []+               , if testBit y 5 then [toEnum (i + 5)] else []+               , if testBit y 6 then [toEnum (i + 6)] else []+               , if testBit y 7 then [toEnum (i + 7)] else []+               , go (shiftR x 8) $! (i + 8)                ]            where y :: Word32
src/Lang/Crucible/Utils/CoreRewrite.hs view
@@ -22,11 +22,11 @@ ( annotateCFGStmts ) where -import           Control.Lens-+import           Data.Function ((&)) import qualified Data.Parameterized.Context as Ctx import           Data.Parameterized.Map (Pair(..)) import           Data.Parameterized.TraversableFC+import           Lens.Micro ((^.), (%~))  import           Lang.Crucible.CFG.Core import           Lang.Crucible.CFG.Extension
src/Lang/Crucible/Utils/MuxTree.hs view
@@ -34,11 +34,10 @@   , muxTreeGt   ) where -import           Control.Lens (folded)- import           Data.Map.Strict (Map) import qualified Data.Map.Strict as Map import qualified Data.Map.Merge.Strict as Map+import           Lens.Micro (folded)  import           What4.Interface import           Lang.Crucible.Panic
src/Lang/Crucible/Utils/Structural.hs view
@@ -23,6 +23,7 @@ import Data.Parameterized.TH.GADT import Data.Parameterized.TraversableFC +import Lang.Crucible.Panic (panic) import Lang.Crucible.Utils.PrettyPrint (ppFn, commas)  ------------------------------------------------------------------------@@ -52,7 +53,7 @@   let vars = varE <$> nms   let nm' = case nameBase nm of               c:r -> toLower c : r-              [] -> error "matchPretty given constructor with empty name."+              [] -> panic "matchPretty" ["given constructor with empty name"]   let mkPP0 v tp = do         me <- matchPat tp         case me of
src/Lang/Crucible/Vector.hs view
@@ -102,6 +102,6 @@   Endian ->   NatRepr i {- ^ Split bit-vectors in this many parts -} ->   NatRepr w {- ^ Length of bit-vectors in the result -} ->-  Vector n (f (BVType (i * w))) -> Vector (n*i) (f (BVType w))+  Vector n (f (BVType (i * w))) -> Vector (n * i) (f (BVType w)) splitVecBV e i w xs = join i (fromBV e i w <$> xs) {-# Inline splitVecBV #-}
test/absint/Max.hs view
@@ -32,7 +32,7 @@ maxDom :: Domain Max' maxDom = d   where-    d = pointed j (==) (WTOWidening (>10) w)+    d = pointed j (==) (WTOWidening (> 10) w)     j (Max i1) (Max i2) = Pointed (Max (max i1 i2))     w _ _ = Top 
test/absint/WTO.hs view
@@ -18,6 +18,7 @@ import qualified Test.Tasty.QuickCheck as T  import Lang.Crucible.Analysis.Fixpoint.Components+import Lang.Crucible.Panic (panic)  wtoTests :: T.TestTree wtoTests = T.testGroup "WeakTopologicalOrdering" [@@ -97,7 +98,7 @@ -- -- The graphs are not all connected. mkRandomGraph :: Int -> QC.Gen RandomGraph-mkRandomGraph ((+1) -> sz) = do+mkRandomGraph ((+ 1) -> sz) = do   nEdges <- QC.choose (2, 2*sz)   srcs <- replicateM nEdges (QC.choose (0, sz))   dsts <- replicateM nEdges (QC.choose (0, sz))@@ -161,7 +162,7 @@ -- -- Not defined for empty graphs toCFG :: RandomGraph -> (Int, (Int -> [Int]))-toCFG (RG []) = error "Empty graph"+toCFG (RG []) = panic "toCFG" ["Empty graph"] toCFG (RG edges@((s0, _) : _)) =   (s0, \n -> [ dst | (src, dst) <- edges, n == src]) 
test/helpers/Main.hs view
@@ -2,9 +2,9 @@  module Main (main) where -import Control.Lens ((^.)) import Data.List (isInfixOf) import Data.Maybe (fromMaybe)+import Lens.Micro ((^.))  import Test.Hspec import Test.Tasty
test/helpers/SymSequence.hs view
@@ -1,300 +1,15 @@-{-# LANGUAGE EmptyDataDeriving #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE GADTs #-} {-# LANGUAGE ImportQualifiedPost #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE TypeApplications #-}-{-# LANGUAGE TypeFamilies #-}  module SymSequence (tests) where -import Control.Monad.IO.Class (liftIO)-import Data.Foldable qualified as F-import Data.List qualified as List-import Data.Maybe qualified as Maybe-import Data.Parameterized.Nonce qualified as Nonce-import Data.Parameterized.Some (Some(Some))-import Hedgehog (Gen)-import Hedgehog qualified as H-import Hedgehog.Gen qualified as Gen-import Hedgehog.Range qualified as Range-import Lang.Crucible.Backend (SomeBackend(SomeBackend), backendGetSym)-import Lang.Crucible.Backend.Simple (newSimpleBackend)-import Lang.Crucible.Simulator.SymSequence (SymSequence)-import Lang.Crucible.Simulator.SymSequence qualified as S import Test.Tasty qualified as TT-import Test.Tasty.Hedgehog qualified as TTH-import What4.Expr (EmptyExprBuilderState(EmptyExprBuilderState))-import What4.Expr.Builder (newExprBuilder)-import What4.FloatMode (FloatModeRepr(FloatIEEERepr))-import What4.Interface qualified as WI-import What4.Partial qualified as WP ------------------------------------------------------------------------- Tests+import SymSequence.Properties qualified as Properties+import SymSequence.Reverse qualified as Reverse  tests :: TT.TestTree tests =-  TTH.testProperty-    "propSame"-    -- This is a big API, so we want adequate coverage (default is 100)-    (H.withTests 4096 propSame)---- | Check that a generated API interaction has the same effect when interpreted--- with either 'SymSequence' or lists.-propSame :: H.Property-propSame =-  H.property $ do-    Some (SomeBackend bak) <- liftIO mkBackend-    let sym = backendGetSym bak-    op <- H.forAll (Gen.sized $ \n -> genList (H.unSize n) Gen.bool)-    let l = opList op-    s <- liftIO (opSeq sym op)-    l' <- liftIO (F.toList <$> asSeq sym s)-    l H.=== l'-  where-    asSeq sym =-      S.concretizeSymSequence (pure . asConstPred (Just sym)) pure-------------------------------------------------------------------------- Helpers--mkBackend :: IO (Some SomeBackend)-mkBackend = do-  sym <- newExprBuilder FloatIEEERepr EmptyExprBuilderState Nonce.globalNonceGenerator-  Some . SomeBackend <$> newSimpleBackend sym---- Requires that the predicate is concrete-asConstPred ::-  WI.IsExprBuilder sym =>-  proxy sym ->-  WI.Pred sym ->-  Bool-asConstPred _proxy p =-  case WI.asConstantPred p of-    Just True -> True-    Just False -> False-    Nothing -> error "non-constant predicate?"-------------------------------------------------------------------------- Op--data Elem a deriving Show--data List a deriving Show---- TODO: Replace with `Seq` for performance-type family AsList t where-  AsList (List a) = [a]-  AsList (Elem a) = a-  AsList (Maybe a) = Maybe (AsList a)-  AsList (a, b) = (AsList a, AsList b)-  AsList a = a--type family AsSeq sym t where-  AsSeq sym (List a) = SymSequence sym a-  AsSeq sym (Elem a) = a-  AsSeq sym (Maybe a) = Maybe (AsSeq sym a)-  AsSeq sym (a, b) = (AsSeq sym a, AsSeq sym b)-  AsSeq sym a = a---- | An interaction with the 'SymSequence' API-data Op a t where-  -- Generic functions-  OTrue :: Op a Bool-  OFalse :: Op a Bool-  OFst :: Op a (l, r) -> Op a l-  OSnd :: Op a (l, r) -> Op a r-  OElem :: a -> Op a (Elem a)-  OFromMaybe :: Op a t -> Op a (Maybe t) -> Op a t--  -- Constructors-  ONil :: Op a (List a)-  OCons :: Op a (Elem a) -> Op a (List a) -> Op a (List a)-  OAppend :: Op a (List a) -> Op a (List a) -> Op a (List a)-  OMux :: Op a Bool -> Op a (List a) -> Op a (List a) -> Op a (List a)--  -- Operations-  OUncons :: Op a (List a) -> Op a (Maybe (Elem a), (List a))-  OLength :: Op a (List a) -> Op a Integer-  -- TODO: isNil, head, tail--sexp :: [String] -> String-sexp s = '(' : (unwords s ++ ")")--fun :: String -> [String] -> String-fun f s = sexp (f:s)--fun1 :: Show a => String -> a -> String-fun1 f a = fun f [show a]--fun2 :: (Show a, Show b) => String -> a -> b -> String-fun2 f a b = fun f [show a, show b]--fun3 :: (Show a, Show b, Show c) => String -> a -> b -> c -> String-fun3 f a b c = fun f [show a, show b, show c]--instance Show a => Show (Op a t) where-  show =-    \case-      -- Generic functions-      OTrue -> "true"-      OFalse -> "false"-      OFst t -> fun1 "fst" t-      OSnd t -> fun1 "snd" t-      OElem a -> show a-      OFromMaybe a m -> fun2 "fromMaybe" a m--      -- Constructors-      ONil -> "nil"-      OCons l r -> fun2 "cons" l r-      OAppend l r -> fun2 "append" l r-      OMux b l r -> fun3 "mux" b l r--      -- Operations-      OUncons l -> fun1 "uncons" l-      OLength l -> fun1 "length" l-------------------------------------------------------------------------- Generating Op--genBool :: Gen (Op a Bool)-genBool =-  Gen.choice-  [ pure OTrue-  , pure OFalse+  TT.testGroup "SymSequence"+  [ Properties.tests+  , Reverse.tests   ]--genElem ::-  Int ->-  Gen a ->-  Gen (Op a (Elem a))-genElem sz genA =-  if sz <= 0-  then OElem <$> genA-  else-    Gen.choice-    [ OElem <$> genA-    , OFromMaybe-      <$> genElem (sz - 1) genA-      <*> (OFst <$> (OUncons <$> genList (sz - 1) genA))-    ]--genList ::-  Int ->-  Gen a ->-  Gen (Op a (List a))-genList sz genA =-  if sz <= 0-  then pure ONil-  else-    Gen.choice-    [ genCons-    , genAppend-    , genMux-    ]-  where-    sub1 = genList (sz - 1) genA-    sub2 = do-      let budget = max 0 (sz - 1)-      bl <- Gen.integral (Range.linear 0 budget)-      let br = max 0 (budget - bl)-      l <- genList bl genA-      r <- genList br genA-      pure (l, r)--    genCons = OCons <$> genElem (sz - 1) genA <*> sub1--    genAppend = uncurry OAppend <$> sub2--    genMux = do-      b <- genBool-      uncurry (OMux b) <$> sub2-------------------------------------------------------------------------- Interpreting Op--opList :: Op a t -> AsList t-opList =-  \case-    -- Generic functions-    OTrue -> True-    OFalse -> False-    OFst t -> fst (opList t)-    OSnd t -> snd (opList t)-    OElem a -> a-    OFromMaybe a m -> Maybe.fromMaybe (opList a) (opList m)--    -- Constructors-    ONil -> []-    OCons a l -> opList a : opList l-    OAppend l r -> opList l ++ opList r-    OMux b l r -> if opList b then opList l else opList r--    -- Operations-    OUncons l ->-      let l' = opList l in-      case List.uncons l' of-        Just (hd, tl) -> (Just hd, tl)-        Nothing -> (Nothing, l')-    OLength l -> fromIntegral @Int @Integer (length (opList l))  -- safe--opSeq ::-  WI.IsExprBuilder sym =>-  sym ->-  Op a t ->-  IO (AsSeq sym t)-opSeq sym =-  \case-    -- Generic functions-    OTrue -> pure True-    OFalse -> pure False-    OFst t -> fst <$> opSeq sym t-    OSnd t -> snd <$> opSeq sym t-    OElem a -> pure a-    OFromMaybe a m ->-      Maybe.fromMaybe-      <$> opSeq sym a-      <*> opSeq sym m--    -- Constructors-    ONil -> pure S.SymSequenceNil-    OCons a l ->-      S.SymSequenceCons-      <$> Nonce.freshNonce Nonce.globalNonceGenerator-      <*> opSeq sym a-      <*> opSeq sym l-    OAppend l r ->-      S.SymSequenceAppend-      <$> Nonce.freshNonce Nonce.globalNonceGenerator-      <*> opSeq sym l-      <*> opSeq sym r-    OMux b l r -> do-      b' <- opSeq sym b-      let b'' = if b' then WI.truePred sym else WI.falsePred sym-      S.SymSequenceMerge-        <$> Nonce.freshNonce Nonce.globalNonceGenerator-        <*> pure b''-        <*> opSeq sym l-        <*> opSeq sym r--    -- Operations-    OUncons l -> do-      l' <- opSeq sym l-      let interpPred p x y =-            if asConstPred (Just sym) p-            then pure x-            else pure y-      pe <- S.unconsSymSequence sym interpPred l'-      case pe of-        WP.Unassigned -> pure (Nothing, l')-        WP.PE _ (hd, tl) -> -- TODO: assert pred is truePred-          pure (Just hd, tl)-    OLength s -> do-      l <- S.lengthSymSequence sym =<< opSeq sym s-      case WI.asInteger (WI.natToIntegerPure l) of-        Just l' -> pure l'-        Nothing -> error "SymSequence: symbolic length"
+ test/helpers/SymSequence/Properties.hs view
@@ -0,0 +1,308 @@+{-# LANGUAGE EmptyDataDeriving #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE ImportQualifiedPost #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}++module SymSequence.Properties (tests) where++import Control.Monad.IO.Class (liftIO)+import Data.Foldable qualified as F+import Data.List qualified as List+import Data.Maybe qualified as Maybe+import Data.Parameterized.Nonce qualified as Nonce+import Data.Parameterized.Some (Some(Some))+import Hedgehog (Gen)+import Hedgehog qualified as H+import Hedgehog.Gen qualified as Gen+import Hedgehog.Range qualified as Range+import Lang.Crucible.Backend (SomeBackend(SomeBackend), backendGetSym)+import Lang.Crucible.Backend.Simple (newSimpleBackend)+import Lang.Crucible.Panic (panic)+import Lang.Crucible.Simulator.SymSequence (SymSequence)+import Lang.Crucible.Simulator.SymSequence qualified as S+import Test.Tasty qualified as TT+import Test.Tasty.Hedgehog qualified as TTH+import What4.Expr (EmptyExprBuilderState(EmptyExprBuilderState))+import What4.Expr.Builder (newExprBuilder)+import What4.FloatMode (FloatModeRepr(FloatIEEERepr))+import What4.Interface qualified as WI+import What4.Partial qualified as WP++---------------------------------------------------------------------+-- Tests++tests :: TT.TestTree+tests =+  TTH.testProperty+    "propSame"+    -- This is a big API, so we want adequate coverage (default is 100)+    (H.withTests 4096 propSame)++-- | Check that a generated API interaction has the same effect when interpreted+-- with either 'SymSequence' or lists.+propSame :: H.Property+propSame =+  H.property $ do+    Some (SomeBackend bak) <- liftIO mkBackend+    let sym = backendGetSym bak+    op <- H.forAll (Gen.sized $ \n -> genList (H.unSize n) Gen.bool)+    let l = opList op+    s <- liftIO (opSeq sym op)+    l' <- liftIO (F.toList <$> asSeq sym s)+    l H.=== l'+  where+    asSeq sym =+      S.concretizeSymSequence (pure . asConstPred (Just sym)) pure++---------------------------------------------------------------------+-- Helpers++mkBackend :: IO (Some SomeBackend)+mkBackend = do+  sym <- newExprBuilder FloatIEEERepr EmptyExprBuilderState Nonce.globalNonceGenerator+  Some . SomeBackend <$> newSimpleBackend sym++-- Requires that the predicate is concrete+asConstPred ::+  WI.IsExprBuilder sym =>+  proxy sym ->+  WI.Pred sym ->+  Bool+asConstPred _proxy p =+  case WI.asConstantPred p of+    Just True -> True+    Just False -> False+    Nothing -> panic "asConstPred" ["non-constant predicate"]++---------------------------------------------------------------------+-- Op++data Elem a deriving Show++data List a deriving Show++-- TODO: Replace with `Seq` for performance+type family AsList t where+  AsList (List a) = [a]+  AsList (Elem a) = a+  AsList (Maybe a) = Maybe (AsList a)+  AsList (a, b) = (AsList a, AsList b)+  AsList a = a++type family AsSeq sym t where+  AsSeq sym (List a) = SymSequence sym a+  AsSeq sym (Elem a) = a+  AsSeq sym (Maybe a) = Maybe (AsSeq sym a)+  AsSeq sym (a, b) = (AsSeq sym a, AsSeq sym b)+  AsSeq sym a = a++-- | An interaction with the 'SymSequence' API+data Op a t where+  -- Generic functions+  OTrue :: Op a Bool+  OFalse :: Op a Bool+  OFst :: Op a (l, r) -> Op a l+  OSnd :: Op a (l, r) -> Op a r+  OElem :: a -> Op a (Elem a)+  OFromMaybe :: Op a t -> Op a (Maybe t) -> Op a t++  -- Constructors+  ONil :: Op a (List a)+  OCons :: Op a (Elem a) -> Op a (List a) -> Op a (List a)+  OAppend :: Op a (List a) -> Op a (List a) -> Op a (List a)+  OMux :: Op a Bool -> Op a (List a) -> Op a (List a) -> Op a (List a)++  -- Operations+  OUncons :: Op a (List a) -> Op a (Maybe (Elem a), (List a))+  OLength :: Op a (List a) -> Op a Integer+  OReverse :: Op a (List a) -> Op a (List a)+  -- TODO: isNil, head, tail++sexp :: [String] -> String+sexp s = '(' : (unwords s ++ ")")++fun :: String -> [String] -> String+fun f s = sexp (f:s)++fun1 :: Show a => String -> a -> String+fun1 f a = fun f [show a]++fun2 :: (Show a, Show b) => String -> a -> b -> String+fun2 f a b = fun f [show a, show b]++fun3 :: (Show a, Show b, Show c) => String -> a -> b -> c -> String+fun3 f a b c = fun f [show a, show b, show c]++instance Show a => Show (Op a t) where+  show =+    \case+      -- Generic functions+      OTrue -> "true"+      OFalse -> "false"+      OFst t -> fun1 "fst" t+      OSnd t -> fun1 "snd" t+      OElem a -> show a+      OFromMaybe a m -> fun2 "fromMaybe" a m++      -- Constructors+      ONil -> "nil"+      OCons l r -> fun2 "cons" l r+      OAppend l r -> fun2 "append" l r+      OMux b l r -> fun3 "mux" b l r++      -- Operations+      OUncons l -> fun1 "uncons" l+      OLength l -> fun1 "length" l+      OReverse l -> fun1 "reverse" l++---------------------------------------------------------------------+-- Generating Op++genBool :: Gen (Op a Bool)+genBool =+  Gen.choice+  [ pure OTrue+  , pure OFalse+  ]++genElem ::+  Int ->+  Gen a ->+  Gen (Op a (Elem a))+genElem sz genA =+  if sz <= 0+  then OElem <$> genA+  else+    Gen.choice+    [ OElem <$> genA+    , OFromMaybe+      <$> genElem (sz - 1) genA+      <*> (OFst <$> (OUncons <$> genList (sz - 1) genA))+    ]++genList ::+  Int ->+  Gen a ->+  Gen (Op a (List a))+genList sz genA =+  if sz <= 0+  then pure ONil+  else+    Gen.choice+    [ genCons+    , genAppend+    , genMux+    , genReverse+    ]+  where+    sub1 = genList (sz - 1) genA+    sub2 = do+      let budget = max 0 (sz - 1)+      bl <- Gen.integral (Range.linear 0 budget)+      let br = max 0 (budget - bl)+      l <- genList bl genA+      r <- genList br genA+      pure (l, r)++    genCons = OCons <$> genElem (sz - 1) genA <*> sub1++    genAppend = uncurry OAppend <$> sub2++    genMux = do+      b <- genBool+      uncurry (OMux b) <$> sub2++    genReverse = OReverse <$> sub1++---------------------------------------------------------------------+-- Interpreting Op++opList :: Op a t -> AsList t+opList =+  \case+    -- Generic functions+    OTrue -> True+    OFalse -> False+    OFst t -> fst (opList t)+    OSnd t -> snd (opList t)+    OElem a -> a+    OFromMaybe a m -> Maybe.fromMaybe (opList a) (opList m)++    -- Constructors+    ONil -> []+    OCons a l -> opList a : opList l+    OAppend l r -> opList l ++ opList r+    OMux b l r -> if opList b then opList l else opList r++    -- Operations+    OUncons l ->+      let l' = opList l in+      case List.uncons l' of+        Just (hd, tl) -> (Just hd, tl)+        Nothing -> (Nothing, l')+    OLength l -> fromIntegral @Int @Integer (length (opList l))  -- safe+    OReverse l -> reverse (opList l)++opSeq ::+  WI.IsExprBuilder sym =>+  sym ->+  Op a t ->+  IO (AsSeq sym t)+opSeq sym =+  \case+    -- Generic functions+    OTrue -> pure True+    OFalse -> pure False+    OFst t -> fst <$> opSeq sym t+    OSnd t -> snd <$> opSeq sym t+    OElem a -> pure a+    OFromMaybe a m ->+      Maybe.fromMaybe+      <$> opSeq sym a+      <*> opSeq sym m++    -- Constructors+    ONil -> pure S.SymSequenceNil+    OCons a l ->+      S.SymSequenceCons+      <$> Nonce.freshNonce Nonce.globalNonceGenerator+      <*> opSeq sym a+      <*> opSeq sym l+    OAppend l r ->+      S.SymSequenceAppend+      <$> Nonce.freshNonce Nonce.globalNonceGenerator+      <*> opSeq sym l+      <*> opSeq sym r+    OMux b l r -> do+      b' <- opSeq sym b+      let b'' = if b' then WI.truePred sym else WI.falsePred sym+      S.SymSequenceMerge+        <$> Nonce.freshNonce Nonce.globalNonceGenerator+        <*> pure b''+        <*> opSeq sym l+        <*> opSeq sym r++    -- Operations+    OUncons l -> do+      l' <- opSeq sym l+      let interpPred p x y =+            if asConstPred (Just sym) p+            then pure x+            else pure y+      pe <- S.unconsSymSequence sym interpPred l'+      case pe of+        WP.Unassigned -> pure (Nothing, l')+        WP.PE _ (hd, tl) -> -- TODO: assert pred is truePred+          pure (Just hd, tl)+    OLength s -> do+      l <- S.lengthSymSequence sym =<< opSeq sym s+      case WI.asInteger (WI.natToIntegerPure l) of+        Just l' -> pure l'+        Nothing -> panic "opSeq" ["SymSequence: symbolic length"]+    OReverse l -> S.reverseSymSequence sym =<< opSeq sym l
+ test/helpers/SymSequence/Reverse.hs view
@@ -0,0 +1,174 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ImportQualifiedPost #-}+{-# LANGUAGE RankNTypes #-}++module SymSequence.Reverse (tests) where++import Data.Parameterized.Nonce qualified as Nonce+import Data.Parameterized.Some (Some(Some))+import Lang.Crucible.Backend (SomeBackend(SomeBackend), backendGetSym)+import Lang.Crucible.Backend.Simple (newSimpleBackend)+import Lang.Crucible.Simulator.SymSequence (SymSequence)+import Lang.Crucible.Simulator.SymSequence qualified as S+import System.Timeout (timeout)+import Test.Tasty qualified as TT+import Test.Tasty.HUnit qualified as TTU+import What4.Expr (EmptyExprBuilderState(EmptyExprBuilderState))+import What4.Expr.Builder (newExprBuilder)+import What4.FloatMode (FloatModeRepr(FloatIEEERepr))+import What4.Interface qualified as WI++---------------------------------------------------------------------+-- Tests++tests :: TT.TestTree+tests = TT.testGroup "reverse performance"++  -- Pure cons-list (no branching, no appends):+  --+  --   Cons -> Cons -> ... -> Cons -> Nil+  --+  [ reverseTest "reverse large cons-list" $ \sym ->+      buildSeq sym 1500000 $ \s _ acc ->+        S.consSymSequence s True acc++  -- Cons-list with a Mux node every 100 elements.+  -- At each Mux both branches point to the same shared tail:+  --+  --                                 /--true---\+  --   Cons -> ... -> Cons -> Mux ->            Cons -> ... -> Nil+  --                                 \--false--/+  --+  , reverseTest "reverse cons-list with periodic muxes" $ \sym ->+      buildSeq sym 250000 $ \s i acc -> do+        acc' <-+          if i `mod` 100 == 0+          then do+            t <- S.consSymSequence s True acc+            f <- S.consSymSequence s False acc+            S.muxSymSequence s (WI.truePred s) t f+          else pure acc+        S.consSymSequence s True acc'++  -- Left-nested chain of Appends:+  --+  --   Append -> Append -> ... -> Append -> Nil+  --+  , reverseTest "reverse left-nested appends" $ \sym ->+      buildSeq sym 250000 $ \s _ acc -> do+        singleton <- S.consSymSequence s True S.SymSequenceNil+        S.appendSymSequence s acc singleton++  -- Right-nested chain of Appends:+  --+  --   Append -> Append -> ... -> Append -> Nil+  --+  , reverseTest "reverse right-nested appends" $ \sym ->+      buildSeq sym 250000 $ \s _ acc -> do+        singleton <- S.consSymSequence s True S.SymSequenceNil+        S.appendSymSequence s singleton acc++  -- Left-deep chain of Muxes (true branch grows):+  --+  --   Mux -> Mux -> Mux -> ... -> Mux -> Nil+  --+  , reverseTest "reverse left-deep mux chain" $ \sym ->+      buildSeq sym 250000 $ \s _ acc -> do+        singleton <- S.consSymSequence s True S.SymSequenceNil+        S.muxSymSequence s (WI.truePred s) acc singleton++  -- Right-deep chain of Muxes (true branch is a leaf):+  --+  --   Mux -> Mux -> Mux -> ... -> Mux -> Nil+  --+  , reverseTest "reverse right-deep mux chain" $ \sym ->+      buildSeq sym 250000 $ \s _ acc -> do+        singleton <- S.consSymSequence s True S.SymSequenceNil+        S.muxSymSequence s (WI.truePred s) singleton acc++  -- Balanced binary tree of Appends over singletons:+  --+  --            Append+  --           /      \+  --       Append    Append+  --       /    \    /    \+  --     [1]  [2]  [3]  [4] ...+  --+  , reverseTest "reverse balanced appends" $ \sym ->+      buildBalanced sym 250000 $ \s acc1 acc2 ->+        S.appendSymSequence s acc1 acc2++  -- Balanced binary tree of Muxes over singletons:+  --+  --            Mux+  --           /   \+  --        Mux    Mux+  --       /   \  /   \+  --     [1] [2] [3] [4] ...+  --+  , reverseTest "reverse balanced muxes" $ \sym ->+      buildBalanced sym 250000 $ \s acc1 acc2 ->+        S.muxSymSequence s (WI.truePred s) acc1 acc2+  ]++---------------------------------------------------------------------+-- Helpers++mkBackend :: IO (Some SomeBackend)+mkBackend = do+  sym <- newExprBuilder FloatIEEERepr EmptyExprBuilderState Nonce.globalNonceGenerator+  Some . SomeBackend <$> newSimpleBackend sym++-- | Build a sequence, reverse it, and check that length is preserved.+--   Must complete within 5 seconds.+reverseTest ::+  String ->+  (forall sym. WI.IsExprBuilder sym => sym -> IO (SymSequence sym Bool)) ->+  TT.TestTree+reverseTest name build = TTU.testCase name $ do+  Some (SomeBackend bak) <- mkBackend+  let sym = backendGetSym bak+  s <- build sym+  origLen <- S.lengthSymSequence sym s+  result <- timeout (5 * 1000000) $ do+    r <- S.reverseSymSequence sym s+    S.lengthSymSequence sym r+  case result of+    Nothing -> TTU.assertFailure (name ++ " timed out (>5s)")+    Just revLen ->+      TTU.assertEqual "length preserved"+        (WI.asInteger (WI.natToIntegerPure origLen))+        (WI.asInteger (WI.natToIntegerPure revLen))++-- | Iterate a step function n times starting from nil.+buildSeq ::+  WI.IsExprBuilder sym =>+  sym ->+  Int ->+  (sym -> Int -> SymSequence sym Bool -> IO (SymSequence sym Bool)) ->+  IO (SymSequence sym Bool)+buildSeq sym n step = go n S.SymSequenceNil+  where+    go 0 acc = pure acc+    go i acc = go (i - 1) =<< step sym i acc++-- | Build a balanced binary tree of n singletons combined with the given+--   binary operation (e.g. appendSymSequence or muxSymSequence).+buildBalanced ::+  WI.IsExprBuilder sym =>+  sym ->+  Int ->+  (sym -> SymSequence sym Bool -> SymSequence sym Bool -> IO (SymSequence sym Bool)) ->+  IO (SymSequence sym Bool)+buildBalanced sym n combine = do+  leaves <- mapM (\_ -> S.consSymSequence sym True S.SymSequenceNil) [1..n]+  reduce leaves+  where+    reduce [] = pure S.SymSequenceNil+    reduce [x] = pure x+    reduce xs = reduce =<< pairUp xs+    pairUp [] = pure []+    pairUp [x] = pure [x]+    pairUp (x:y:rest) = do+      combined <- combine sym x y+      (combined :) <$> pairUp rest