Skip to content

Commit b1030c4

Browse files
committed
Ethdebug uses schema for serialization
1 parent 0312a10 commit b1030c4

File tree

3 files changed

+87
-55
lines changed

3 files changed

+87
-55
lines changed

Diff for: libevmasm/Ethdebug.cpp

+80-51
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
#include <libevmasm/Ethdebug.h>
2020

21+
#include <libevmasm/EthdebugSchema.h>
22+
2123
#include <range/v3/algorithm/any_of.hpp>
2224

2325
using namespace solidity;
@@ -27,14 +29,66 @@ using namespace solidity::evmasm::ethdebug;
2729
namespace
2830
{
2931

30-
std::vector<Json> codeSectionInstructions(Assembly const& _assembly, LinkerObject const& _linkerObject, unsigned _sourceId, size_t const _codeSectionIndex)
32+
schema::program::Instruction::Operation instructionOperation(Assembly const& _assembly, LinkerObject const& _linkerObject, size_t const _start, size_t const _end)
33+
{
34+
solAssert(_end <= _linkerObject.bytecode.size());
35+
solAssert(_start < _end);
36+
schema::program::Instruction::Operation operation;
37+
operation.mnemonic = instructionInfo(static_cast<Instruction>(_linkerObject.bytecode[_start]), _assembly.evmVersion()).name;
38+
static size_t constexpr instructionSize = 1;
39+
if (_start + instructionSize < _end)
40+
{
41+
bytes const argumentData(
42+
_linkerObject.bytecode.begin() + static_cast<std::ptrdiff_t>(_start) + instructionSize,
43+
_linkerObject.bytecode.begin() + static_cast<std::ptrdiff_t>(_end)
44+
);
45+
solAssert(!argumentData.empty());
46+
operation.arguments = {{schema::data::HexValue{argumentData}}};
47+
}
48+
return operation;
49+
}
50+
51+
schema::materials::SourceRange::Range locationRange(langutil::SourceLocation const& _location)
52+
{
53+
return {
54+
.length = schema::data::Unsigned{_location.end - _location.start},
55+
.offset = schema::data::Unsigned{_location.start}
56+
};
57+
}
58+
59+
schema::materials::Reference sourceReference(unsigned _sourceID)
60+
{
61+
return {
62+
.id = schema::materials::ID{_sourceID},
63+
.type = std::nullopt
64+
};
65+
}
66+
67+
std::optional<schema::program::Context> instructionContext(Assembly::CodeSection const& _codeSection, size_t _assemblyItemIndex, unsigned _sourceID)
68+
{
69+
solAssert(_assemblyItemIndex < _codeSection.items.size());
70+
langutil::SourceLocation const& location = _codeSection.items.at(_assemblyItemIndex).location();
71+
if (!location.isValid())
72+
return std::nullopt;
73+
74+
return schema::program::Context{
75+
schema::materials::SourceRange{
76+
.source = sourceReference(_sourceID),
77+
.range = locationRange(location)
78+
},
79+
std::nullopt,
80+
std::nullopt
81+
};
82+
}
83+
84+
std::vector<schema::program::Instruction> codeSectionInstructions(Assembly const& _assembly, LinkerObject const& _linkerObject, unsigned const _sourceID, size_t const _codeSectionIndex)
3185
{
3286
solAssert(_codeSectionIndex < _linkerObject.codeSectionLocations.size());
3387
solAssert(_codeSectionIndex < _assembly.codeSections().size());
3488
auto const& locations = _linkerObject.codeSectionLocations[_codeSectionIndex];
3589
auto const& codeSection = _assembly.codeSections().at(_codeSectionIndex);
3690

37-
std::vector<Json> instructions;
91+
std::vector<schema::program::Instruction> instructions;
3892
instructions.reserve(codeSection.items.size());
3993

4094
bool const codeSectionContainsVerbatim = ranges::any_of(
@@ -52,72 +106,47 @@ std::vector<Json> codeSectionInstructions(Assembly const& _assembly, LinkerObjec
52106
if (start == end)
53107
continue;
54108

55-
size_t const assemblyItemIndex = currentInstruction.assemblyItemIndex;
56-
solAssert(end <= _linkerObject.bytecode.size());
57-
solAssert(start < end);
58-
solAssert(assemblyItemIndex < codeSection.items.size());
59-
Json operation = Json::object();
60-
operation["mnemonic"] = instructionInfo(static_cast<Instruction>(_linkerObject.bytecode[start]), _assembly.evmVersion()).name;
61-
static size_t constexpr instructionSize = 1;
62-
if (start + instructionSize < end)
63-
{
64-
bytes const argumentData(
65-
_linkerObject.bytecode.begin() + static_cast<std::ptrdiff_t>(start) + instructionSize,
66-
_linkerObject.bytecode.begin() + static_cast<std::ptrdiff_t>(end)
67-
);
68-
solAssert(!argumentData.empty());
69-
operation["arguments"] = Json::array({util::toHex(argumentData, util::HexPrefix::Add)});
70-
}
71-
langutil::SourceLocation const& location = codeSection.items.at(assemblyItemIndex).location();
72-
instructions.emplace_back(Json{
73-
{ "offset", start },
74-
{"operation", operation },
75-
{
76-
"context", {
77-
"code", {
78-
"source", {
79-
{ "id", static_cast<int>(_sourceId) },
80-
},
81-
"range", {
82-
{ "offset", location.start },
83-
{ "length", location.end - location.start }
84-
}
85-
}
86-
}
87-
}
109+
instructions.emplace_back(schema::program::Instruction{
110+
.offset = schema::data::Unsigned{start},
111+
.operation = instructionOperation(_assembly, _linkerObject, start, end),
112+
.context = instructionContext(codeSection, currentInstruction.assemblyItemIndex, _sourceID)
88113
});
89114
}
90115

91116
return instructions;
92117
}
93118

94-
Json programInstructions(Assembly const& _assembly, LinkerObject const& _linkerObject, unsigned _sourceId)
119+
std::vector<schema::program::Instruction> programInstructions(Assembly const& _assembly, LinkerObject const& _linkerObject, unsigned const _sourceID)
95120
{
96121
auto const numCodeSections = _assembly.codeSections().size();
97122
solAssert(numCodeSections == _linkerObject.codeSectionLocations.size());
98123

99-
std::vector<Json> instructionInfo;
124+
std::vector<schema::program::Instruction> instructionInfo;
100125
for (size_t codeSectionIndex = 0; codeSectionIndex < numCodeSections; ++codeSectionIndex)
101-
instructionInfo += codeSectionInstructions(_assembly, _linkerObject, _sourceId, codeSectionIndex);
126+
instructionInfo += codeSectionInstructions(_assembly, _linkerObject, _sourceID, codeSectionIndex);
102127
return instructionInfo;
103128
}
104129

105130
} // anonymous namespace
106131

107-
Json ethdebug::program(std::string_view _name, unsigned _sourceId, Assembly const& _assembly, LinkerObject const& _linkerObject)
132+
Json ethdebug::program(std::string_view _name, unsigned _sourceID, Assembly const& _assembly, LinkerObject const& _linkerObject)
108133
{
109-
Json result = Json::object();
110-
result["contract"] = Json::object();
111-
result["contract"]["name"] = _name;
112-
result["contract"]["definition"] = Json::object();
113-
result["contract"]["definition"]["source"] = Json::object();
114-
result["contract"]["definition"]["source"]["id"] = _sourceId;
115-
if (_assembly)
116-
{
117-
result["environment"] = _assembly->isCreation() ? "create" : "call";
118-
result["instructions"] = programInstructions(*_assembly, _linkerObject, _sourceId);
119-
}
120-
return result;
134+
return schema::Program{
135+
.compilation = std::nullopt,
136+
.contract = {
137+
.name = std::string{_name},
138+
.definition = {
139+
.source = {
140+
.id = {_sourceID},
141+
.type = std::nullopt
142+
},
143+
.range = std::nullopt
144+
}
145+
},
146+
.environment = _assembly.isCreation() ? schema::Program::Environment::CREATE : schema::Program::Environment::CALL,
147+
.context = std::nullopt,
148+
.instructions = programInstructions(_assembly, _linkerObject, _sourceID)
149+
};
121150
}
122151

123152
Json ethdebug::resources(std::vector<std::string> const& _sources, std::string const& _version)

Diff for: libevmasm/Ethdebug.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ namespace solidity::evmasm::ethdebug
2727
{
2828

2929
// returns ethdebug/format/program.
30-
Json program(std::string_view _name, unsigned _sourceId, Assembly const& _assembly, LinkerObject const& _linkerObject);
30+
Json program(std::string_view _name, unsigned _sourceID, Assembly const& _assembly, LinkerObject const& _linkerObject);
3131

3232
// returns ethdebug/format/info/resources
3333
Json resources(std::vector<std::string> const& _sources, std::string const& _version);

Diff for: test/libsolidity/StandardCompiler.cpp

+6-3
Original file line numberDiff line numberDiff line change
@@ -2249,9 +2249,12 @@ BOOST_DATA_TEST_CASE(ethdebug_output_instructions_smoketest, boost::unit_test::d
22492249
BOOST_REQUIRE(instruction.contains("offset"));
22502250
BOOST_REQUIRE(instruction.contains("operation"));
22512251
BOOST_REQUIRE(instruction["operation"].contains("mnemonic"));
2252-
BOOST_REQUIRE(instruction["context"]["code"]["range"].contains("length"));
2253-
BOOST_REQUIRE(instruction["context"]["code"]["range"].contains("offset"));
2254-
BOOST_REQUIRE(instruction["context"]["code"]["source"].contains("id"));
2252+
if (instruction.contains("context"))
2253+
{
2254+
BOOST_REQUIRE(instruction["context"]["code"]["range"].contains("length"));
2255+
BOOST_REQUIRE(instruction["context"]["code"]["range"].contains("offset"));
2256+
BOOST_REQUIRE(instruction["context"]["code"]["source"].contains("id"));
2257+
}
22552258
std::string mnemonic = instruction["operation"]["mnemonic"];
22562259
if (mnemonic.find("PUSH") != std::string::npos)
22572260
{

0 commit comments

Comments
 (0)