1-- SPDX-FileCopyrightText: 2025 Sören Tempel <soeren+git@soeren-tempel.net>2--3-- SPDX-License-Identifier: GPL-3.0-only45module Language.QBE.Simulator.Concolic.Expression6 ( Concolic (..),7 hasSymbolic,8 )9where1011import Control.Exception (assert)12import Data.Functor ((<&>))13import Data.Maybe (fromMaybe)14import Data.Word (Word8)15import Language.QBE.Simulator.Default.Expression qualified as D16import Language.QBE.Simulator.Expression qualified as E17import Language.QBE.Simulator.Memory qualified as MEM18import Language.QBE.Simulator.Symbolic.Expression qualified as SE1920data Concolic v21 = Concolic22 { concrete :: v,23 symbolic :: Maybe SE.BitVector24 }25 deriving (Show)2627hasSymbolic :: Concolic v -> Bool28hasSymbolic Concolic {symbolic = Just _} = True29hasSymbolic _ = False3031getSymbolicDef :: (v -> SE.BitVector) -> Concolic v -> SE.BitVector32getSymbolicDef conc Concolic {concrete = c, symbolic = s} =33 fromMaybe (conc c) s3435------------------------------------------------------------------------3637instance MEM.Storable (Concolic D.RegVal) (Concolic Word8) where38 toBytes Concolic {concrete = c, symbolic = s} =39 let cbytes = MEM.toBytes c40 nbytes = length cbytes41 sbytes = maybe (replicate nbytes Nothing) (map Just . MEM.toBytes) s42 in assert (nbytes == length sbytes) $43 zipWith Concolic cbytes sbytes4445 fromBytes ty bytes =46 do47 let conBytes = map concrete bytes48 con <- MEM.fromBytes ty conBytes4950 let mkConcolic = Concolic con51 if any hasSymbolic bytes52 then do53 let symBVs = map (getSymbolicDef SE.fromByte) bytes54 MEM.fromBytes ty symBVs <&> mkConcolic . Just55 else Just $ mkConcolic Nothing5657------------------------------------------------------------------------5859unaryOp ::60 (D.RegVal -> Maybe D.RegVal) ->61 (SE.BitVector -> Maybe SE.BitVector) ->62 Concolic D.RegVal ->63 Maybe (Concolic D.RegVal)64unaryOp fnCon fnSym Concolic {concrete = c, symbolic = s} = do65 c' <- fnCon c66 let con = Concolic c'67 case s of68 Just s' -> fnSym s' <&> con . Just69 Nothing -> pure $ con Nothing7071binaryOp ::72 (D.RegVal -> D.RegVal -> Maybe D.RegVal) ->73 (SE.BitVector -> SE.BitVector -> Maybe SE.BitVector) ->74 Concolic D.RegVal ->75 Concolic D.RegVal ->76 Maybe (Concolic D.RegVal)77binaryOp fnCon fnSym lhs rhs =78 do79 c <- concrete lhs `fnCon` concrete rhs80 if hasSymbolic lhs || hasSymbolic rhs81 then82 let lhsS = getSymbolicDef SE.fromReg lhs83 rhsS = getSymbolicDef SE.fromReg rhs84 in (lhsS `fnSym` rhsS) <&> Concolic c . Just85 else pure $ Concolic c Nothing8687instance E.ValueRepr (Concolic D.RegVal) where88 fromLit ty v = Concolic (E.fromLit ty v) Nothing89 fromFloat fl = Concolic (E.fromFloat fl) Nothing90 fromDouble d = Concolic (E.fromDouble d) Nothing91 toWord64 Concolic {concrete = c} = E.toWord64 c9293 add = binaryOp E.add E.add94 sub = binaryOp E.sub E.sub95 mul = binaryOp E.mul E.mul96 div = binaryOp E.div E.div97 or = binaryOp E.or E.or98 xor = binaryOp E.xor E.xor99 and = binaryOp E.and E.and100 urem = binaryOp E.urem E.urem101 srem = binaryOp E.srem E.srem102 udiv = binaryOp E.udiv E.udiv103104 neg = unaryOp E.neg E.neg105106 sar = binaryOp E.sar E.sar107 shr = binaryOp E.shr E.shr108 shl = binaryOp E.shl E.shl109110 eq = binaryOp E.eq E.eq111 ne = binaryOp E.ne E.ne112 sle = binaryOp E.sle E.sle113 slt = binaryOp E.slt E.slt114 sge = binaryOp E.sge E.sge115 sgt = binaryOp E.sgt E.sgt116 ule = binaryOp E.ule E.ule117 ult = binaryOp E.ult E.ult118 uge = binaryOp E.uge E.uge119 ugt = binaryOp E.ugt E.ugt120121 wordToLong ty = unaryOp (E.wordToLong ty) (E.wordToLong ty)122 subType ty = unaryOp (E.subType ty) (E.subType ty)