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 toSExpr,10 symbolic,11 bitSize,12 toCond,13 )14where1516import Control.DeepSeq (NFData)17import Control.Exception (assert)18import Data.Bits (shiftL, (.&.))19import Data.Word (Word64, Word8)20import GHC.Generics (Generic)21import Language.QBE.Simulator.Default.Expression qualified as D22import Language.QBE.Simulator.Expression qualified as E23import Language.QBE.Simulator.Memory qualified as MEM24import Language.QBE.Types qualified as QBE25import SimpleBV qualified as SMT2627-- TODO: Floating point support.28newtype BitVector = BitVector SMT.SExpr29 deriving (Show, Eq, Generic)3031instance NFData BitVector3233fromByte :: Word8 -> BitVector34fromByte byte = BitVector (SMT.bvLit 8 $ fromIntegral byte)3536fromReg :: D.RegVal -> BitVector37fromReg (D.VByte v) = BitVector (SMT.bvLit 8 $ fromIntegral v)38fromReg (D.VHalf v) = BitVector (SMT.bvLit 16 $ fromIntegral v)39fromReg (D.VWord v) = BitVector (SMT.bvLit 32 $ fromIntegral v)40fromReg (D.VLong v) = BitVector (SMT.bvLit 64 $ fromIntegral v)41fromReg (D.VSingle _) = error "symbolic floats not supported"42fromReg (D.VDouble _) = error "symbolic doubles not supported"4344toSExpr :: BitVector -> SMT.SExpr45toSExpr (BitVector s) = s4647symbolic :: String -> QBE.ExtType -> BitVector48symbolic name ty = BitVector (SMT.const name $ QBE.extTypeBitSize ty)4950bitSize :: BitVector -> Int51bitSize = SMT.width . toSExpr5253-- In the QBE a condition (see `jnz`) is true if the Word value is not zero.54toCond :: Bool -> BitVector -> SMT.SExpr55toCond isTrue bv =56 -- Equality is only defined for Words.57 assert (bitSize bv == QBE.baseTypeBitSize QBE.Word) $58 let zeroSExpr = toSExpr (fromReg $ E.fromLit (QBE.Base QBE.Word) 0)59 in toCond' (toSExpr bv) zeroSExpr60 where61 toCond' lhs rhs62 | isTrue = SMT.not (SMT.eq lhs rhs) -- /= 063 | otherwise = SMT.eq lhs rhs -- == 06465------------------------------------------------------------------------6667instance MEM.Storable BitVector BitVector where68 toBytes (BitVector s) =69 assert (size `mod` 8 == 0) $70 map (BitVector . nthByte s) [1 .. fromIntegral size `div` 8]71 where72 size :: Integer73 size = fromIntegral $ SMT.width s7475 nthByte :: SMT.SExpr -> Int -> SMT.SExpr76 nthByte expr n = SMT.extract expr ((n - 1) * 8) 87778 fromBytes _ [] = Nothing79 fromBytes ty bytes@(BitVector s : xs) =80 if length bytes /= fromIntegral (QBE.loadByteSize ty)81 then Nothing82 else case (ty, bytes) of83 (QBE.LSubWord QBE.UnsignedByte, [_]) ->84 Just (BitVector (SMT.zeroExtend 24 concated))85 (QBE.LSubWord QBE.SignedByte, [_]) ->86 Just (BitVector (SMT.signExtend 24 concated))87 (QBE.LSubWord QBE.SignedHalf, [_, _]) ->88 Just (BitVector (SMT.signExtend 16 concated))89 (QBE.LSubWord QBE.UnsignedHalf, [_, _]) ->90 Just (BitVector (SMT.zeroExtend 16 concated))91 (QBE.LBase QBE.Word, [_, _, _, _]) ->92 Just (BitVector concated)93 (QBE.LBase QBE.Long, [_, _, _, _, _, _, _, _]) ->94 Just (BitVector concated)95 (QBE.LBase QBE.Single, [_, _, _, _]) ->96 error "float loading not implemented"97 (QBE.LBase QBE.Double, [_, _, _, _, _, _, _, _]) ->98 error "double loading not implemented"99 _ -> Nothing100 where101 concated :: SMT.SExpr102 concated = foldl concatBV s xs103104 concatBV :: SMT.SExpr -> BitVector -> SMT.SExpr105 concatBV acc (BitVector byte) =106 assert (SMT.width byte == 8) $107 SMT.concat byte acc108109------------------------------------------------------------------------110111binaryOp :: (SMT.SExpr -> SMT.SExpr -> SMT.SExpr) -> BitVector -> BitVector -> Maybe BitVector112binaryOp op (BitVector lhs) (BitVector rhs)113 | SMT.width lhs == SMT.width rhs = Just $ BitVector (lhs `op` rhs)114 | otherwise = Nothing115116-- TODO: Move this into the expression abstraction.117toShiftAmount :: Word64 -> BitVector -> Maybe BitVector118toShiftAmount size amount = amount `E.urem` E.fromLit (QBE.Base QBE.Word) size119120shiftOp :: (SMT.SExpr -> SMT.SExpr -> SMT.SExpr) -> BitVector -> BitVector -> Maybe BitVector121shiftOp op value amount@(BitVector SMT.Word) =122 case bitSize value of123 32 -> toShiftAmount 32 amount >>= binaryOp op value124 64 -> do125 shiftAmount <- toShiftAmount 64 amount126 E.extend (QBE.Base QBE.Long) False shiftAmount >>= binaryOp op value127 _ -> Nothing128shiftOp _ _ _ = Nothing -- Shift amount must always be a Word.129130binaryBoolOp :: (SMT.SExpr -> SMT.SExpr -> SMT.SExpr) -> BitVector -> BitVector -> Maybe BitVector131binaryBoolOp op lhs rhs = do132 bv <- binaryOp op lhs rhs133 return $ BitVector (SMT.ite (toSExpr bv) trueValue falseValue)134 where135 -- TODO: Declare these as constants.136 trueValue :: SMT.SExpr137 trueValue = toSExpr $ E.fromLit (QBE.Base QBE.Long) 1138139 falseValue :: SMT.SExpr140 falseValue = toSExpr $ E.fromLit (QBE.Base QBE.Long) 0141142instance E.ValueRepr BitVector where143 fromLit ty n =144 let size = QBE.extTypeBitSize ty145 mask = (1 `shiftL` size) - 1146 in BitVector $ SMT.bvLit (fromIntegral size) $ fromIntegral (n .&. mask)147148 fromFloat = error "symbolic floats currently unsupported"149 fromDouble = error "symbolic doubles currently unsupported"150151 -- XXX: This only works for constants values, but this is fine since we implement152 -- concolic execution and can obtain the address from the concrete value part.153 toWord64 (BitVector value) =154 case SMT.sexprToVal value of155 SMT.Bits _ n -> fromIntegral n156 _ -> error "unrechable"157158 getType v = case bitSize v of159 08 -> QBE.Byte160 16 -> QBE.HalfWord161 32 -> QBE.Base QBE.Word162 64 -> QBE.Base QBE.Long163 _ -> error "unreachable"164165 floatToInt = error "symbolic float conversion not supported"166 intToFloat = error "symbolic float conversion not supported"167 extendFloat = error "symbolic float extension not supported"168 truncFloat = error "symbolic float trunction not supported"169170 extend extTy isSigned val@(BitVector s)171 | QBE.extTypeBitSize extTy <= bitSize val = Nothing172 | otherwise = Just $ BitVector (extFunc targetSize s)173 where174 targetSize :: Integer175 targetSize = fromIntegral $ QBE.extTypeBitSize extTy - bitSize val176177 extFunc :: Integer -> SMT.SExpr -> SMT.SExpr178 extFunc = if isSigned then SMT.signExtend else SMT.zeroExtend179180 extract extTy val@(BitVector s)181 | QBE.extTypeBitSize extTy > bitSize val = Nothing182 | otherwise = Just $ BitVector (SMT.extract s 0 $ QBE.extTypeBitSize extTy)183184 add = binaryOp SMT.bvAdd185 sub = binaryOp SMT.bvSub186 mul = binaryOp SMT.bvMul187 div = binaryOp SMT.bvSDiv188 or = binaryOp SMT.bvOr189 xor = binaryOp SMT.bvXOr190 and = binaryOp SMT.bvAnd191 urem = binaryOp SMT.bvURem192 srem = binaryOp SMT.bvSRem193 udiv = binaryOp SMT.bvUDiv194195 neg (BitVector v) = Just $ BitVector (SMT.bvNeg v)196197 sar = shiftOp SMT.bvAShr198 shr = shiftOp SMT.bvLShr199 shl = shiftOp SMT.bvShl200201 eq = binaryBoolOp SMT.eq202 ne = binaryBoolOp (\lhs rhs -> SMT.not $ SMT.eq lhs rhs)203 sle = binaryBoolOp SMT.bvSLeq204 slt = binaryBoolOp SMT.bvSLt205 sge = binaryBoolOp SMT.bvSGeq206 sgt = binaryBoolOp SMT.bvSGt207 ule = binaryBoolOp SMT.bvULeq208 ult = binaryBoolOp SMT.bvULt209 uge = binaryBoolOp SMT.bvUGeq210 ugt = binaryBoolOp SMT.bvUGt211212 ord = error "symbolic ordered comparison not supported"213 unord = error "symbolic unordered comparison not supported"