···11+{-# LANGUAGE LambdaCase #-}
22+33+module Executor where
44+55+import SymbolicExpression
66+import SymbolicState
77+import Opcode
88+import Data.ByteString (ByteString)
99+import qualified Data.ByteString as BS
1010+import Data.Maybe (fromMaybe)
1111+import Control.Monad (foldM)
1212+import Prelude hiding (LT, GT, EQ)
1313+1414+data StepResult
1515+ = Continue ExecState
1616+ | Branch ExecState ExecState
1717+ | Halt ExecState
1818+ | Error String
1919+ deriving (Show)
2020+2121+executeOpcode :: ByteString -> Opcode -> ExecState -> StepResult
2222+executeOpcode code op state = case op of
2323+ ADD -> binOp mkAdd state
2424+ MUL -> binOp mkMul state
2525+ SUB -> binOp mkSub state
2626+ DIV -> binOp mkDiv state
2727+ MOD -> binOp mkMod state
2828+2929+ LT -> binOp mkLt state
3030+ GT -> binOp mkGt state
3131+ EQ -> binOp mkEq state
3232+ ISZERO -> unOp mkIsZero state
3333+3434+ AND -> binOp mkAnd state
3535+ OR -> binOp mkOr state
3636+ XOR -> binOp mkXor state
3737+ NOT -> unOp mkNot state
3838+3939+ POP -> case popStack (stack state) of
4040+ Just (_, s') -> Continue state { stack = s', pc = pc state + 1 }
4141+ Nothing -> Error "Stack underflow"
4242+4343+ _ | Just n <- dupDepth op -> case dupStack n (stack state) of
4444+ Just s' -> Continue state { stack = s', pc = pc state + 1 }
4545+ Nothing -> Error "Stack underflow on DUP"
4646+4747+ _ | Just n <- swapDepth op -> case swapStack n (stack state) of
4848+ Just s' -> Continue state { stack = s', pc = pc state + 1 }
4949+ Nothing -> Error "Stack underflow on SWAP"
5050+5151+ MLOAD -> case popStack (stack state) of
5252+ Just (offset, s') ->
5353+ let value = case offset of
5454+ Concrete n -> mload n (memory state)
5555+ _ -> Symbolic "mload" (symbolicId state)
5656+ state' = state { symbolicId = symbolicId state + 1 }
5757+ in case pushStack value s' of
5858+ Just s'' -> Continue state' { stack = s'', pc = pc state' + 1 }
5959+ Nothing -> Error "Stack overflow"
6060+ Nothing -> Error "Stack underflow"
6161+6262+ MSTORE -> case popStackN 2 (stack state) of
6363+ Just ([offset, value], s') ->
6464+ let mem' = case offset of
6565+ Concrete n -> mstore n value (memory state)
6666+ _ -> memory state
6767+ in Continue state { stack = s', memory = mem', pc = pc state + 1 }
6868+ _ -> Error "Stack underflow"
6969+7070+ MSTORE8 -> case popStackN 2 (stack state) of
7171+ Just ([offset, value], s') ->
7272+ let mem' = case offset of
7373+ Concrete n -> mstore8 n value (memory state)
7474+ _ -> memory state
7575+ in Continue state { stack = s', memory = mem', pc = pc state + 1 }
7676+ _ -> Error "Stack underflow"
7777+7878+ SLOAD -> case popStack (stack state) of
7979+ Just (key, s') ->
8080+ let value = sload key (storage state)
8181+ in case pushStack value s' of
8282+ Just s'' -> Continue state { stack = s'', pc = pc state + 1 }
8383+ Nothing -> Error "Stack overflow"
8484+ Nothing -> Error "Stack underflow"
8585+8686+ SSTORE -> case popStackN 2 (stack state) of
8787+ Just ([key, value], s') ->
8888+ let stor' = sstore key value (storage state)
8989+ in Continue state { stack = s', storage = stor', pc = pc state + 1 }
9090+ _ -> Error "Stack underflow"
9191+9292+ JUMP -> case popStack (stack state) of
9393+ Just (Concrete dest, s') ->
9494+ Continue state { stack = s', pc = fromInteger dest }
9595+ Just (_, _) -> Error "Symbolic jump destination not supported"
9696+ Nothing -> Error "Stack underflow"
9797+9898+ JUMPI -> case popStackN 2 (stack state) of
9999+ Just ([Concrete dest, cond], s') ->
100100+ let trueBranch = addConstraint (CTrue cond) $
101101+ state { stack = s', pc = fromInteger dest }
102102+ falseBranch = addConstraint (CFalse cond) $
103103+ state { stack = s', pc = pc state + 1 }
104104+ in case cond of
105105+ Concrete 0 -> Continue falseBranch
106106+ Concrete _ -> Continue trueBranch
107107+ _ -> Branch trueBranch falseBranch
108108+ Just ([_, cond], s') -> Error "Symbolic jump destination not supported"
109109+ _ -> Error "Stack underflow"
110110+111111+ JUMPDEST -> Continue state { pc = pc state + 1 }
112112+113113+ PC -> case pushStack (Concrete $ fromIntegral $ pc state) (stack state) of
114114+ Just s' -> Continue state { stack = s', pc = pc state + 1 }
115115+ Nothing -> Error "Stack overflow"
116116+117117+ CALLER -> case pushStack Caller (stack state) of
118118+ Just s' -> Continue state { stack = s', pc = pc state + 1 }
119119+ Nothing -> Error "Stack overflow"
120120+121121+ CALLVALUE -> case pushStack CallValue (stack state) of
122122+ Just s' -> Continue state { stack = s', pc = pc state + 1 }
123123+ Nothing -> Error "Stack overflow"
124124+125125+ CALLDATALOAD -> case popStack (stack state) of
126126+ Just (offset, s') ->
127127+ let value = case offset of
128128+ Concrete n -> loadCalldata (calldata state) n
129129+ _ -> CallDataLoad offset
130130+ in case pushStack value s' of
131131+ Just s'' -> Continue state { stack = s'', pc = pc state + 1 }
132132+ Nothing -> Error "Stack overflow"
133133+ Nothing -> Error "Stack underflow"
134134+135135+ CALLDATASIZE -> case pushStack CallDataSize (stack state) of
136136+ Just s' -> Continue state { stack = s', pc = pc state + 1 }
137137+ Nothing -> Error "Stack overflow"
138138+139139+ STOP -> Halt state { halted = True }
140140+141141+ RETURN -> case popStackN 2 (stack state) of
142142+ Just ([offset, size], s') ->
143143+ let retVal = case (offset, size) of
144144+ (Concrete o, Concrete s) -> mload o (memory state)
145145+ _ -> Symbolic "return" (symbolicId state)
146146+ in Halt state { stack = s', returnData = Just retVal, halted = True }
147147+ _ -> Error "Stack underflow"
148148+149149+ REVERT -> Halt state { reverted = True, halted = True }
150150+151151+ INVALID -> Halt state { reverted = True, halted = True }
152152+153153+ _ -> Error $ "Unsupported opcode: " ++ show op
154154+155155+binOp :: (SymExpr -> SymExpr -> SymExpr) -> ExecState -> StepResult
156156+binOp f state = case popStackN 2 (stack state) of
157157+ Just ([a, b], s') ->
158158+ case pushStack (f a b) s' of
159159+ Just s'' -> Continue state { stack = s'', pc = pc state + 1 }
160160+ Nothing -> Error "Stack overflow"
161161+ _ -> Error "Stack underflow"
162162+163163+unOp :: (SymExpr -> SymExpr) -> ExecState -> StepResult
164164+unOp f state = case popStack (stack state) of
165165+ Just (a, s') ->
166166+ case pushStack (f a) s' of
167167+ Just s'' -> Continue state { stack = s'', pc = pc state + 1 }
168168+ Nothing -> Error "Stack overflow"
169169+ Nothing -> Error "Stack underflow"
170170+171171+loadCalldata :: ByteString -> Integer -> SymExpr
172172+loadCalldata cd offset
173173+ | offset >= 0 && offset < fromIntegral (BS.length cd) =
174174+ let bytes = BS.drop (fromInteger offset) cd
175175+ value = foldl (\acc b -> acc * 256 + fromIntegral b) 0 (BS.unpack $ BS.take 32 bytes)
176176+ in Concrete value
177177+ | otherwise = Concrete 0
178178+179179+step :: ByteString -> ExecState -> StepResult
180180+step code state
181181+ | halted state = Halt state
182182+ | pc state < 0 || pc state >= BS.length code = Halt state { halted = True }
183183+ | otherwise =
184184+ let byte = BS.index code (pc state)
185185+ opcode = decodeOpcode byte
186186+ in if isPush opcode
187187+ then
188188+ let n = pushBytes opcode
189189+ value = readBytes code (pc state + 1) n
190190+ in case pushStack (Concrete value) (stack state) of
191191+ Just s' -> Continue state { stack = s', pc = pc state + 1 + n }
192192+ Nothing -> Error "Stack overflow"
193193+ else executeOpcode code opcode state
194194+195195+run :: ByteString -> ExecState -> Int -> [ExecState]
196196+run code state maxSteps = go state 0
197197+ where
198198+ go st n
199199+ | n >= maxSteps = [st]
200200+ | halted st = [st]
201201+ | otherwise = case step code st of
202202+ Continue st' -> go st' (n + 1)
203203+ Halt st' -> [st']
204204+ Branch _ _ -> [st]
205205+ Error msg -> [st { halted = True, reverted = True }]
206206+207207+explore :: ByteString -> ExecState -> Int -> [ExecState]
208208+explore code initialState maxSteps = go [initialState] 0
209209+ where
210210+ go states n
211211+ | n >= maxSteps = states
212212+ | all halted states = states
213213+ | otherwise =
214214+ let states' = concatMap stepOne states
215215+ in go states' (n + 1)
216216+217217+ stepOne st
218218+ | halted st = [st]
219219+ | otherwise = case step code st of
220220+ Continue st' -> [st']
221221+ Halt st' -> [st']
222222+ Branch st1 st2 -> [st1, st2]
223223+ Error msg -> [st { halted = True, reverted = True }]
···11+{-# LANGUAGE DeriveGeneric #-}
22+{-# LANGUAGE DeriveAnyClass #-}
33+44+module SymbolicExpression where
55+66+import Data.Word
77+import Data.Map.Strict (Map)
88+import qualified Data.Map.Strict as Map
99+import GHC.Generics (Generic)
1010+import Data.Bits hiding (And, Xor)
1111+1212+data SymExpr
1313+ = Concrete Integer
1414+ | Symbolic String Int
1515+ | Add SymExpr SymExpr
1616+ | Sub SymExpr SymExpr
1717+ | Mul SymExpr SymExpr
1818+ | Div SymExpr SymExpr
1919+ | Mod SymExpr SymExpr
2020+ | Exp SymExpr SymExpr
2121+ | SDiv SymExpr SymExpr
2222+ | SMod SymExpr SymExpr
2323+ | Lt SymExpr SymExpr
2424+ | Gt SymExpr SymExpr
2525+ | SLt SymExpr SymExpr
2626+ | SGt SymExpr SymExpr
2727+ | Eq SymExpr SymExpr
2828+ | IsZero SymExpr
2929+ | And SymExpr SymExpr
3030+ | Or SymExpr SymExpr
3131+ | Xor SymExpr SymExpr
3232+ | Not SymExpr
3333+ | Byte SymExpr SymExpr
3434+ | Shl SymExpr SymExpr
3535+ | Shr SymExpr SymExpr
3636+ | Sar SymExpr SymExpr
3737+ | Sha3 SymExpr SymExpr
3838+ | Address
3939+ | Balance SymExpr
4040+ | Origin
4141+ | Caller
4242+ | CallValue
4343+ | CallDataLoad SymExpr
4444+ | CallDataSize
4545+ | CodeSize
4646+ | GasPrice
4747+ | BlockHash SymExpr
4848+ | Coinbase
4949+ | Timestamp
5050+ | Number
5151+ | Difficulty
5252+ | GasLimit
5353+ | ChainId
5454+ | SelfBalance
5555+ | BaseFee
5656+ deriving (Eq, Ord, Generic, Show)
5757+5858+data Constraint
5959+ = CTrue SymExpr
6060+ | CFalse SymExpr
6161+ | CEq SymExpr SymExpr
6262+ | CNeq SymExpr SymExpr
6363+ | CLt SymExpr SymExpr
6464+ | CGt SymExpr SymExpr
6565+ deriving (Eq, Ord, Show)
6666+6767+mkAdd :: SymExpr -> SymExpr -> SymExpr
6868+mkAdd (Concrete 0) e = e
6969+mkAdd e (Concrete 0) = e
7070+mkAdd (Concrete a) (Concrete b) = Concrete ((a + b) `mod` (2^256))
7171+mkAdd a b = Add a b
7272+7373+mkSub :: SymExpr -> SymExpr -> SymExpr
7474+mkSub e (Concrete 0) = e
7575+mkSub (Concrete a) (Concrete b) = Concrete ((a - b) `mod` (2^256))
7676+mkSub a b = Sub a b
7777+7878+mkMul :: SymExpr -> SymExpr -> SymExpr
7979+mkMul (Concrete 0) _ = Concrete 0
8080+mkMul _ (Concrete 0) = Concrete 0
8181+mkMul (Concrete 1) e = e
8282+mkMul e (Concrete 1) = e
8383+mkMul (Concrete a) (Concrete b) = Concrete ((a * b) `mod` (2^256))
8484+mkMul a b = Mul a b
8585+8686+mkDiv :: SymExpr -> SymExpr -> SymExpr
8787+mkDiv _ (Concrete 0) = Concrete 0
8888+mkDiv e (Concrete 1) = e
8989+mkDiv (Concrete a) (Concrete b) = if b == 0 then Concrete 0 else Concrete (a `div` b)
9090+mkDiv a b = Div a b
9191+9292+mkMod :: SymExpr -> SymExpr -> SymExpr
9393+mkMod _ (Concrete 0) = Concrete 0
9494+mkMod (Concrete a) (Concrete b) = if b == 0 then Concrete 0 else Concrete (a `mod` b)
9595+mkMod a b = Mod a b
9696+9797+mkLt :: SymExpr -> SymExpr -> SymExpr
9898+mkLt (Concrete a) (Concrete b) = Concrete (if a < b then 1 else 0)
9999+mkLt a b = Lt a b
100100+101101+mkGt :: SymExpr -> SymExpr -> SymExpr
102102+mkGt (Concrete a) (Concrete b) = Concrete (if a > b then 1 else 0)
103103+mkGt a b = Gt a b
104104+105105+mkEq :: SymExpr -> SymExpr -> SymExpr
106106+mkEq a b | a == b = Concrete 1
107107+mkEq (Concrete a) (Concrete b) = Concrete (if a == b then 1 else 0)
108108+mkEq a b = Eq a b
109109+110110+mkIsZero :: SymExpr -> SymExpr
111111+mkIsZero (Concrete 0) = Concrete 1
112112+mkIsZero (Concrete _) = Concrete 0
113113+mkIsZero e = IsZero e
114114+115115+mkAnd :: SymExpr -> SymExpr -> SymExpr
116116+mkAnd (Concrete 0) _ = Concrete 0
117117+mkAnd _ (Concrete 0) = Concrete 0
118118+mkAnd (Concrete a) (Concrete b) = Concrete (a .&. b)
119119+mkAnd a b = And a b
120120+121121+mkOr :: SymExpr -> SymExpr -> SymExpr
122122+mkOr (Concrete a) (Concrete b) = Concrete (a .|. b)
123123+mkOr a b = Or a b
124124+125125+mkXor :: SymExpr -> SymExpr -> SymExpr
126126+mkXor (Concrete a) (Concrete b) = Concrete (xor a b)
127127+mkXor a b = Xor a b
128128+129129+mkNot :: SymExpr -> SymExpr
130130+mkNot (Concrete a) = Concrete ((2^256 - 1) - a)
131131+mkNot e = Not e
132132+133133+prettyExpr :: SymExpr -> String
134134+prettyExpr (Concrete n) = show n
135135+prettyExpr (Symbolic name id) = name ++ "_" ++ show id
136136+prettyExpr (Add a b) = "(" ++ prettyExpr a ++ " + " ++ prettyExpr b ++ ")"
137137+prettyExpr (Sub a b) = "(" ++ prettyExpr a ++ " - " ++ prettyExpr b ++ ")"
138138+prettyExpr (Mul a b) = "(" ++ prettyExpr a ++ " * " ++ prettyExpr b ++ ")"
139139+prettyExpr (Div a b) = "(" ++ prettyExpr a ++ " / " ++ prettyExpr b ++ ")"
140140+prettyExpr (Mod a b) = "(" ++ prettyExpr a ++ " % " ++ prettyExpr b ++ ")"
141141+prettyExpr (Lt a b) = "(" ++ prettyExpr a ++ " < " ++ prettyExpr b ++ ")"
142142+prettyExpr (Gt a b) = "(" ++ prettyExpr a ++ " > " ++ prettyExpr b ++ ")"
143143+prettyExpr (Eq a b) = "(" ++ prettyExpr a ++ " == " ++ prettyExpr b ++ ")"
144144+prettyExpr (IsZero a) = "IsZero(" ++ prettyExpr a ++ ")"
145145+prettyExpr (And a b) = "(" ++ prettyExpr a ++ " & " ++ prettyExpr b ++ ")"
146146+prettyExpr (Or a b) = "(" ++ prettyExpr a ++ " | " ++ prettyExpr b ++ ")"
147147+prettyExpr (Not a) = "~" ++ prettyExpr a
148148+prettyExpr Caller = "caller"
149149+prettyExpr CallValue = "callvalue"
150150+prettyExpr (CallDataLoad offset) = "calldataload(" ++ prettyExpr offset ++ ")"
151151+prettyExpr CallDataSize = "calldatasize"
152152+prettyExpr _ = "<expr>"
153153+154154+prettyConstraint :: Constraint -> String
155155+prettyConstraint (CTrue e) = prettyExpr e ++ " != 0"
156156+prettyConstraint (CFalse e) = prettyExpr e ++ " == 0"
157157+prettyConstraint (CEq a b) = prettyExpr a ++ " == " ++ prettyExpr b
158158+prettyConstraint (CNeq a b) = prettyExpr a ++ " != " ++ prettyExpr b
159159+prettyConstraint (CLt a b) = prettyExpr a ++ " < " ++ prettyExpr b
160160+prettyConstraint (CGt a b) = prettyExpr a ++ " > " ++ prettyExpr b