Skip to content
This repository was archived by the owner on Oct 28, 2021. It is now read-only.

Commit f324cc2

Browse files
chfastgumb0
authored andcommitted
EVMC tracing for interpreter
1 parent 7e4250b commit f324cc2

File tree

4 files changed

+95
-17
lines changed

4 files changed

+95
-17
lines changed

libaleth-interpreter/VM.cpp

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222

2323
namespace
2424
{
25+
evmc_trace_callback g_traceCallback = nullptr;
26+
evmc_tracer_context* g_traceContext = nullptr;
27+
2528
void destroy(evmc_instance* _instance)
2629
{
2730
(void)_instance;
@@ -33,7 +36,7 @@ void delete_output(const evmc_result* result)
3336
}
3437

3538
evmc_result execute(evmc_instance* _instance, evmc_context* _context, evmc_revision _rev,
36-
const evmc_message* _msg, uint8_t const* _code, size_t _codeSize) noexcept
39+
evmc_message const* _msg, uint8_t const* _code, size_t _codeSize) noexcept
3740
{
3841
(void)_instance;
3942
std::unique_ptr<dev::eth::VM> vm{new dev::eth::VM};
@@ -82,28 +85,47 @@ evmc_result execute(evmc_instance* _instance, evmc_context* _context, evmc_revis
8285

8386
return result;
8487
}
88+
89+
void setTracer(evmc_instance* /*_instance*/, evmc_trace_callback _callback,
90+
evmc_tracer_context* _context) noexcept
91+
{
92+
g_traceCallback = _callback;
93+
g_traceContext = _context;
94+
}
8595
} // namespace
8696

8797
extern "C" evmc_instance* evmc_create_interpreter() noexcept
8898
{
8999
// TODO: Allow creating multiple instances with different configurations.
90100
static evmc_instance s_instance{
91-
EVMC_ABI_VERSION,
92-
"interpreter",
93-
aleth_get_buildinfo()->project_version,
94-
::destroy,
95-
::execute,
96-
nullptr, // set_tracer
101+
EVMC_ABI_VERSION, "interpreter", aleth_get_buildinfo()->project_version, ::destroy,
102+
::execute, ::setTracer,
97103
nullptr, // set_option
98104
};
99105
return &s_instance;
100106
}
101107

102-
103108
namespace dev
104109
{
105110
namespace eth
106111
{
112+
void VM::trace() noexcept
113+
{
114+
if (g_traceCallback)
115+
{
116+
auto const& metrics = c_metrics[static_cast<size_t>(m_OP)];
117+
evmc_uint256be topStackItem;
118+
evmc_uint256be const* pushedStackItem = nullptr;
119+
if (metrics.num_stack_returned_items == 1)
120+
{
121+
topStackItem = toEvmC(m_SPP[0]);
122+
pushedStackItem = &topStackItem;
123+
}
124+
g_traceCallback(g_traceContext, m_PC, EVMC_SUCCESS, m_io_gas, m_stackEnd - m_SPP,
125+
pushedStackItem, m_mem.size(), 0, 0, nullptr);
126+
}
127+
}
128+
107129
uint64_t VM::memNeed(u256 _offset, u256 _size)
108130
{
109131
return toInt63(_size ? u512(_offset) + _size : u512(0));
@@ -397,6 +419,7 @@ void VM::interpretCases()
397419
updateIOGas();
398420

399421
m_SPP[0] = (u256)*(h256 const*)(m_mem.data() + (unsigned)m_SP[0]);
422+
trace();
400423
}
401424
NEXT
402425

@@ -407,6 +430,7 @@ void VM::interpretCases()
407430
updateIOGas();
408431

409432
*(h256*)&m_mem[(unsigned)m_SP[0]] = (h256)m_SP[1];
433+
trace();
410434
}
411435
NEXT
412436

@@ -1155,11 +1179,14 @@ void VM::interpretCases()
11551179
// get val at two-byte offset into const pool and advance pc by one-byte remainder
11561180
TRACE_OP(2, m_PC, m_OP);
11571181
unsigned off;
1158-
++m_PC;
1159-
off = m_code[m_PC++] << 8;
1160-
off |= m_code[m_PC++];
1161-
m_PC += m_code[m_PC];
1182+
uint64_t pc = m_PC;
1183+
++pc;
1184+
off = m_code[pc++] << 8;
1185+
off |= m_code[pc++];
1186+
pc += m_code[pc];
11621187
m_SPP[0] = m_pool[off];
1188+
trace();
1189+
m_PC = pc;
11631190
TRACE_VAL(2, "Retrieved pooled const", m_SPP[0]);
11641191
#else
11651192
throwBadInstruction();
@@ -1171,9 +1198,9 @@ void VM::interpretCases()
11711198
{
11721199
ON_OP();
11731200
updateIOGas();
1174-
++m_PC;
1175-
m_SPP[0] = m_code[m_PC];
1176-
++m_PC;
1201+
m_SPP[0] = m_code[m_PC + 1];
1202+
trace();
1203+
m_PC += 2;
11771204
}
11781205
CONTINUE
11791206

@@ -1219,6 +1246,8 @@ void VM::interpretCases()
12191246
// bytes to handle "out of code" push data here.
12201247
for (++m_PC; numBytes--; ++m_PC)
12211248
m_SPP[0] = (m_SPP[0] << 8) | m_code[m_PC];
1249+
1250+
trace();
12221251
}
12231252
CONTINUE
12241253

@@ -1347,6 +1376,7 @@ void VM::interpretCases()
13471376

13481377
updateSSGas();
13491378
updateIOGas();
1379+
trace();
13501380

13511381
evmc_uint256be key = toEvmC(m_SP[0]);
13521382
evmc_uint256be value = toEvmC(m_SP[1]);

libaleth-interpreter/VM.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@ class VM
8080
void copyCode(int);
8181
typedef void (VM::*MemFnPtr)();
8282
MemFnPtr m_bounce = nullptr;
83-
uint64_t m_nSteps = 0;
8483

8584
// return bytes
8685
owning_bytes_ref m_output;
@@ -115,6 +114,8 @@ class VM
115114
uint64_t m_newMemSize = 0;
116115
uint64_t m_copyMemSize = 0;
117116

117+
void trace() noexcept;
118+
118119
// initialize interpreter
119120
void initEntry();
120121
void optimize();

libevm/EVMC.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include "EVMC.h"
55

6+
#include <evmc/instructions.h>
67
#include <libdevcore/Log.h>
78
#include <libevm/VMFactory.h>
89

@@ -21,6 +22,36 @@ EVM::EVM(evmc_instance* _instance) noexcept : m_instance(_instance)
2122
m_instance->set_option(m_instance, pair.first.c_str(), pair.second.c_str());
2223
}
2324

25+
EVMC::EVMC(evmc_instance* _instance) : EVM(_instance)
26+
{
27+
static const auto tracer = [](evmc_tracer_context * context, size_t code_offset,
28+
evmc_status_code status_code, int64_t gas_left, size_t stack_num_items,
29+
const evmc_uint256be* pushed_stack_item, size_t memory_size, size_t changed_memory_offset,
30+
size_t changed_memory_size, const uint8_t* changed_memory) noexcept
31+
{
32+
EVMC* evmc = reinterpret_cast<EVMC*>(context);
33+
34+
// TODO: It might be easier to just pass instruction from VM.
35+
char const* name = evmc->m_instructionNames[evmc->m_code[code_offset]];
36+
37+
std::cerr << "EVMC "
38+
<< " " << evmc->m_step++ << " " << code_offset << " " << name << " "
39+
<< status_code << " " << gas_left << " " << stack_num_items;
40+
41+
if (pushed_stack_item)
42+
std::cerr << " +[" << fromEvmC(*pushed_stack_item) << "]";
43+
44+
std::cerr << " " << memory_size << "\n";
45+
46+
(void)changed_memory_offset;
47+
(void)changed_memory_size;
48+
(void)changed_memory_size;
49+
(void)changed_memory;
50+
};
51+
52+
_instance->set_tracer(_instance, tracer, reinterpret_cast<evmc_tracer_context*>(this));
53+
}
54+
2455
owning_bytes_ref EVMC::exec(u256& io_gas, ExtVMFace& _ext, const OnOpFunc& _onOp)
2556
{
2657
assert(_ext.envInfo().number() >= 0);
@@ -35,8 +66,19 @@ owning_bytes_ref EVMC::exec(u256& io_gas, ExtVMFace& _ext, const OnOpFunc& _onOp
3566
assert(_ext.envInfo().gasLimit() <= int64max);
3667
assert(_ext.depth <= static_cast<size_t>(std::numeric_limits<int32_t>::max()));
3768

69+
m_code = bytesConstRef{&_ext.code};
70+
m_step = 0;
71+
72+
// FIXME: EVMC revision found twice.
73+
m_instructionNames = evmc_get_instruction_names_table(toRevision(_ext.evmSchedule()));
74+
75+
3876
auto gas = static_cast<int64_t>(io_gas);
77+
std::cerr << "EVMC message START " << _ext.depth << " " << _ext.caller << " -> "
78+
<< _ext.myAddress << " gas: " << gas << "\n";
3979
EVM::Result r = execute(_ext, gas);
80+
std::cerr << "EVMC message END " << _ext.depth << " status: " << r.status()
81+
<< " gas left: " << r.gasLeft() << "\n";
4082

4183
switch (r.status())
4284
{

libevm/EVMC.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,14 @@ class EVM
9191
class EVMC : public EVM, public VMFace
9292
{
9393
public:
94-
explicit EVMC(evmc_instance* _instance) : EVM(_instance) {}
94+
explicit EVMC(evmc_instance* _instance);
9595

9696
owning_bytes_ref exec(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) final;
97+
98+
private:
99+
bytesConstRef m_code;
100+
int m_step = 0;
101+
char const* const* m_instructionNames = nullptr;
97102
};
98103
}
99104
}

0 commit comments

Comments
 (0)