Skip to content

Commit db6cb3f

Browse files
committed
Ethdebug instructions output over multiple code sections
1 parent f211e8e commit db6cb3f

File tree

2 files changed

+57
-29
lines changed

2 files changed

+57
-29
lines changed

Diff for: Changelog.md

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Language Features:
44

55

66
Compiler Features:
7+
* Ethdebug: Experimental support for instructions and source locations under EOF.
78
* NatSpec: Capture Natspec documentation of `enum` values in the AST.
89

910

Diff for: libevmasm/Ethdebug.cpp

+56-29
Original file line numberDiff line numberDiff line change
@@ -18,32 +18,44 @@
1818

1919
#include <libevmasm/Ethdebug.h>
2020

21+
#include <range/v3/algorithm/any_of.hpp>
22+
2123
using namespace solidity;
2224
using namespace solidity::evmasm;
2325
using namespace solidity::evmasm::ethdebug;
2426

2527
namespace
2628
{
2729

28-
Json programInstructions(Assembly const& _assembly, LinkerObject const& _linkerObject, unsigned _sourceId)
30+
std::vector<Json> codeSectionInstructions(Assembly const& _assembly, LinkerObject const& _linkerObject, unsigned _sourceId, size_t const _codeSectionIndex)
2931
{
30-
solUnimplementedAssert(_assembly.eofVersion() == std::nullopt, "ethdebug does not yet support EOF.");
31-
solUnimplementedAssert(_assembly.codeSections().size() == 1, "ethdebug does not yet support multiple code-sections.");
32-
for (auto const& instruction: _assembly.codeSections()[0].items)
33-
solUnimplementedAssert(instruction.type() != VerbatimBytecode, "Verbatim bytecode is currently not supported by ethdebug.");
34-
35-
solAssert(_linkerObject.codeSectionLocations.size() == 1);
36-
solAssert(_linkerObject.codeSectionLocations[0].end <= _linkerObject.bytecode.size());
37-
Json instructions = Json::array();
38-
for (size_t i = 0; i < _linkerObject.codeSectionLocations[0].instructionLocations.size(); ++i)
32+
solAssert(_codeSectionIndex < _linkerObject.codeSectionLocations.size());
33+
solAssert(_codeSectionIndex < _assembly.codeSections().size());
34+
auto const& locations = _linkerObject.codeSectionLocations[_codeSectionIndex];
35+
auto const& codeSection = _assembly.codeSections().at(_codeSectionIndex);
36+
37+
std::vector<Json> instructions;
38+
instructions.reserve(codeSection.items.size());
39+
40+
bool const codeSectionContainsVerbatim = ranges::any_of(
41+
codeSection.items,
42+
[](auto const& _instruction) { return _instruction.type() == VerbatimBytecode; }
43+
);
44+
solUnimplementedAssert(!codeSectionContainsVerbatim, "Verbatim bytecode is currently not supported by ethdebug.");
45+
46+
for (auto const& currentInstruction: locations.instructionLocations)
3947
{
40-
LinkerObject::InstructionLocation currentInstruction = _linkerObject.codeSectionLocations[0].instructionLocations[i];
41-
size_t start = currentInstruction.start;
42-
size_t end = currentInstruction.end;
43-
size_t assemblyItemIndex = currentInstruction.assemblyItemIndex;
48+
size_t const start = currentInstruction.start;
49+
size_t const end = currentInstruction.end;
50+
51+
// some instructions do not contribute to the bytecode
52+
if (start == end)
53+
continue;
54+
55+
size_t const assemblyItemIndex = currentInstruction.assemblyItemIndex;
4456
solAssert(end <= _linkerObject.bytecode.size());
4557
solAssert(start < end);
46-
solAssert(assemblyItemIndex < _assembly.codeSections().at(0).items.size());
58+
solAssert(assemblyItemIndex < codeSection.items.size());
4759
Json operation = Json::object();
4860
operation["mnemonic"] = instructionInfo(static_cast<Instruction>(_linkerObject.bytecode[start]), _assembly.evmVersion()).name;
4961
static size_t constexpr instructionSize = 1;
@@ -56,25 +68,40 @@ Json programInstructions(Assembly const& _assembly, LinkerObject const& _linkerO
5668
solAssert(!argumentData.empty());
5769
operation["arguments"] = Json::array({util::toHex(argumentData, util::HexPrefix::Add)});
5870
}
59-
langutil::SourceLocation const& location = _assembly.codeSections().at(0).items.at(assemblyItemIndex).location();
60-
Json instruction = Json::object();
61-
instruction["offset"] = start;
62-
instruction["operation"] = operation;
63-
64-
instruction["context"] = Json::object();
65-
instruction["context"]["code"] = Json::object();
66-
instruction["context"]["code"]["source"] = Json::object();
67-
instruction["context"]["code"]["source"]["id"] = static_cast<int>(_sourceId);
68-
69-
instruction["context"]["code"]["range"] = Json::object();
70-
instruction["context"]["code"]["range"]["offset"] = location.start;
71-
instruction["context"]["code"]["range"]["length"] = location.end - location.start;
72-
instructions.emplace_back(instruction);
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+
}
88+
});
7389
}
7490

7591
return instructions;
7692
}
7793

94+
Json programInstructions(Assembly const& _assembly, LinkerObject const& _linkerObject, unsigned _sourceId)
95+
{
96+
auto const numCodeSections = _assembly.codeSections().size();
97+
solAssert(numCodeSections == _linkerObject.codeSectionLocations.size());
98+
99+
std::vector<Json> instructionInfo;
100+
for (size_t codeSectionIndex = 0; codeSectionIndex < numCodeSections; ++codeSectionIndex)
101+
instructionInfo += codeSectionInstructions(_assembly, _linkerObject, _sourceId, codeSectionIndex);
102+
return instructionInfo;
103+
}
104+
78105
} // anonymous namespace
79106

80107
Json ethdebug::program(std::string_view _name, unsigned _sourceId, Assembly const& _assembly, LinkerObject const& _linkerObject)

0 commit comments

Comments
 (0)