an intermediate symbolic execution engine for EVM bytecode
16

Configure Feed

Select the types of activity you want to include in your feed.

symevm / src / SymbolicState.hs
4.4 kB 154 lines
1{-# LANGUAGE DeriveGeneric #-} 2 3module SymbolicState where 4 5import SymbolicExpression 6import Data.Map.Strict (Map) 7import qualified Data.Map.Strict as Map 8import Data.Word 9import Data.ByteString (ByteString) 10import qualified Data.ByteString as BS 11import GHC.Generics (Generic) 12 13newtype SymStack = SymStack [SymExpr] 14 deriving (Show, Eq) 15 16newtype SymMemory = SymMemory (Map Integer SymExpr) 17 deriving (Show, Eq) 18 19newtype SymStorage = SymStorage (Map SymExpr SymExpr) 20 deriving (Show, Eq) 21 22data ExecState = ExecState 23 { stack :: SymStack 24 , memory :: SymMemory 25 , storage :: SymStorage 26 , pc :: Int 27 , gas :: Integer 28 , constraints :: [Constraint] 29 , calldata :: ByteString 30 , returnData :: Maybe SymExpr 31 , reverted :: Bool 32 , halted :: Bool 33 , symbolicId :: Int 34 } deriving (Show) 35 36initState :: ByteString -> ExecState 37initState cd = ExecState 38 { stack = emptyStack 39 , memory = emptyMemory 40 , storage = emptyStorage 41 , pc = 0 42 , gas = 1000000 43 , constraints = [] 44 , calldata = cd 45 , returnData = Nothing 46 , reverted = False 47 , halted = False 48 , symbolicId = 0 49 } 50 51emptyStack :: SymStack 52emptyStack = SymStack [] 53 54pushStack :: SymExpr -> SymStack -> Maybe SymStack 55pushStack expr (SymStack xs) 56 | length xs >= 1024 = Nothing 57 | otherwise = Just (SymStack (expr : xs)) 58 59popStack :: SymStack -> Maybe (SymExpr, SymStack) 60popStack (SymStack []) = Nothing 61popStack (SymStack (x:xs)) = Just (x, SymStack xs) 62 63popStackN :: Int -> SymStack -> Maybe ([SymExpr], SymStack) 64popStackN n (SymStack xs) 65 | n > length xs = Nothing 66 | otherwise = Just (take n xs, SymStack (drop n xs)) 67 68peekStack :: Int -> SymStack -> Maybe SymExpr 69peekStack n (SymStack xs) 70 | n >= length xs = Nothing 71 | otherwise = Just (xs !! n) 72 73dupStack :: Int -> SymStack -> Maybe SymStack 74dupStack n s = do 75 expr <- peekStack (n - 1) s 76 pushStack expr s 77 78swapStack :: Int -> SymStack -> Maybe SymStack 79swapStack n (SymStack xs) 80 | n >= length xs = Nothing 81 | otherwise = Just (SymStack (xs0 : (take (n-1) xs1) ++ [xn] ++ (drop n xs1))) 82 where 83 xs0 = head xs 84 xs1 = tail xs 85 xn = xs !! n 86 87stackSize :: SymStack -> Int 88stackSize (SymStack xs) = length xs 89 90emptyMemory :: SymMemory 91emptyMemory = SymMemory Map.empty 92 93mstore :: Integer -> SymExpr -> SymMemory -> SymMemory 94mstore offset value (SymMemory m) = SymMemory (Map.insert offset value m) 95 96mstore8 :: Integer -> SymExpr -> SymMemory -> SymMemory 97mstore8 = mstore 98 99mload :: Integer -> SymMemory -> SymExpr 100mload offset (SymMemory m) = Map.findWithDefault (Concrete 0) offset m 101 102emptyStorage :: SymStorage 103emptyStorage = SymStorage Map.empty 104 105sstore :: SymExpr -> SymExpr -> SymStorage -> SymStorage 106sstore key value (SymStorage s) = SymStorage (Map.insert key value s) 107 108sload :: SymExpr -> SymStorage -> SymExpr 109sload key (SymStorage s) = Map.findWithDefault (Concrete 0) key s 110 111addConstraint :: Constraint -> ExecState -> ExecState 112addConstraint c state = state { constraints = c : constraints state } 113 114newSymbolic :: String -> ExecState -> (SymExpr, ExecState) 115newSymbolic name state = 116 let sid = symbolicId state 117 sym = Symbolic name sid 118 state' = state { symbolicId = sid + 1 } 119 in (sym, state') 120 121prettyStack :: SymStack -> String 122prettyStack (SymStack xs) = unlines $ 123 [ "[" ++ show i ++ "] " ++ prettyExpr expr 124 | (i, expr) <- zip [0..] xs ] 125 126prettyMemory :: SymMemory -> String 127prettyMemory (SymMemory m) = unlines $ 128 [ " 0x" ++ showHex offset ++ ": " ++ prettyExpr value 129 | (offset, value) <- Map.toList m ] 130 131prettyStorage :: SymStorage -> String 132prettyStorage (SymStorage s) = unlines $ 133 [ " " ++ prettyExpr key ++ " => " ++ prettyExpr value 134 | (key, value) <- Map.toList s ] 135 136showHex :: Integer -> String 137showHex n = reverse $ take 4 $ reverse (go n) ++ repeat '0' 138 where 139 go 0 = "0" 140 go n = let (q, r) = n `divMod` 16 141 digit = "0123456789abcdef" !! fromIntegral r 142 in if q == 0 then [digit] else go q ++ [digit] 143 144prettyState :: ExecState -> String 145prettyState state = unlines 146 [ "PC: " ++ show (pc state) 147 , "Gas: " ++ show (gas state) 148 , "Halted: " ++ show (halted state) 149 , "Reverted: " ++ show (reverted state) 150 , "Stack:" 151 , prettyStack (stack state) 152 , "Constraints: " ++ show (length (constraints state)) 153 , unlines [" " ++ prettyConstraint c | c <- reverse (constraints state)] 154 ]