Skip to content

Commit f89d6b8

Browse files
committed
Add support for --import-asm-json.
1 parent 7df33f0 commit f89d6b8

11 files changed

+557
-129
lines changed

Changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Compiler Features:
77
* Immutable variables can be read at construction time once they are initialized.
88
* SMTChecker: Support low level ``call`` as external calls to unknown code.
99
* SMTChecker: Add constraints to better correlate ``address(this).balance`` and ``msg.value``.
10+
* Commandline Interface: Adds alternative input mode ``--import-asm-json`` to import assembly json.
1011

1112

1213
Bugfixes:

libevmasm/Assembly.cpp

Lines changed: 265 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
#include <libevmasm/ConstantOptimiser.h>
3232
#include <libevmasm/GasMeter.h>
3333

34+
#include <libsolutil/JSON.h>
35+
3436
#include <liblangutil/Exceptions.h>
3537

3638
#include <json/json.h>
@@ -227,6 +229,219 @@ string Assembly::toStringInHex(u256 _value)
227229
return hexStr.str();
228230
}
229231

232+
AssemblyItem Assembly::assemblyItemFromJSON(Json::Value const& _json, Assembly& _assembly)
233+
{
234+
std::string name = _json["name"].isString() ? _json["name"].asString() : "";
235+
int begin = _json["begin"].isInt() ? _json["begin"].asInt() : -1;
236+
int end = _json["end"].isInt() ? _json["end"].asInt() : -1;
237+
std::string value = _json["value"].isString() ? _json["value"].asString() : "";
238+
std::string jumpType = _json["jumpType"].isString() ? _json["jumpType"].asString() : "";
239+
solAssert(!name.empty(), "");
240+
241+
auto updateUsedTags = [&](u256 const& data) {
242+
auto tag = static_cast<unsigned>(data);
243+
if (_assembly.m_usedTags <= tag)
244+
_assembly.m_usedTags = tag + 1;
245+
};
246+
247+
auto updateImmutables = [&](u256 const& data) -> h256 {
248+
std::string value = toStringInHex(data);
249+
h256 hash(util::keccak256(value));
250+
_assembly.m_immutables[hash] = value;
251+
return hash;
252+
};
253+
254+
auto updateLibraries = [&](string const& value) -> h256 {
255+
h256 hash(util::keccak256(value));
256+
_assembly.m_libraries[hash] = value;
257+
return hash;
258+
};
259+
260+
SourceLocation location;
261+
location.start = begin;
262+
location.end = end;
263+
if (c_instructions.find(name) != c_instructions.end())
264+
{
265+
AssemblyItem item{c_instructions.at(name), location};
266+
if (!value.empty())
267+
item.setJumpTypeFromString(value);
268+
return item;
269+
}
270+
else
271+
{
272+
u256 data;
273+
if (name == "PUSH")
274+
{
275+
if (!value.empty())
276+
data = u256("0x" + value);
277+
AssemblyItem item{AssemblyItemType::Push, data, location};
278+
if (!jumpType.empty())
279+
item.setJumpTypeFromString(jumpType);
280+
return item;
281+
}
282+
else if (name == "PUSH tag")
283+
{
284+
if (!value.empty())
285+
data = u256("0x" + value);
286+
updateUsedTags(data);
287+
return {AssemblyItemType::PushString, data, location};
288+
}
289+
else if (name == "PUSH [ErrorTag]")
290+
return {AssemblyItemType::PushTag, data, location};
291+
else if (name == "PUSH [tag]")
292+
{
293+
if (!value.empty())
294+
data = u256(value);
295+
updateUsedTags(data);
296+
return {AssemblyItemType::PushTag, data, location};
297+
}
298+
else if (name == "PUSH [$]")
299+
{
300+
if (!value.empty())
301+
data = u256("0x" + value);
302+
return {AssemblyItemType::PushSub, data, location};
303+
}
304+
else if (name == "PUSH #[$]")
305+
{
306+
if (!value.empty())
307+
data = u256("0x" + value);
308+
return {AssemblyItemType::PushSubSize, data, location};
309+
}
310+
else if (name == "PUSHSIZE")
311+
return {AssemblyItemType::PushProgramSize, data, location};
312+
else if (name == "PUSHLIB")
313+
{
314+
h256 hash = updateLibraries(value);
315+
return {AssemblyItemType::PushLibraryAddress, hash, location};
316+
}
317+
else if (name == "PUSHDEPLOYADDRESS")
318+
return {AssemblyItemType::PushDeployTimeAddress, data, location};
319+
else if (name == "PUSHIMMUTABLE")
320+
{
321+
if (!value.empty())
322+
data = u256("0x" + value);
323+
h256 hash = updateImmutables(data);
324+
return {AssemblyItemType::PushImmutable, hash, location};
325+
}
326+
else if (name == "ASSIGNIMMUTABLE")
327+
{
328+
if (!value.empty())
329+
data = u256("0x" + value);
330+
h256 hash = updateImmutables(data);
331+
return {AssemblyItemType::AssignImmutable, hash, location};
332+
}
333+
else if (name == "tag")
334+
{
335+
if (!value.empty())
336+
data = u256(value);
337+
return {AssemblyItemType::Tag, data, location};
338+
}
339+
else if (name == "PUSH data")
340+
{
341+
if (!value.empty())
342+
data = u256("0x" + value);
343+
return {AssemblyItemType::PushData, data, location};
344+
}
345+
else if (name == "VERBATIM")
346+
{
347+
if (!value.empty())
348+
data = u256("0x" + value);
349+
return {AssemblyItemType::VerbatimBytecode, data, location};
350+
}
351+
else
352+
assertThrow(false, InvalidOpcode, "");
353+
}
354+
}
355+
356+
vector<Json::Value> Assembly::assemblyItemAsJSON(AssemblyItem const& _item, int _sourceIndex) const
357+
{
358+
vector<Json::Value> result;
359+
360+
switch (_item.type())
361+
{
362+
case Operation:
363+
result.emplace_back(createJsonValue(
364+
instructionInfo(_item.instruction()).name,
365+
_sourceIndex,
366+
_item.location().start,
367+
_item.location().end,
368+
_item.getJumpTypeAsString()));
369+
break;
370+
case Push:
371+
result.emplace_back(createJsonValue(
372+
"PUSH",
373+
_sourceIndex,
374+
_item.location().start,
375+
_item.location().end,
376+
toStringInHex(_item.data()),
377+
_item.getJumpTypeAsString()));
378+
break;
379+
case PushString:
380+
result.emplace_back(createJsonValue(
381+
"PUSH tag", _sourceIndex, _item.location().start, _item.location().end, m_strings.at(h256(_item.data()))));
382+
break;
383+
case PushTag:
384+
if (_item.data() == 0)
385+
result.emplace_back(
386+
createJsonValue("PUSH [ErrorTag]", _sourceIndex, _item.location().start, _item.location().end, ""));
387+
else
388+
result.emplace_back(createJsonValue(
389+
"PUSH [tag]", _sourceIndex, _item.location().start, _item.location().end, toString(_item.data())));
390+
break;
391+
case PushSub:
392+
result.emplace_back(createJsonValue(
393+
"PUSH [$]", _sourceIndex, _item.location().start, _item.location().end, toString(h256(_item.data()))));
394+
break;
395+
case PushSubSize:
396+
result.emplace_back(createJsonValue(
397+
"PUSH #[$]", _sourceIndex, _item.location().start, _item.location().end, toString(h256(_item.data()))));
398+
break;
399+
case PushProgramSize:
400+
result.emplace_back(createJsonValue("PUSHSIZE", _sourceIndex, _item.location().start, _item.location().end));
401+
break;
402+
case PushLibraryAddress:
403+
result.emplace_back(createJsonValue(
404+
"PUSHLIB", _sourceIndex, _item.location().start, _item.location().end, m_libraries.at(h256(_item.data()))));
405+
break;
406+
case PushDeployTimeAddress:
407+
result.emplace_back(
408+
createJsonValue("PUSHDEPLOYADDRESS", _sourceIndex, _item.location().start, _item.location().end));
409+
break;
410+
case PushImmutable:
411+
result.emplace_back(createJsonValue(
412+
"PUSHIMMUTABLE",
413+
_sourceIndex,
414+
_item.location().start,
415+
_item.location().end,
416+
m_immutables.at(h256(_item.data()))));
417+
break;
418+
case AssignImmutable:
419+
result.emplace_back(createJsonValue(
420+
"ASSIGNIMMUTABLE",
421+
_sourceIndex,
422+
_item.location().start,
423+
_item.location().end,
424+
m_immutables.at(h256(_item.data()))));
425+
break;
426+
case Tag:
427+
result.emplace_back(
428+
createJsonValue("tag", _sourceIndex, _item.location().start, _item.location().end, toString(_item.data())));
429+
result.emplace_back(createJsonValue("JUMPDEST", _sourceIndex, _item.location().start, _item.location().end));
430+
break;
431+
case PushData:
432+
result.emplace_back(createJsonValue(
433+
"PUSH data", _sourceIndex, _item.location().start, _item.location().end, toStringInHex(_item.data())));
434+
break;
435+
case VerbatimBytecode:
436+
result.emplace_back(createJsonValue(
437+
"VERBATIM", _sourceIndex, _item.location().start, _item.location().end, toHex(_item.verbatimData())));
438+
break;
439+
default:
440+
assertThrow(false, InvalidOpcode, "");
441+
}
442+
return result;
443+
}
444+
230445
Json::Value Assembly::assemblyJSON(map<string, unsigned> const& _sourceIndices) const
231446
{
232447
Json::Value root;
@@ -242,89 +457,8 @@ Json::Value Assembly::assemblyJSON(map<string, unsigned> const& _sourceIndices)
242457
sourceIndex = static_cast<int>(iter->second);
243458
}
244459

245-
switch (i.type())
246-
{
247-
case Operation:
248-
collection.append(
249-
createJsonValue(
250-
instructionInfo(i.instruction()).name,
251-
sourceIndex,
252-
i.location().start,
253-
i.location().end,
254-
i.getJumpTypeAsString())
255-
);
256-
break;
257-
case Push:
258-
collection.append(
259-
createJsonValue("PUSH", sourceIndex, i.location().start, i.location().end, toStringInHex(i.data()), i.getJumpTypeAsString()));
260-
break;
261-
case PushString:
262-
collection.append(
263-
createJsonValue("PUSH tag", sourceIndex, i.location().start, i.location().end, m_strings.at(h256(i.data()))));
264-
break;
265-
case PushTag:
266-
if (i.data() == 0)
267-
collection.append(
268-
createJsonValue("PUSH [ErrorTag]", sourceIndex, i.location().start, i.location().end, ""));
269-
else
270-
collection.append(
271-
createJsonValue("PUSH [tag]", sourceIndex, i.location().start, i.location().end, toString(i.data())));
272-
break;
273-
case PushSub:
274-
collection.append(
275-
createJsonValue("PUSH [$]", sourceIndex, i.location().start, i.location().end, toString(h256(i.data()))));
276-
break;
277-
case PushSubSize:
278-
collection.append(
279-
createJsonValue("PUSH #[$]", sourceIndex, i.location().start, i.location().end, toString(h256(i.data()))));
280-
break;
281-
case PushProgramSize:
282-
collection.append(
283-
createJsonValue("PUSHSIZE", sourceIndex, i.location().start, i.location().end));
284-
break;
285-
case PushLibraryAddress:
286-
collection.append(
287-
createJsonValue("PUSHLIB", sourceIndex, i.location().start, i.location().end, m_libraries.at(h256(i.data())))
288-
);
289-
break;
290-
case PushDeployTimeAddress:
291-
collection.append(
292-
createJsonValue("PUSHDEPLOYADDRESS", sourceIndex, i.location().start, i.location().end)
293-
);
294-
break;
295-
case PushImmutable:
296-
collection.append(createJsonValue(
297-
"PUSHIMMUTABLE",
298-
sourceIndex,
299-
i.location().start,
300-
i.location().end,
301-
m_immutables.at(h256(i.data()))
302-
));
303-
break;
304-
case AssignImmutable:
305-
collection.append(createJsonValue(
306-
"ASSIGNIMMUTABLE",
307-
sourceIndex,
308-
i.location().start,
309-
i.location().end,
310-
m_immutables.at(h256(i.data()))
311-
));
312-
break;
313-
case Tag:
314-
collection.append(
315-
createJsonValue("tag", sourceIndex, i.location().start, i.location().end, toString(i.data())));
316-
collection.append(
317-
createJsonValue("JUMPDEST", sourceIndex, i.location().start, i.location().end));
318-
break;
319-
case PushData:
320-
collection.append(createJsonValue("PUSH data", sourceIndex, i.location().start, i.location().end, toStringInHex(i.data())));
321-
break;
322-
case VerbatimBytecode:
323-
collection.append(createJsonValue("VERBATIM", sourceIndex, i.location().start, i.location().end, toHex(i.verbatimData())));
324-
break;
325-
default:
326-
assertThrow(false, InvalidOpcode, "");
327-
}
460+
for (Json::Value const& item: assemblyItemAsJSON(i, sourceIndex))
461+
collection.append(item);
328462
}
329463

330464
if (!m_data.empty() || !m_subs.empty())
@@ -342,12 +476,59 @@ Json::Value Assembly::assemblyJSON(map<string, unsigned> const& _sourceIndices)
342476
}
343477
}
344478

345-
if (m_auxiliaryData.size() > 0)
479+
if (!m_auxiliaryData.empty())
346480
root[".auxdata"] = toHex(m_auxiliaryData);
347481

348482
return root;
349483
}
350484

485+
void Assembly::forEachJSONAssemblyItem(Json::Value const& _code, Assembly& _assembly)
486+
{
487+
solAssert(_code.isArray(), "");
488+
for (auto it = _code.begin(); it != _code.end(); ++it)
489+
{
490+
AssemblyItem current = assemblyItemFromJSON(*it, _assembly);
491+
_assembly.m_items.emplace_back(current);
492+
493+
auto nextIt = std::next(it);
494+
if (nextIt != _code.end())
495+
{
496+
AssemblyItem next = assemblyItemFromJSON(*nextIt, _assembly);
497+
if (current.type() == AssemblyItemType::Tag &&
498+
next.type() == AssemblyItemType::Operation && next.instruction() == Instruction::JUMPDEST)
499+
++it;
500+
}
501+
}
502+
}
503+
504+
bool Assembly::loadFromAssemblyJSON(Json::Value const& _json, Assembly& _assembly)
505+
{
506+
solAssert(_json[".code"].isArray(), "");
507+
forEachJSONAssemblyItem(_json[".code"], _assembly);
508+
Json::Value const& data = _json[".data"];
509+
for (Json::ValueConstIterator itr = data.begin(); itr != data.end(); itr++)
510+
{
511+
solAssert(itr.key().isString(), "");
512+
std::string key = itr.key().asString();
513+
Json::Value const& code = data[key];
514+
if (code.isString())
515+
_assembly.m_data[h256(fromHex(key))] = fromHex(code.asString());
516+
else
517+
{
518+
shared_ptr<Assembly> subassembly = make_shared<Assembly>();
519+
loadFromAssemblyJSON(code, *subassembly);
520+
Json::Value const& auxdata = data[key][".auxdata"];
521+
if (auxdata.isString())
522+
{
523+
solAssert(subassembly->m_auxiliaryData.empty(), "");
524+
subassembly->m_auxiliaryData = fromHex(auxdata.asString());
525+
}
526+
_assembly.m_subs.emplace_back(subassembly);
527+
}
528+
}
529+
return true;
530+
}
531+
351532
AssemblyItem Assembly::namedTag(string const& _name, size_t _params, size_t _returns, optional<uint64_t> _sourceID)
352533
{
353534
assertThrow(!_name.empty(), AssemblyException, "Empty named tag.");
@@ -402,7 +583,6 @@ Assembly& Assembly::optimise(bool _enable, EVMVersion _evmVersion, bool _isCreat
402583
return *this;
403584
}
404585

405-
406586
Assembly& Assembly::optimise(OptimiserSettings const& _settings)
407587
{
408588
optimiseInternal(_settings, {});

0 commit comments

Comments
 (0)