1-- SPDX-FileCopyrightText: 2025 Sören Tempel <soeren+git@soeren-tempel.net>2--3-- SPDX-License-Identifier: GPL-3.0-only45module Language.QBE.Simulator.Symbolic.Expression6 ( BitVector,7 fromByte,8 fromReg,9 fromSExpr,10 toSExpr,11 symbolic,12 bitSize,13 toCond,14 )15where1617import Control.Exception (assert)18import Data.Bits (shiftL, (.&.))19import Data.Word (Word64, Word8)20import Language.QBE.Simulator.Default.Expression qualified as D21import Language.QBE.Simulator.Expression qualified as E22import Language.QBE.Simulator.Memory qualified as MEM23import Language.QBE.Types qualified as QBE24import SimpleBV qualified as SMT2526-- TODO: Floating point support.27newtype BitVector = BitVector SMT.SExpr28 deriving (Show, Eq)2930fromByte :: Word8 -> BitVector31fromByte byte = BitVector (SMT.bvLit 8 $ fromIntegral byte)3233fromReg :: D.RegVal -> BitVector34fromReg (D.VByte v) = BitVector (SMT.bvLit 8 $ fromIntegral v)35fromReg (D.VHalf v) = BitVector (SMT.bvLit 16 $ fromIntegral v)36fromReg (D.VWord v) = BitVector (SMT.bvLit 32 $ fromIntegral v)37fromReg (D.VLong v) = BitVector (SMT.bvLit 64 $ fromIntegral v)38fromReg (D.VSingle _) = error "symbolic floats not supported"39fromReg (D.VDouble _) = error "symbolic doubles not supported"4041-- TODO: remove42fromSExpr :: SMT.SExpr -> BitVector43fromSExpr = BitVector4445toSExpr :: BitVector -> SMT.SExpr46toSExpr (BitVector s) = s4748symbolic :: String -> QBE.ExtType -> BitVector49symbolic name ty = BitVector (SMT.const name $ QBE.extTypeBitSize ty)5051bitSize :: BitVector -> Int52bitSize = SMT.width . toSExpr5354-- In the QBE a condition (see `jnz`) is true if the Word value is not zero.55toCond :: Bool -> BitVector -> SMT.SExpr56toCond isTrue bv =57 -- Equality is only defined for Words.58 assert (bitSize bv == QBE.baseTypeBitSize QBE.Word) $59 let zeroSExpr = toSExpr (fromReg $ E.fromLit (QBE.Base QBE.Word) 0)60 in toCond' (toSExpr bv) zeroSExpr61 where62 toCond' lhs rhs63 | isTrue = SMT.not (SMT.eq lhs rhs) -- /= 064 | otherwise = SMT.eq lhs rhs -- == 06566------------------------------------------------------------------------6768instance MEM.Storable BitVector BitVector where69 toBytes (BitVector s) =70 assert (size `mod` 8 == 0) $71 map (BitVector . nthByte s) [1 .. fromIntegral size `div` 8]72 where73 size :: Integer74 size = fromIntegral $ SMT.width s7576 nthByte :: SMT.SExpr -> Int -> SMT.SExpr77 nthByte expr n = SMT.extract expr ((n - 1) * 8) 87879 fromBytes _ [] = Nothing80 fromBytes ty bytes@(BitVector s : xs) =81 if length bytes /= fromIntegral (QBE.loadByteSize ty)82 then Nothing83 else case (ty, bytes) of84 (QBE.LSubWord QBE.UnsignedByte, [_]) ->85 Just (BitVector (SMT.zeroExtend 24 concated))86 (QBE.LSubWord QBE.SignedByte, [_]) ->87 Just (BitVector (SMT.signExtend 24 concated))88 (QBE.LSubWord QBE.SignedHalf, [_, _]) ->89 Just (BitVector (SMT.signExtend 16 concated))90 (QBE.LSubWord QBE.UnsignedHalf, [_, _]) ->91 Just (BitVector (SMT.zeroExtend 16 concated))92 (QBE.LBase QBE.Word, [_, _, _, _]) ->93 Just (BitVector concated)94 (QBE.LBase QBE.Long, [_, _, _, _, _, _, _, _]) ->95 Just (BitVector concated)96 (QBE.LBase QBE.Single, [_, _, _, _]) ->97 error "float loading not implemented"98 (QBE.LBase QBE.Double, [_, _, _, _, _, _, _, _]) ->99 error "double loading not implemented"100 _ -> Nothing101 where102 concated :: SMT.SExpr103 concated = foldl concatBV s xs104105 concatBV :: SMT.SExpr -> BitVector -> SMT.SExpr106 concatBV acc (BitVector byte) =107 assert (SMT.width byte == 8) $108 SMT.concat byte acc109110------------------------------------------------------------------------111112binaryOp :: (SMT.SExpr -> SMT.SExpr -> SMT.SExpr) -> BitVector -> BitVector -> Maybe BitVector113binaryOp op (BitVector lhs) (BitVector rhs)114 | SMT.width lhs == SMT.width rhs = Just $ BitVector (lhs `op` rhs)115 | otherwise = Nothing116117-- TODO: Move this into the expression abstraction.118toShiftAmount :: Word64 -> BitVector -> Maybe BitVector119toShiftAmount size amount = amount `E.urem` E.fromLit (QBE.Base QBE.Word) size120121shiftOp :: (SMT.SExpr -> SMT.SExpr -> SMT.SExpr) -> BitVector -> BitVector -> Maybe BitVector122shiftOp op value amount@(BitVector SMT.Word) =123 case bitSize value of124 32 -> toShiftAmount 32 amount >>= binaryOp op value125 64 -> do126 shiftAmount <- toShiftAmount 64 amount127 E.wordToLong QBE.SLUnsignedWord shiftAmount >>= binaryOp op value128 _ -> Nothing129shiftOp _ _ _ = Nothing -- Shift amount must always be a Word.130131binaryBoolOp :: (SMT.SExpr -> SMT.SExpr -> SMT.SExpr) -> BitVector -> BitVector -> Maybe BitVector132binaryBoolOp op lhs rhs = do133 bv <- binaryOp op lhs rhs134 return $ fromSExpr (SMT.ite (toSExpr bv) trueValue falseValue)135 where136 -- TODO: Declare these as constants.137 trueValue :: SMT.SExpr138 trueValue = toSExpr $ E.fromLit (QBE.Base QBE.Long) 1139140 falseValue :: SMT.SExpr141 falseValue = toSExpr $ E.fromLit (QBE.Base QBE.Long) 0142143instance E.ValueRepr BitVector where144 fromLit ty n =145 let size = QBE.extTypeBitSize ty146 mask = (1 `shiftL` size) - 1147 in BitVector $ SMT.bvLit (fromIntegral size) $ fromIntegral (n .&. mask)148149 fromFloat = error "symbolic floats currently unsupported"150 fromDouble = error "symbolic doubles currently unsupported"151152 -- XXX: This only works for constants values, but this is fine since we implement153 -- concolic execution and can obtain the address from the concrete value part.154 toWord64 (BitVector value) =155 case SMT.sexprToVal value of156 SMT.Bits _ n -> fromIntegral n157 _ -> error "unrechable"158159 wordToLong (QBE.SLSubWord QBE.SignedByte) (BitVector s@SMT.Word) =160 Just $ BitVector (SMT.signExtend 56 (SMT.extract s 0 8))161 wordToLong (QBE.SLSubWord QBE.UnsignedByte) (BitVector s@SMT.Word) =162 Just $ BitVector (SMT.zeroExtend 56 (SMT.extract s 0 8))163 wordToLong (QBE.SLSubWord QBE.SignedHalf) (BitVector s@SMT.Word) =164 Just $ BitVector (SMT.signExtend 48 (SMT.extract s 0 16))165 wordToLong (QBE.SLSubWord QBE.UnsignedHalf) (BitVector s@SMT.Word) =166 Just $ BitVector (SMT.zeroExtend 48 (SMT.extract s 0 16))167 wordToLong QBE.SLSignedWord (BitVector s@SMT.Word) =168 Just $ BitVector (SMT.signExtend 32 s)169 wordToLong QBE.SLUnsignedWord (BitVector s@SMT.Word) =170 Just $ BitVector (SMT.zeroExtend 32 s)171 wordToLong _ _ = Nothing172173 subType QBE.Word v@(BitVector SMT.Word) = Just v174 subType QBE.Word (BitVector s@SMT.Long) =175 Just $ BitVector (SMT.extract s 0 32)176 subType QBE.Long v@(BitVector SMT.Long) = Just v177 subType _ _ = Nothing178179 add = binaryOp SMT.bvAdd180 sub = binaryOp SMT.bvSub181 mul = binaryOp SMT.bvMul182 div = binaryOp SMT.bvSDiv183 or = binaryOp SMT.bvOr184 xor = binaryOp SMT.bvXOr185 and = binaryOp SMT.bvAnd186 urem = binaryOp SMT.bvURem187 srem = binaryOp SMT.bvSRem188 udiv = binaryOp SMT.bvUDiv189190 neg (BitVector v) = Just $ BitVector (SMT.bvNeg v)191192 sar = shiftOp SMT.bvAShr193 shr = shiftOp SMT.bvLShr194 shl = shiftOp SMT.bvShl195196 eq = binaryBoolOp SMT.eq197 ne = binaryBoolOp (\lhs rhs -> SMT.not $ SMT.eq lhs rhs)198 sle = binaryBoolOp SMT.bvSLeq199 slt = binaryBoolOp SMT.bvSLt200 sge = binaryBoolOp (flip SMT.bvSLeq)201 sgt = binaryBoolOp (flip SMT.bvSLt)202 ule = binaryBoolOp SMT.bvULeq203 ult = binaryBoolOp SMT.bvULt204 uge = binaryBoolOp (\lhs rhs -> SMT.or (SMT.bvULt rhs lhs) (SMT.eq lhs rhs))205 ugt = binaryBoolOp (flip SMT.bvULt)