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

Commit

Permalink
EVMC tracing for interpreter
Browse files Browse the repository at this point in the history
  • Loading branch information
chfast authored and gumb0 committed Aug 1, 2018
1 parent 7e4250b commit f324cc2
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 17 deletions.
60 changes: 45 additions & 15 deletions libaleth-interpreter/VM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@

namespace
{
evmc_trace_callback g_traceCallback = nullptr;
evmc_tracer_context* g_traceContext = nullptr;

void destroy(evmc_instance* _instance)
{
(void)_instance;
Expand All @@ -33,7 +36,7 @@ void delete_output(const evmc_result* result)
}

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

return result;
}

void setTracer(evmc_instance* /*_instance*/, evmc_trace_callback _callback,
evmc_tracer_context* _context) noexcept
{
g_traceCallback = _callback;
g_traceContext = _context;
}
} // namespace

extern "C" evmc_instance* evmc_create_interpreter() noexcept
{
// TODO: Allow creating multiple instances with different configurations.
static evmc_instance s_instance{
EVMC_ABI_VERSION,
"interpreter",
aleth_get_buildinfo()->project_version,
::destroy,
::execute,
nullptr, // set_tracer
EVMC_ABI_VERSION, "interpreter", aleth_get_buildinfo()->project_version, ::destroy,
::execute, ::setTracer,
nullptr, // set_option
};
return &s_instance;
}


namespace dev
{
namespace eth
{
void VM::trace() noexcept
{
if (g_traceCallback)
{
auto const& metrics = c_metrics[static_cast<size_t>(m_OP)];
evmc_uint256be topStackItem;
evmc_uint256be const* pushedStackItem = nullptr;
if (metrics.num_stack_returned_items == 1)
{
topStackItem = toEvmC(m_SPP[0]);
pushedStackItem = &topStackItem;
}
g_traceCallback(g_traceContext, 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));
Expand Down Expand Up @@ -397,6 +419,7 @@ void VM::interpretCases()
updateIOGas();

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

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

*(h256*)&m_mem[(unsigned)m_SP[0]] = (h256)m_SP[1];
trace();
}
NEXT

Expand Down Expand Up @@ -1155,11 +1179,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();
Expand All @@ -1171,9 +1198,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

Expand Down Expand Up @@ -1219,6 +1246,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

Expand Down Expand Up @@ -1347,6 +1376,7 @@ void VM::interpretCases()

updateSSGas();
updateIOGas();
trace();

evmc_uint256be key = toEvmC(m_SP[0]);
evmc_uint256be value = toEvmC(m_SP[1]);
Expand Down
3 changes: 2 additions & 1 deletion libaleth-interpreter/VM.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ class VM
void copyCode(int);
typedef void (VM::*MemFnPtr)();
MemFnPtr m_bounce = nullptr;
uint64_t m_nSteps = 0;

// return bytes
owning_bytes_ref m_output;
Expand Down Expand Up @@ -115,6 +114,8 @@ class VM
uint64_t m_newMemSize = 0;
uint64_t m_copyMemSize = 0;

void trace() noexcept;

// initialize interpreter
void initEntry();
void optimize();
Expand Down
42 changes: 42 additions & 0 deletions libevm/EVMC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "EVMC.h"

#include <evmc/instructions.h>
#include <libdevcore/Log.h>
#include <libevm/VMFactory.h>

Expand All @@ -21,6 +22,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 const auto tracer = [](evmc_tracer_context * context, 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<EVMC*>(context);

// TODO: It might be easier to just pass instruction from VM.
char const* name = evmc->m_instructionNames[evmc->m_code[code_offset]];

std::cerr << "EVMC "
<< " " << evmc->m_step++ << " " << code_offset << " " << 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<evmc_tracer_context*>(this));
}

owning_bytes_ref EVMC::exec(u256& io_gas, ExtVMFace& _ext, const OnOpFunc& _onOp)
{
assert(_ext.envInfo().number() >= 0);
Expand All @@ -35,8 +66,19 @@ owning_bytes_ref EVMC::exec(u256& io_gas, ExtVMFace& _ext, const OnOpFunc& _onOp
assert(_ext.envInfo().gasLimit() <= int64max);
assert(_ext.depth <= static_cast<size_t>(std::numeric_limits<int32_t>::max()));

m_code = bytesConstRef{&_ext.code};
m_step = 0;

// FIXME: EVMC revision found twice.
m_instructionNames = evmc_get_instruction_names_table(toRevision(_ext.evmSchedule()));


auto gas = static_cast<int64_t>(io_gas);
std::cerr << "EVMC message START " << _ext.depth << " " << _ext.caller << " -> "
<< _ext.myAddress << " gas: " << gas << "\n";
EVM::Result r = execute(_ext, gas);
std::cerr << "EVMC message END " << _ext.depth << " status: " << r.status()
<< " gas left: " << r.gasLeft() << "\n";

switch (r.status())
{
Expand Down
7 changes: 6 additions & 1 deletion libevm/EVMC.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,14 @@ 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;
int m_step = 0;
char const* const* m_instructionNames = nullptr;
};
}
}

0 comments on commit f324cc2

Please sign in to comment.