Skip to content

Commit eb9d13f

Browse files
committed
libevmasm: Add support to import evm assembly json.
1 parent 24bebf5 commit eb9d13f

12 files changed

+477
-67
lines changed

libevmasm/Assembly.cpp

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,117 @@ unsigned Assembly::codeSize(unsigned subTagSize) const
7474
}
7575
}
7676

77+
void Assembly::addAssemblyItemsFromJSON(Json::Value const& _code)
78+
{
79+
solAssert(_code.isArray(), "");
80+
for (auto const& jsonItem: _code)
81+
m_items.emplace_back(loadItemFromJSON(jsonItem));
82+
83+
for (auto current = m_items.begin(); current != m_items.end(); ++current)
84+
{
85+
// During the assembly json export a `JUMPDEST` is always generated after a `tag`.
86+
// So we just ignore exactly these `JUMPDEST`'s.
87+
auto const next = std::next(current);
88+
if (
89+
next != m_items.end() &&
90+
current->type() == AssemblyItemType::Tag &&
91+
next->type() == AssemblyItemType::Operation &&
92+
next->instruction() == Instruction::JUMPDEST
93+
)
94+
m_items.erase(next);
95+
}
96+
}
97+
98+
AssemblyItem Assembly::loadItemFromJSON(Json::Value const& _json)
99+
{
100+
std::string name = _json["name"].isString() ? _json["name"].asString() : "";
101+
int begin = _json["begin"].isInt() ? _json["begin"].asInt() : -1;
102+
int end = _json["end"].isInt() ? _json["end"].asInt() : -1;
103+
int srcIndex = _json["source"].isInt() ? _json["source"].asInt() : -1;
104+
size_t modifierDepth = _json["modifierDepth"].isInt() ? static_cast<size_t>(_json["modifierDepth"].asInt()) : 0;
105+
std::string value = _json["value"].isString() ? _json["value"].asString() : "";
106+
std::string jumpType = _json["jumpType"].isString() ? _json["jumpType"].asString() : "";
107+
solAssert(!name.empty(), "");
108+
109+
auto updateUsedTags = [&](u256 const& data) {
110+
auto tag = static_cast<unsigned>(data);
111+
if (m_usedTags <= tag)
112+
m_usedTags = tag + 1;
113+
return data;
114+
};
115+
116+
auto immutableHash = [&](string const& _immutableName) -> h256 {
117+
h256 hash(util::keccak256(value));
118+
m_immutables[hash] = _immutableName;
119+
return hash;
120+
};
121+
122+
auto libraryHash = [&](string const& _libraryName) -> h256 {
123+
h256 hash(util::keccak256(value));
124+
m_libraries[hash] = _libraryName;
125+
return hash;
126+
};
127+
128+
SourceLocation location;
129+
location.start = begin;
130+
location.end = end;
131+
if (srcIndex > -1 && srcIndex < static_cast<int>(sources().size()))
132+
location.sourceName = sources()[static_cast<size_t>(srcIndex)];
133+
134+
AssemblyItem result(0);
135+
136+
if (c_instructions.find(name) != c_instructions.end())
137+
{
138+
AssemblyItem item{c_instructions.at(name), location};
139+
item.m_modifierDepth = modifierDepth;
140+
if (!jumpType.empty())
141+
item.setJumpType(jumpType);
142+
result = item;
143+
}
144+
else
145+
{
146+
if (name == "PUSH")
147+
{
148+
AssemblyItem item{AssemblyItemType::Push, u256("0x" + value), location};
149+
if (!jumpType.empty())
150+
item.setJumpType(jumpType);
151+
result = item;
152+
}
153+
else if (name == "PUSH [ErrorTag]")
154+
result = {AssemblyItemType::PushTag, 0, location};
155+
else if (name == "PUSH [tag]")
156+
result = {AssemblyItemType::PushTag, updateUsedTags(u256(value)), location};
157+
else if (name == "PUSH [$]")
158+
result = {AssemblyItemType::PushSub, u256("0x" + value), location};
159+
else if (name == "PUSH #[$]")
160+
result = {AssemblyItemType::PushSubSize, u256("0x" + value), location};
161+
else if (name == "PUSHSIZE")
162+
result = {AssemblyItemType::PushProgramSize, 0, location};
163+
else if (name == "PUSHLIB")
164+
result = {AssemblyItemType::PushLibraryAddress, libraryHash(value), location};
165+
else if (name == "PUSHDEPLOYADDRESS")
166+
result = {AssemblyItemType::PushDeployTimeAddress, 0, location};
167+
else if (name == "PUSHIMMUTABLE")
168+
result = {AssemblyItemType::PushImmutable, immutableHash(value), location};
169+
else if (name == "ASSIGNIMMUTABLE")
170+
result = {AssemblyItemType::AssignImmutable, immutableHash(value), location};
171+
else if (name == "tag")
172+
result = {AssemblyItemType::Tag, updateUsedTags(u256(value)), location};
173+
else if (name == "PUSH data")
174+
result = {AssemblyItemType::PushData, u256("0x" + value), location};
175+
else if (name == "VERBATIM")
176+
{
177+
AssemblyItem item(fromHex(value), 0, 0);
178+
item.setLocation(location);
179+
result = item;
180+
}
181+
else
182+
assertThrow(false, InvalidOpcode, "");
183+
}
184+
result.m_modifierDepth = modifierDepth;
185+
return result;
186+
}
187+
77188
namespace
78189
{
79190

@@ -299,6 +410,43 @@ Json::Value Assembly::assemblyJSON(map<string, unsigned> const& _sourceIndices,
299410
return root;
300411
}
301412

413+
bool Assembly::loadFromAssemblyJSON(Json::Value const& _json, bool _loadSources /* = true */)
414+
{
415+
if (!_json[".code"].isArray())
416+
return false;
417+
bool success{true};
418+
419+
if (_loadSources)
420+
{
421+
vector<string> sourceList;
422+
if (_json.isMember("sourceList"))
423+
for (auto const& it: _json["sourceList"])
424+
sourceList.emplace_back(it.asString());
425+
setSources(sourceList);
426+
}
427+
428+
addAssemblyItemsFromJSON(_json[".code"]);
429+
if (_json[".auxdata"].isString())
430+
m_auxiliaryData = fromHex(_json[".auxdata"].asString());
431+
Json::Value const& data = _json[".data"];
432+
for (Json::ValueConstIterator itr = data.begin(); itr != data.end(); itr++)
433+
{
434+
solAssert(itr.key().isString(), "");
435+
std::string key = itr.key().asString();
436+
Json::Value const& code = data[key];
437+
if (code.isString())
438+
m_data[h256(fromHex(key))] = fromHex(code.asString());
439+
else
440+
{
441+
shared_ptr<Assembly> subassembly = make_shared<Assembly>(false, "");
442+
subassembly->setSources(sources());
443+
success &= subassembly->loadFromAssemblyJSON(code, false);
444+
m_subs.emplace_back(subassembly);
445+
}
446+
}
447+
return success;
448+
}
449+
302450
AssemblyItem Assembly::namedTag(string const& _name, size_t _params, size_t _returns, optional<uint64_t> _sourceID)
303451
{
304452
assertThrow(!_name.empty(), AssemblyException, "Empty named tag.");

libevmasm/Assembly.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,12 @@ class Assembly
152152
bool _includeSourceList = true
153153
) const;
154154

155+
/// Loads the JSON representation of assembly.
156+
/// @param _json JSON object containing assembly
157+
/// @param _loadSources true, if source list should be included, false otherwise.
158+
/// @returns true on success, false otherwise
159+
bool loadFromAssemblyJSON(Json::Value const& _json, bool _loadSources = true);
160+
155161
/// Mark this assembly as invalid. Calling ``assemble`` on it will throw.
156162
void markAsInvalid() { m_invalid = true; }
157163

@@ -160,6 +166,22 @@ class Assembly
160166

161167
bool isCreation() const { return m_creation; }
162168

169+
/// Set the source list.
170+
void setSources(std::vector<std::shared_ptr<std::string const>> _sources)
171+
{
172+
m_sources = std::move(_sources);
173+
}
174+
175+
/// Set the source list from simple vector<string>.
176+
void setSources(std::vector<std::string> const& _sources)
177+
{
178+
for (auto const& item: _sources)
179+
m_sources.emplace_back(std::make_shared<std::string>(item));
180+
}
181+
182+
/// @returns List of sources.
183+
std::vector<std::shared_ptr<std::string const>> sources() const& { return m_sources; }
184+
163185
protected:
164186
/// Does the same operations as @a optimise, but should only be applied to a sub and
165187
/// returns the replaced tags. Also takes an argument containing the tags of this assembly
@@ -168,6 +190,14 @@ class Assembly
168190

169191
unsigned codeSize(unsigned subTagSize) const;
170192

193+
/// Add all assembly items from given JSON array.
194+
void addAssemblyItemsFromJSON(Json::Value const& _code);
195+
196+
/// Creates an AssemblyItem from a given JSON representation.
197+
/// @param _json JSON representation of an assembly item
198+
/// @returns AssemblyItem from a given JSON representation.
199+
AssemblyItem loadItemFromJSON(Json::Value const& _json);
200+
171201
private:
172202
bool m_invalid = false;
173203

@@ -214,6 +244,7 @@ class Assembly
214244
std::string m_name;
215245

216246
langutil::SourceLocation m_currentSourceLocation;
247+
std::vector<std::shared_ptr<std::string const>> m_sources;
217248

218249
public:
219250
size_t m_currentModifierDepth = 0;

libevmasm/AssemblyItem.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,18 @@ string AssemblyItem::getJumpTypeAsString() const
243243
}
244244
}
245245

246+
void AssemblyItem::setJumpType(std::string const& _jumpType)
247+
{
248+
if (_jumpType == "[in]")
249+
m_jumpType = JumpType::IntoFunction;
250+
else if (_jumpType == "[out]")
251+
m_jumpType = JumpType::OutOfFunction;
252+
else if (_jumpType.empty())
253+
m_jumpType = JumpType::Ordinary;
254+
else
255+
assertThrow(false, AssemblyException, "Invalid jump type.");
256+
}
257+
246258
string AssemblyItem::toAssemblyText(Assembly const& _assembly) const
247259
{
248260
string text;

libevmasm/AssemblyItem.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ class AssemblyItem
173173
langutil::SourceLocation const& location() const { return m_location; }
174174

175175
void setJumpType(JumpType _jumpType) { m_jumpType = _jumpType; }
176+
void setJumpType(std::string const& _jumpType);
176177
JumpType getJumpType() const { return m_jumpType; }
177178
std::string getJumpTypeAsString() const;
178179

0 commit comments

Comments
 (0)