A software analysis framework built around the QBE intermediate language
git clone https://git.8pit.net/quebex.git
1-- SPDX-FileCopyrightText: 2025 Sören Tempel <soeren+git@soeren-tempel.net> 2-- 3-- SPDX-License-Identifier: GPL-3.0-only 4 5module Language.QBE.Backend.Store 6 ( Store (cValues), 7 Assign, 8 empty, 9 sexprs,10 finalize,11 setModel,12 getConcolic,13 )14where1516import Data.Map qualified as Map17import Language.QBE.Backend.Model qualified as Model18import Language.QBE.Simulator.Concolic.Expression qualified as CE19import Language.QBE.Simulator.Default.Expression qualified as DE20import Language.QBE.Simulator.Expression qualified as E21import Language.QBE.Simulator.Symbolic.Expression qualified as SE22import Language.QBE.Types qualified as QBE23import SimpleBV qualified as SMT24import System.Random (StdGen, genWord64)2526-- | Concrete variable assignment.27type Assign = Map.Map String DE.RegVal2829-- A variable store mapping variable names to concrete values.30data Store31 = Store32 { cValues :: Assign,33 sValues :: Map.Map String SE.BitVector,34 defined :: Map.Map String SE.BitVector,35 randGen :: StdGen36 }3738-- | Create a new (empty) store.39empty :: StdGen -> Store40empty = Store Map.empty Map.empty Map.empty4142-- | Obtain symbolic values as a list of 'SimpleBV' expressions.43sexprs :: Store -> [SMT.SExpr]44sexprs = map SE.toSExpr . Map.elems . sValues4546-- | Finalize all pending symbolic variable declarations.47finalize :: SMT.Solver -> Store -> IO Store48finalize solver store@(Store {sValues = m, defined = defs}) = do49 let new = m `Map.difference` defs50 mapM_ (uncurry declareSymbolic) $ Map.toList new5152 pure53 store54 { defined = Map.union m new,55 sValues = Map.empty56 }57 where58 declareSymbolic n v =59 SMT.declareBV solver n $ SE.bitSize v6061-- | Create a variable store from a 'Model'.62setModel :: Store -> Model.Model -> Store63setModel store model =64 store {cValues = Map.fromList $ Model.toList model}6566-- | Lookup the variable name in the store, if it doesn't exist return67-- an unconstrained 'CE.Concolic' value with a random concrete part.68getConcolic :: Store -> String -> QBE.ExtType -> (Store, CE.Concolic DE.RegVal)69getConcolic store@Store {randGen = rand} name ty =70 ( store {sValues = newSymVars, randGen = nextRand},71 CE.Concolic concrete (Just symbolic)72 )73 where74 (symbolic, newSymVars) =75 let bv = SE.symbolic name ty76 in (bv, Map.insert name bv $ sValues store)7778 (concrete, nextRand) =79 case Map.lookup name (cValues store) of80 Just cv -> (cv, rand)81 Nothing ->82 -- TODO: The generator should consider the bounds of QBE.BaseType.83 let (rv, nr) = genWord64 rand84 conValue = E.fromLit ty rv85 in (conValue, nr)