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, 7 Assign, 8 empty, 9 sexprs,10 assign,11 setModel,12 getConcolic,13 )14where1516import Data.Functor (($>))17import Data.IORef (IORef, newIORef, readIORef, writeIORef)18import Data.Map qualified as Map19import Language.QBE.Backend.Model qualified as Model20import Language.QBE.Simulator.Concolic.Expression qualified as CE21import Language.QBE.Simulator.Default.Expression qualified as DE22import Language.QBE.Simulator.Expression qualified as E23import Language.QBE.Simulator.Symbolic.Expression qualified as SE24import Language.QBE.Types qualified as QBE25import SimpleSMT qualified as SMT26import System.Random.Stateful (IOGenM, StdGen, initStdGen, newIOGenM, uniformWord64)2728-- | Concrete variable assignment.29type Assign = Map.Map String DE.RegVal3031-- A variable store mapping variable names to concrete values.32data Store33 = Store34 { cValues :: IORef Assign,35 sValues :: IORef (Map.Map String SE.BitVector),36 randGen :: IOGenM StdGen37 }3839-- | Create a new (empty) store.40empty :: IO Store41empty = do42 ranGen <- initStdGen >>= newIOGenM43 conMap <- newIORef Map.empty44 symMap <- newIORef Map.empty45 pure $ Store conMap symMap ranGen4647-- | Obtain symbolic values as a list of 'SimpleSMT' expressions.48sexprs :: Store -> IO [SMT.SExpr]49sexprs Store {sValues = m} =50 map SE.toSExpr <$> (Map.elems <$> readIORef m)5152-- | Obtain a list of concrete variable assignments.53assign :: Store -> IO Assign54assign store = readIORef (cValues store)5556-- | Create a variable store from a 'Model'.57setModel :: Store -> Model.Model -> IO ()58setModel store model = do59 modelMap <- Map.fromList <$> Model.toList model60 writeIORef (cValues store) modelMap6162-- | Lookup the variable name in the store, if it doesn't exist return63-- an unconstrained 'CE.Concolic' value with a random concrete part.64getConcolic :: SMT.Solver -> Store -> String -> QBE.BaseType -> IO CE.Concolic65getConcolic solver store@Store {cValues = con, sValues = sym} name ty = do66 concreteMap <- readIORef con67 concrete <-68 case Map.lookup name concreteMap of69 Just x -> pure x70 Nothing ->71 -- TODO: The uniform generator must consider the bounds of QBE.BaseType.72 E.fromLit ty <$> uniformWord64 (randGen store)7374 symbolicMap <- readIORef sym75 symbolic <-76 case Map.lookup name symbolicMap of77 Just x -> pure x78 Nothing -> do79 s <- SE.symbolic solver name ty80 writeIORef sym (Map.insert name s symbolicMap) $> s8182 pure $ CE.Concolic concrete (Just symbolic)