Coverage Report

Created: 2022-08-24 06:32

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