diff --git a/evmc b/evmc index 6743fb9232c..95059813224 160000 --- a/evmc +++ b/evmc @@ -1 +1 @@ -Subproject commit 6743fb9232c5b803597e73d2480605057348dc35 +Subproject commit 95059813224e59caaf6425d310fc01eb276f3151 diff --git a/libevm/EVMC.cpp b/libevm/EVMC.cpp index 92159cff446..b64a98637be 100644 --- a/libevm/EVMC.cpp +++ b/libevm/EVMC.cpp @@ -21,6 +21,36 @@ EVM::EVM(evmc_instance* _instance) noexcept : m_instance(_instance) m_instance->set_option(m_instance, pair.first.c_str(), pair.second.c_str()); } +EVMC::EVMC(evmc_instance* _instance) : EVM(_instance) +{ + static constexpr auto tracer = [](evmc_tracer_context * context, int depth, int step, + size_t code_offset, evmc_status_code status_code, int64_t gas_left, size_t stack_num_items, + const evmc_uint256be* pushed_stack_item, size_t memory_size, + size_t changed_memory_offset, size_t changed_memory_size, + const uint8_t* changed_memory) noexcept { + + EVMC* evmc = reinterpret_cast(context); + + // TODO: It might be easier to just pass instruction from VM. + InstructionInfo instrInfo = instructionInfo(static_cast(evmc->m_code[code_offset])); + + std::cerr << "EVMC " << depth << " " << step << " " << code_offset << " " << instrInfo.name << " " << status_code + << " " << gas_left << " " << stack_num_items; + + if (pushed_stack_item) + std::cerr << " +[" << fromEvmC(*pushed_stack_item) << "]"; + + std::cerr << " " << memory_size << "\n"; + + (void)changed_memory_offset; + (void)changed_memory_size; + (void)changed_memory_size; + (void)changed_memory; + }; + + _instance->set_tracer(_instance, tracer, reinterpret_cast(this)); +} + owning_bytes_ref EVMC::exec(u256& io_gas, ExtVMFace& _ext, const OnOpFunc& _onOp) { assert(_ext.envInfo().number() >= 0); @@ -35,6 +65,8 @@ owning_bytes_ref EVMC::exec(u256& io_gas, ExtVMFace& _ext, const OnOpFunc& _onOp assert(_ext.envInfo().gasLimit() <= int64max); assert(_ext.depth <= static_cast(std::numeric_limits::max())); + m_code = bytesConstRef{&_ext.code}; + auto gas = static_cast(io_gas); EVM::Result r = execute(_ext, gas); diff --git a/libevm/EVMC.h b/libevm/EVMC.h index b21563352ad..94f69902834 100644 --- a/libevm/EVMC.h +++ b/libevm/EVMC.h @@ -91,9 +91,12 @@ class EVM class EVMC : public EVM, public VMFace { public: - explicit EVMC(evmc_instance* _instance) : EVM(_instance) {} + explicit EVMC(evmc_instance* _instance); owning_bytes_ref exec(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) final; + +private: + bytesConstRef m_code; }; } } diff --git a/libevm/VM.cpp b/libevm/VM.cpp index add5bb13fce..92d7cb63bbf 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -91,10 +91,36 @@ VM::VM() aleth_get_buildinfo()->project_version, ::destroy, ::execute, + setTracer, nullptr, } {} +void VM::setTracer( + evmc_instance* _instance, evmc_trace_callback _callback, evmc_tracer_context* _context) noexcept +{ + auto vm = static_cast(_instance); + vm->m_trace = _callback; + vm->m_traceContext = _context; +} + +void VM::trace() noexcept +{ + if (m_trace) + { + InstructionMetric const& metric = c_metrics[static_cast(m_OP)]; + evmc_uint256be topStackItem; + evmc_uint256be const* pushedStackItem = nullptr; + if (metric.ret == 1) + { + topStackItem = toEvmC(m_SPP[0]); + pushedStackItem = &topStackItem; + } + m_trace(m_traceContext, m_message->depth, m_step++, m_PC, EVMC_SUCCESS, m_io_gas, + m_stackEnd - m_SPP, pushedStackItem, m_mem.size(), 0, 0, nullptr); + } +} + uint64_t VM::memNeed(u256 _offset, u256 _size) { return toInt63(_size ? u512(_offset) + _size : u512(0)); @@ -387,6 +413,7 @@ void VM::interpretCases() updateIOGas(); m_SPP[0] = (u256)*(h256 const*)(m_mem.data() + (unsigned)m_SP[0]); + trace(); } NEXT @@ -397,6 +424,7 @@ void VM::interpretCases() updateIOGas(); *(h256*)&m_mem[(unsigned)m_SP[0]] = (h256)m_SP[1]; + trace(); } NEXT @@ -1530,11 +1558,14 @@ void VM::interpretCases() // get val at two-byte offset into const pool and advance pc by one-byte remainder TRACE_OP(2, m_PC, m_OP); unsigned off; - ++m_PC; - off = m_code[m_PC++] << 8; - off |= m_code[m_PC++]; - m_PC += m_code[m_PC]; + uint64_t pc = m_PC; + ++pc; + off = m_code[pc++] << 8; + off |= m_code[pc++]; + pc += m_code[pc]; m_SPP[0] = m_pool[off]; + trace(); + m_PC = pc; TRACE_VAL(2, "Retrieved pooled const", m_SPP[0]); #else throwBadInstruction(); @@ -1546,9 +1577,9 @@ void VM::interpretCases() { ON_OP(); updateIOGas(); - ++m_PC; - m_SPP[0] = m_code[m_PC]; - ++m_PC; + m_SPP[0] = m_code[m_PC + 1]; + trace(); + m_PC += 2; } CONTINUE @@ -1594,6 +1625,8 @@ void VM::interpretCases() // bytes to handle "out of code" push data here. for (++m_PC; numBytes--; ++m_PC) m_SPP[0] = (m_SPP[0] << 8) | m_code[m_PC]; + + trace(); } CONTINUE @@ -1722,6 +1755,7 @@ void VM::interpretCases() updateSSGas(); updateIOGas(); + trace(); evmc_uint256be key = toEvmC(m_SP[0]); evmc_uint256be value = toEvmC(m_SP[1]); diff --git a/libevm/VM.h b/libevm/VM.h index c55cea0b469..f7fd4b2c124 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -92,7 +92,6 @@ class VM : public evmc_instance void copyCode(int); typedef void (VM::*MemFnPtr)(); MemFnPtr m_bounce = nullptr; - uint64_t m_nSteps = 0; // return bytes owning_bytes_ref m_output; @@ -138,6 +137,15 @@ class VM : public evmc_instance uint64_t m_newMemSize = 0; uint64_t m_copyMemSize = 0; + // EVMC tracing. + int m_step = 0; + evmc_trace_callback m_trace = nullptr; + evmc_tracer_context* m_traceContext = nullptr; + static void setTracer(evmc_instance* _instance, evmc_trace_callback _callback, + evmc_tracer_context* _context) noexcept; + + void trace() noexcept; + // initialize interpreter void initEntry(); void optimize();