quebex

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
 4module Language.QBE.Simulator.Explorer
 5  ( newEngine,
 6    explore,
 7    defSolver,
 8    logSolver,
 9  )
10where
11
12import Language.QBE (Program)
13import Language.QBE.Backend.DFS (PathSel, findUnexplored, newPathSel, trackTrace)
14import Language.QBE.Backend.Model (Model)
15import Language.QBE.Backend.Store qualified as ST
16import Language.QBE.Backend.Tracer qualified as T
17import Language.QBE.Simulator (execFunc)
18import Language.QBE.Simulator.Concolic.Expression qualified as CE
19import Language.QBE.Simulator.Concolic.State (run)
20import Language.QBE.Simulator.Default.Expression qualified as DE
21import Language.QBE.Types qualified as QBE
22import SimpleSMT qualified as SMT
23import System.IO (Handle)
24
25logic :: String
26logic = "QF_BV"
27
28defSolver :: IO SMT.Solver
29defSolver = do
30  -- l <- SMT.newLogger 0
31  s <- SMT.newSolver "bitwuzla" [] Nothing
32  SMT.setLogic s logic
33  return s
34
35logSolver :: Handle -> IO SMT.Solver
36logSolver handle = do
37  l <- SMT.newLoggerWithHandle handle 0
38  s <-
39    SMT.newSolverWithConfig
40      (SMT.defaultConfig "bitwuzla" [])
41        { SMT.solverLogger = SMT.smtSolverLogger l
42        }
43  SMT.setLogic s logic
44  return s
45
46------------------------------------------------------------------------
47
48data Engine
49  = Engine
50  { expSolver :: SMT.Solver,
51    expPathSel :: PathSel,
52    expStore :: ST.Store
53  }
54
55newEngine :: SMT.Solver -> IO Engine
56newEngine solver = Engine solver newPathSel <$> ST.empty
57
58findNext :: Engine -> T.ExecTrace -> IO (Maybe Model, Engine)
59findNext e@(Engine {expStore = store}) eTrace = do
60  let pathSel = trackTrace (expPathSel e) eTrace
61  symVars <- ST.sexprs store
62  (model, nextPathSel) <- findUnexplored (expSolver e) symVars pathSel
63
64  let ne = e {expPathSel = nextPathSel}
65  case model of
66    Nothing ->
67      pure (model, ne)
68    Just nm ->
69      ST.setModel store nm >> pure (Just nm, ne)
70
71------------------------------------------------------------------------
72
73traceFunc :: Program -> QBE.FuncDef -> [CE.Concolic DE.RegVal] -> IO T.ExecTrace
74traceFunc prog func params = run prog (execFunc func params)
75
76explore ::
77  Engine ->
78  Program ->
79  QBE.FuncDef ->
80  [(String, QBE.BaseType)] ->
81  IO [(ST.Assign, T.ExecTrace)]
82explore engine@Engine {expSolver = solver, expStore = store} prog entry params = do
83  varAssign <- ST.assign store
84  values <- mapM (uncurry (ST.getConcolic solver store)) params
85  eTrace <- traceFunc prog entry values
86
87  (model, nEngine) <- findNext engine eTrace
88  case model of
89    Nothing -> pure [(varAssign, eTrace)]
90    Just _m -> (:) (varAssign, eTrace) <$> explore nEngine prog entry params