1 /*
2 	This file is part of solidity.
3 
4 	solidity is free software: you can redistribute it and/or modify
5 	it under the terms of the GNU General Public License as published by
6 	the Free Software Foundation, either version 3 of the License, or
7 	(at your option) any later version.
8 
9 	solidity is distributed in the hope that it will be useful,
10 	but WITHOUT ANY WARRANTY; without even the implied warranty of
11 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 	GNU General Public License for more details.
13 
14 	You should have received a copy of the GNU General Public License
15 	along with solidity.  If not, see <http://www.gnu.org/licenses/>.
16 */
17 // SPDX-License-Identifier: GPL-3.0
18 /** @file Instruction.h
19  * @author Gav Wood <i@gavwood.com>
20  * @date 2014
21  */
22 
23 #pragma once
24 
25 #include <libevmasm/Exceptions.h>
26 #include <libsolutil/Common.h>
27 #include <libsolutil/Assertions.h>
28 #include <libsolutil/Numeric.h>
29 #include <functional>
30 
31 #undef MSIZE // remove MSIZE definition from <sys/params.h>, included by boost 1.66.0
32 
33 namespace solidity::evmasm
34 {
35 
36 /// Virtual machine bytecode instruction.
37 enum class Instruction: uint8_t
38 {
39 	STOP = 0x00,		///< halts execution
40 	ADD,				///< addition operation
41 	MUL,				///< multiplication operation
42 	SUB,				///< subtraction operation
43 	DIV,				///< integer division operation
44 	SDIV,				///< signed integer division operation
45 	MOD,				///< modulo remainder operation
46 	SMOD,				///< signed modulo remainder operation
47 	ADDMOD,				///< unsigned modular addition
48 	MULMOD,				///< unsigned modular multiplication
49 	EXP,				///< exponential operation
50 	SIGNEXTEND,			///< extend length of signed integer
51 
52 	LT = 0x10,			///< less-than comparison
53 	GT,					///< greater-than comparison
54 	SLT,				///< signed less-than comparison
55 	SGT,				///< signed greater-than comparison
56 	EQ,					///< equality comparison
57 	ISZERO,				///< simple not operator
58 	AND,				///< bitwise AND operation
59 	OR,					///< bitwise OR operation
60 	XOR,				///< bitwise XOR operation
61 	NOT,				///< bitwise NOT operation
62 	BYTE,				///< retrieve single byte from word
63 	SHL,				///< bitwise SHL operation
64 	SHR,				///< bitwise SHR operation
65 	SAR,				///< bitwise SAR operation
66 
67 	KECCAK256 = 0x20,		///< compute KECCAK-256 hash
68 
69 	ADDRESS = 0x30,		///< get address of currently executing account
70 	BALANCE,			///< get balance of the given account
71 	ORIGIN,				///< get execution origination address
72 	CALLER,				///< get caller address
73 	CALLVALUE,			///< get deposited value by the instruction/transaction responsible for this execution
74 	CALLDATALOAD,		///< get input data of current environment
75 	CALLDATASIZE,		///< get size of input data in current environment
76 	CALLDATACOPY,		///< copy input data in current environment to memory
77 	CODESIZE,			///< get size of code running in current environment
78 	CODECOPY,			///< copy code running in current environment to memory
79 	GASPRICE,			///< get price of gas in current environment
80 	EXTCODESIZE,		///< get external code size (from another contract)
81 	EXTCODECOPY,		///< copy external code (from another contract)
82 	RETURNDATASIZE = 0x3d,	///< get size of return data buffer
83 	RETURNDATACOPY = 0x3e,	///< copy return data in current environment to memory
84 	EXTCODEHASH = 0x3f,	///< get external code hash (from another contract)
85 
86 	BLOCKHASH = 0x40,	///< get hash of most recent complete block
87 	COINBASE,			///< get the block's coinbase address
88 	TIMESTAMP,			///< get the block's timestamp
89 	NUMBER,				///< get the block's number
90 	DIFFICULTY,			///< get the block's difficulty
91 	GASLIMIT,			///< get the block's gas limit
92 	CHAINID,			///< get the config's chainid param
93 	SELFBALANCE,		///< get balance of the current account
94 	BASEFEE,            ///< get the block's basefee
95 
96 	POP = 0x50,			///< remove item from stack
97 	MLOAD,				///< load word from memory
98 	MSTORE,				///< save word to memory
99 	MSTORE8,			///< save byte to memory
100 	SLOAD,				///< load word from storage
101 	SSTORE,				///< save word to storage
102 	JUMP,				///< alter the program counter
103 	JUMPI,				///< conditionally alter the program counter
104 	PC,					///< get the program counter
105 	MSIZE,				///< get the size of active memory
106 	GAS,				///< get the amount of available gas
107 	JUMPDEST,			///< set a potential jump destination
108 
109 	PUSH1 = 0x60,		///< place 1 byte item on stack
110 	PUSH2,				///< place 2 byte item on stack
111 	PUSH3,				///< place 3 byte item on stack
112 	PUSH4,				///< place 4 byte item on stack
113 	PUSH5,				///< place 5 byte item on stack
114 	PUSH6,				///< place 6 byte item on stack
115 	PUSH7,				///< place 7 byte item on stack
116 	PUSH8,				///< place 8 byte item on stack
117 	PUSH9,				///< place 9 byte item on stack
118 	PUSH10,				///< place 10 byte item on stack
119 	PUSH11,				///< place 11 byte item on stack
120 	PUSH12,				///< place 12 byte item on stack
121 	PUSH13,				///< place 13 byte item on stack
122 	PUSH14,				///< place 14 byte item on stack
123 	PUSH15,				///< place 15 byte item on stack
124 	PUSH16,				///< place 16 byte item on stack
125 	PUSH17,				///< place 17 byte item on stack
126 	PUSH18,				///< place 18 byte item on stack
127 	PUSH19,				///< place 19 byte item on stack
128 	PUSH20,				///< place 20 byte item on stack
129 	PUSH21,				///< place 21 byte item on stack
130 	PUSH22,				///< place 22 byte item on stack
131 	PUSH23,				///< place 23 byte item on stack
132 	PUSH24,				///< place 24 byte item on stack
133 	PUSH25,				///< place 25 byte item on stack
134 	PUSH26,				///< place 26 byte item on stack
135 	PUSH27,				///< place 27 byte item on stack
136 	PUSH28,				///< place 28 byte item on stack
137 	PUSH29,				///< place 29 byte item on stack
138 	PUSH30,				///< place 30 byte item on stack
139 	PUSH31,				///< place 31 byte item on stack
140 	PUSH32,				///< place 32 byte item on stack
141 
142 	DUP1 = 0x80,		///< copies the highest item in the stack to the top of the stack
143 	DUP2,				///< copies the second highest item in the stack to the top of the stack
144 	DUP3,				///< copies the third highest item in the stack to the top of the stack
145 	DUP4,				///< copies the 4th highest item in the stack to the top of the stack
146 	DUP5,				///< copies the 5th highest item in the stack to the top of the stack
147 	DUP6,				///< copies the 6th highest item in the stack to the top of the stack
148 	DUP7,				///< copies the 7th highest item in the stack to the top of the stack
149 	DUP8,				///< copies the 8th highest item in the stack to the top of the stack
150 	DUP9,				///< copies the 9th highest item in the stack to the top of the stack
151 	DUP10,				///< copies the 10th highest item in the stack to the top of the stack
152 	DUP11,				///< copies the 11th highest item in the stack to the top of the stack
153 	DUP12,				///< copies the 12th highest item in the stack to the top of the stack
154 	DUP13,				///< copies the 13th highest item in the stack to the top of the stack
155 	DUP14,				///< copies the 14th highest item in the stack to the top of the stack
156 	DUP15,				///< copies the 15th highest item in the stack to the top of the stack
157 	DUP16,				///< copies the 16th highest item in the stack to the top of the stack
158 
159 	SWAP1 = 0x90,		///< swaps the highest and second highest value on the stack
160 	SWAP2,				///< swaps the highest and third highest value on the stack
161 	SWAP3,				///< swaps the highest and 4th highest value on the stack
162 	SWAP4,				///< swaps the highest and 5th highest value on the stack
163 	SWAP5,				///< swaps the highest and 6th highest value on the stack
164 	SWAP6,				///< swaps the highest and 7th highest value on the stack
165 	SWAP7,				///< swaps the highest and 8th highest value on the stack
166 	SWAP8,				///< swaps the highest and 9th highest value on the stack
167 	SWAP9,				///< swaps the highest and 10th highest value on the stack
168 	SWAP10,				///< swaps the highest and 11th highest value on the stack
169 	SWAP11,				///< swaps the highest and 12th highest value on the stack
170 	SWAP12,				///< swaps the highest and 13th highest value on the stack
171 	SWAP13,				///< swaps the highest and 14th highest value on the stack
172 	SWAP14,				///< swaps the highest and 15th highest value on the stack
173 	SWAP15,				///< swaps the highest and 16th highest value on the stack
174 	SWAP16,				///< swaps the highest and 17th highest value on the stack
175 
176 	LOG0 = 0xa0,		///< Makes a log entry; no topics.
177 	LOG1,				///< Makes a log entry; 1 topic.
178 	LOG2,				///< Makes a log entry; 2 topics.
179 	LOG3,				///< Makes a log entry; 3 topics.
180 	LOG4,				///< Makes a log entry; 4 topics.
181 
182 	CREATE = 0xf0,		///< create a new account with associated code
183 	CALL,				///< message-call into an account
184 	CALLCODE,			///< message-call with another account's code only
185 	RETURN,				///< halt execution returning output data
186 	DELEGATECALL,		///< like CALLCODE but keeps caller's value and sender
187 	CREATE2 = 0xf5,		///< create new account with associated code at address `sha3(0xff + sender + salt + init code) % 2**160`
188 	STATICCALL = 0xfa,	///< like CALL but disallow state modifications
189 
190 	REVERT = 0xfd,		///< halt execution, revert state and return output data
191 	INVALID = 0xfe,		///< invalid instruction for expressing runtime errors (e.g., division-by-zero)
192 	SELFDESTRUCT = 0xff	///< halt execution and register account for later deletion
193 };
194 
195 /// @returns true if the instruction is a PUSH
isPushInstruction(Instruction _inst)196 inline bool isPushInstruction(Instruction _inst)
197 {
198 	return Instruction::PUSH1 <= _inst && _inst <= Instruction::PUSH32;
199 }
200 
201 /// @returns true if the instruction is a DUP
isDupInstruction(Instruction _inst)202 inline bool isDupInstruction(Instruction _inst)
203 {
204 	return Instruction::DUP1 <= _inst && _inst <= Instruction::DUP16;
205 }
206 
207 /// @returns true if the instruction is a SWAP
isSwapInstruction(Instruction _inst)208 inline bool isSwapInstruction(Instruction _inst)
209 {
210 	return Instruction::SWAP1 <= _inst && _inst <= Instruction::SWAP16;
211 }
212 
213 /// @returns true if the instruction is a LOG
isLogInstruction(Instruction _inst)214 inline bool isLogInstruction(Instruction _inst)
215 {
216 	return Instruction::LOG0 <= _inst && _inst <= Instruction::LOG4;
217 }
218 
219 /// @returns the number of PUSH Instruction _inst
getPushNumber(Instruction _inst)220 inline unsigned getPushNumber(Instruction _inst)
221 {
222 	return (uint8_t)_inst - unsigned(Instruction::PUSH1) + 1;
223 }
224 
225 /// @returns the number of DUP Instruction _inst
getDupNumber(Instruction _inst)226 inline unsigned getDupNumber(Instruction _inst)
227 {
228 	return (uint8_t)_inst - unsigned(Instruction::DUP1) + 1;
229 }
230 
231 /// @returns the number of SWAP Instruction _inst
getSwapNumber(Instruction _inst)232 inline unsigned getSwapNumber(Instruction _inst)
233 {
234 	return (uint8_t)_inst - unsigned(Instruction::SWAP1) + 1;
235 }
236 
237 /// @returns the number of LOG Instruction _inst
getLogNumber(Instruction _inst)238 inline unsigned getLogNumber(Instruction _inst)
239 {
240 	return (uint8_t)_inst - unsigned(Instruction::LOG0);
241 }
242 
243 /// @returns the PUSH<_number> instruction
pushInstruction(unsigned _number)244 inline Instruction pushInstruction(unsigned _number)
245 {
246 	assertThrow(1 <= _number && _number <= 32, InvalidOpcode, std::string("Invalid PUSH instruction requested (") + std::to_string(_number) + ").");
247 	return Instruction(unsigned(Instruction::PUSH1) + _number - 1);
248 }
249 
250 /// @returns the DUP<_number> instruction
dupInstruction(unsigned _number)251 inline Instruction dupInstruction(unsigned _number)
252 {
253 	assertThrow(1 <= _number && _number <= 16, InvalidOpcode, std::string("Invalid DUP instruction requested (") + std::to_string(_number) + ").");
254 	return Instruction(unsigned(Instruction::DUP1) + _number - 1);
255 }
256 
257 /// @returns the SWAP<_number> instruction
swapInstruction(unsigned _number)258 inline Instruction swapInstruction(unsigned _number)
259 {
260 	assertThrow(1 <= _number && _number <= 16, InvalidOpcode, std::string("Invalid SWAP instruction requested (") + std::to_string(_number) + ").");
261 	return Instruction(unsigned(Instruction::SWAP1) + _number - 1);
262 }
263 
264 /// @returns the LOG<_number> instruction
logInstruction(unsigned _number)265 inline Instruction logInstruction(unsigned _number)
266 {
267 	assertThrow(_number <= 4, InvalidOpcode, std::string("Invalid LOG instruction requested (") + std::to_string(_number) + ").");
268 	return Instruction(unsigned(Instruction::LOG0) + _number);
269 }
270 
271 enum class Tier : unsigned
272 {
273 	Zero = 0,	// 0, Zero
274 	Base,		// 2, Quick
275 	VeryLow,	// 3, Fastest
276 	Low,		// 5, Fast
277 	Mid,		// 8, Mid
278 	High,		// 10, Slow
279 	Ext,		// 20, Ext
280 	ExtCode,	// 700, Extcode
281 	Balance,	// 400, Balance
282 	Special,	// multiparam or otherwise special
283 	Invalid		// Invalid.
284 };
285 
286 /// Information structure for a particular instruction.
287 struct InstructionInfo
288 {
289 	std::string name;	///< The name of the instruction.
290 	int additional;		///< Additional items required in memory for this instructions (only for PUSH).
291 	int args;			///< Number of items required on the stack for this instruction (and, for the purposes of ret, the number taken from the stack).
292 	int ret;			///< Number of items placed (back) on the stack by this instruction, assuming args items were removed.
293 	bool sideEffects;	///< false if the only effect on the execution environment (apart from gas usage) is a change to a topmost segment of the stack
294 	Tier gasPriceTier;	///< Tier for gas pricing.
295 };
296 
297 /// Information on all the instructions.
298 InstructionInfo instructionInfo(Instruction _inst);
299 
300 /// check whether instructions exists.
301 bool isValidInstruction(Instruction _inst);
302 
303 /// Convert from string mnemonic to Instruction type.
304 extern const std::map<std::string, Instruction> c_instructions;
305 
306 /// Iterate through EVM code and call a function on each instruction.
307 void eachInstruction(bytes const& _mem, std::function<void(Instruction, u256 const&)> const& _onInstruction);
308 
309 /// Convert from EVM code to simple EVM assembly language.
310 std::string disassemble(bytes const& _mem, std::string const& _delimiter = " ");
311 
312 }
313