Skip to content

Commit 69be6bd

Browse files
committed
libevmasm: refactor asm-json export & add support for source list.
1 parent 724af73 commit 69be6bd

File tree

3 files changed

+219
-100
lines changed

3 files changed

+219
-100
lines changed

libevmasm/Assembly.cpp

Lines changed: 152 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -222,13 +222,16 @@ string Assembly::assemblyString(
222222
return tmp.str();
223223
}
224224

225-
Json::Value Assembly::createJsonValue(string _name, int _source, int _begin, int _end, string _value, string _jumpType)
225+
Json::Value Assembly::createJsonValue(
226+
string const& _name, int _sourceIndex, size_t _modifierDepth, int _begin, int _end, string const& _value, string const& _jumpType)
226227
{
227228
Json::Value value{Json::objectValue};
228229
value["name"] = _name;
229-
value["source"] = _source;
230+
value["source"] = _sourceIndex;
230231
value["begin"] = _begin;
231232
value["end"] = _end;
233+
if (_modifierDepth != 0)
234+
value["modifierDepth"] = static_cast<int>(_modifierDepth);
232235
if (!_value.empty())
233236
value["value"] = _value;
234237
if (!_jumpType.empty())
@@ -242,13 +245,153 @@ string Assembly::toStringInHex(u256 _value)
242245
hexStr << std::uppercase << hex << _value;
243246
return hexStr.str();
244247
}
248+
vector<Json::Value> Assembly::assemblyItemAsJSON(AssemblyItem const& _item, int _sourceIndex) const
249+
{
250+
vector<Json::Value> result;
251+
252+
switch (_item.type())
253+
{
254+
case Operation:
255+
result.emplace_back(createJsonValue(
256+
instructionInfo(_item.instruction()).name,
257+
_sourceIndex,
258+
_item.m_modifierDepth,
259+
_item.location().start,
260+
_item.location().end,
261+
_item.getJumpTypeAsString()));
262+
break;
263+
case Push:
264+
result.emplace_back(createJsonValue(
265+
"PUSH",
266+
_sourceIndex,
267+
_item.m_modifierDepth,
268+
_item.location().start,
269+
_item.location().end,
270+
toStringInHex(_item.data()),
271+
_item.getJumpTypeAsString()));
272+
break;
273+
case PushTag:
274+
if (_item.data() == 0)
275+
result.emplace_back(createJsonValue(
276+
"PUSH [ErrorTag]",
277+
_sourceIndex,
278+
_item.m_modifierDepth,
279+
_item.location().start,
280+
_item.location().end,
281+
""));
282+
else
283+
result.emplace_back(createJsonValue(
284+
"PUSH [tag]",
285+
_sourceIndex,
286+
_item.m_modifierDepth,
287+
_item.location().start,
288+
_item.location().end,
289+
toString(_item.data())));
290+
break;
291+
case PushSub:
292+
result.emplace_back(createJsonValue(
293+
"PUSH [$]",
294+
_sourceIndex,
295+
_item.m_modifierDepth,
296+
_item.location().start,
297+
_item.location().end,
298+
toString(h256(_item.data()))));
299+
break;
300+
case PushSubSize:
301+
result.emplace_back(createJsonValue(
302+
"PUSH #[$]",
303+
_sourceIndex,
304+
_item.m_modifierDepth,
305+
_item.location().start,
306+
_item.location().end,
307+
toString(h256(_item.data()))));
308+
break;
309+
case PushProgramSize:
310+
result.emplace_back(createJsonValue(
311+
"PUSHSIZE", _sourceIndex, _item.m_modifierDepth, _item.location().start, _item.location().end));
312+
break;
313+
case PushLibraryAddress:
314+
result.emplace_back(createJsonValue(
315+
"PUSHLIB",
316+
_sourceIndex,
317+
_item.m_modifierDepth,
318+
_item.location().start,
319+
_item.location().end,
320+
m_libraries.at(h256(_item.data()))));
321+
break;
322+
case PushDeployTimeAddress:
323+
result.emplace_back(createJsonValue(
324+
"PUSHDEPLOYADDRESS", _sourceIndex, _item.m_modifierDepth, _item.location().start, _item.location().end));
325+
break;
326+
case PushImmutable:
327+
result.emplace_back(createJsonValue(
328+
"PUSHIMMUTABLE",
329+
_sourceIndex,
330+
_item.m_modifierDepth,
331+
_item.location().start,
332+
_item.location().end,
333+
m_immutables.at(h256(_item.data()))));
334+
break;
335+
case AssignImmutable:
336+
result.emplace_back(createJsonValue(
337+
"ASSIGNIMMUTABLE",
338+
_sourceIndex,
339+
_item.m_modifierDepth,
340+
_item.location().start,
341+
_item.location().end,
342+
m_immutables.at(h256(_item.data()))));
343+
break;
344+
case Tag:
345+
result.emplace_back(createJsonValue(
346+
"tag",
347+
_sourceIndex,
348+
_item.m_modifierDepth,
349+
_item.location().start,
350+
_item.location().end,
351+
toString(_item.data())));
352+
result.emplace_back(createJsonValue(
353+
"JUMPDEST", _sourceIndex, _item.m_modifierDepth, _item.location().start, _item.location().end));
354+
break;
355+
case PushData:
356+
result.emplace_back(createJsonValue(
357+
"PUSH data",
358+
_sourceIndex,
359+
_item.m_modifierDepth,
360+
_item.location().start,
361+
_item.location().end,
362+
toStringInHex(_item.data())));
363+
break;
364+
case VerbatimBytecode:
365+
result.emplace_back(createJsonValue(
366+
"VERBATIM",
367+
_sourceIndex,
368+
_item.m_modifierDepth,
369+
_item.location().start,
370+
_item.location().end,
371+
util::toHex(_item.verbatimData())));
372+
break;
373+
default:
374+
assertThrow(false, InvalidOpcode, "");
375+
}
376+
return result;
377+
}
245378

246-
Json::Value Assembly::assemblyJSON(map<string, unsigned> const& _sourceIndices) const
379+
Json::Value Assembly::assemblyJSON(map<string, unsigned> const& _sourceIndices, bool _includeSourceList) const
247380
{
248381
Json::Value root;
249-
root[".code"] = Json::arrayValue;
382+
if (_includeSourceList)
383+
{
384+
root["sourceList"] = Json::arrayValue;
385+
Json::Value& sourceList = root["sourceList"];
386+
vector<string> sources(_sourceIndices.size());
387+
for (auto const& item: _sourceIndices)
388+
sources[item.second] = item.first;
389+
for (auto const& item: sources)
390+
sourceList.append(item);
391+
}
250392

251-
Json::Value& collection = root[".code"];
393+
root[".code"] = Json::arrayValue;
394+
Json::Value& code = root[".code"];
252395
for (AssemblyItem const& i: m_items)
253396
{
254397
int sourceIndex = -1;
@@ -259,85 +402,8 @@ Json::Value Assembly::assemblyJSON(map<string, unsigned> const& _sourceIndices)
259402
sourceIndex = static_cast<int>(iter->second);
260403
}
261404

262-
switch (i.type())
263-
{
264-
case Operation:
265-
collection.append(
266-
createJsonValue(
267-
instructionInfo(i.instruction()).name,
268-
sourceIndex,
269-
i.location().start,
270-
i.location().end,
271-
i.getJumpTypeAsString())
272-
);
273-
break;
274-
case Push:
275-
collection.append(
276-
createJsonValue("PUSH", sourceIndex, i.location().start, i.location().end, toStringInHex(i.data()), i.getJumpTypeAsString()));
277-
break;
278-
case PushTag:
279-
if (i.data() == 0)
280-
collection.append(
281-
createJsonValue("PUSH [ErrorTag]", sourceIndex, i.location().start, i.location().end, ""));
282-
else
283-
collection.append(
284-
createJsonValue("PUSH [tag]", sourceIndex, i.location().start, i.location().end, toString(i.data())));
285-
break;
286-
case PushSub:
287-
collection.append(
288-
createJsonValue("PUSH [$]", sourceIndex, i.location().start, i.location().end, toString(h256(i.data()))));
289-
break;
290-
case PushSubSize:
291-
collection.append(
292-
createJsonValue("PUSH #[$]", sourceIndex, i.location().start, i.location().end, toString(h256(i.data()))));
293-
break;
294-
case PushProgramSize:
295-
collection.append(
296-
createJsonValue("PUSHSIZE", sourceIndex, i.location().start, i.location().end));
297-
break;
298-
case PushLibraryAddress:
299-
collection.append(
300-
createJsonValue("PUSHLIB", sourceIndex, i.location().start, i.location().end, m_libraries.at(h256(i.data())))
301-
);
302-
break;
303-
case PushDeployTimeAddress:
304-
collection.append(
305-
createJsonValue("PUSHDEPLOYADDRESS", sourceIndex, i.location().start, i.location().end)
306-
);
307-
break;
308-
case PushImmutable:
309-
collection.append(createJsonValue(
310-
"PUSHIMMUTABLE",
311-
sourceIndex,
312-
i.location().start,
313-
i.location().end,
314-
m_immutables.at(h256(i.data()))
315-
));
316-
break;
317-
case AssignImmutable:
318-
collection.append(createJsonValue(
319-
"ASSIGNIMMUTABLE",
320-
sourceIndex,
321-
i.location().start,
322-
i.location().end,
323-
m_immutables.at(h256(i.data()))
324-
));
325-
break;
326-
case Tag:
327-
collection.append(
328-
createJsonValue("tag", sourceIndex, i.location().start, i.location().end, toString(i.data())));
329-
collection.append(
330-
createJsonValue("JUMPDEST", sourceIndex, i.location().start, i.location().end));
331-
break;
332-
case PushData:
333-
collection.append(createJsonValue("PUSH data", sourceIndex, i.location().start, i.location().end, toStringInHex(i.data())));
334-
break;
335-
case VerbatimBytecode:
336-
collection.append(createJsonValue("VERBATIM", sourceIndex, i.location().start, i.location().end, util::toHex(i.verbatimData())));
337-
break;
338-
default:
339-
assertThrow(false, InvalidOpcode, "");
340-
}
405+
for (Json::Value const& item: assemblyItemAsJSON(i, sourceIndex))
406+
code.append(item);
341407
}
342408

343409
if (!m_data.empty() || !m_subs.empty())
@@ -352,11 +418,11 @@ Json::Value Assembly::assemblyJSON(map<string, unsigned> const& _sourceIndices)
352418
{
353419
std::stringstream hexStr;
354420
hexStr << hex << i;
355-
data[hexStr.str()] = m_subs[i]->assemblyJSON(_sourceIndices);
421+
data[hexStr.str()] = m_subs[i]->assemblyJSON(_sourceIndices, false);
356422
}
357423
}
358424

359-
if (m_auxiliaryData.size() > 0)
425+
if (!m_auxiliaryData.empty())
360426
root[".auxdata"] = util::toHex(m_auxiliaryData);
361427

362428
return root;

libevmasm/Assembly.h

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include <sstream>
4040
#include <memory>
4141
#include <map>
42+
#include <utility>
4243

4344
namespace solidity::evmasm
4445
{
@@ -147,7 +148,8 @@ class Assembly
147148

148149
/// Create a JSON representation of the assembly.
149150
Json::Value assemblyJSON(
150-
std::map<std::string, unsigned> const& _sourceIndices = std::map<std::string, unsigned>()
151+
std::map<std::string, unsigned> const& _sourceIndices = std::map<std::string, unsigned>(),
152+
bool _includeSourceList = true
151153
) const;
152154

153155
/// Mark this assembly as invalid. Calling ``assemble`` on it will throw.
@@ -158,6 +160,16 @@ class Assembly
158160

159161
bool isCreation() const { return m_creation; }
160162

163+
void setSources(std::vector<std::shared_ptr<std::string const>> _sources) {
164+
m_sources = std::move(_sources);
165+
}
166+
167+
void setSources(std::vector<std::string> const& _sources) {
168+
for (auto const& item: _sources)
169+
m_sources.emplace_back(std::make_shared<std::string>(item));
170+
}
171+
std::vector<std::shared_ptr<std::string const>> sources() const& { return m_sources; }
172+
161173
protected:
162174
/// Does the same operations as @a optimise, but should only be applied to a sub and
163175
/// returns the replaced tags. Also takes an argument containing the tags of this assembly
@@ -166,14 +178,17 @@ class Assembly
166178

167179
unsigned codeSize(unsigned subTagSize) const;
168180

181+
std::vector<Json::Value> assemblyItemAsJSON(AssemblyItem const& _item, int _sourceIndex) const;
182+
169183
private:
170184
static Json::Value createJsonValue(
171-
std::string _name,
172-
int _source,
185+
std::string const& _name,
186+
int _sourceIndex,
187+
size_t _modifierDepth,
173188
int _begin,
174189
int _end,
175-
std::string _value = std::string(),
176-
std::string _jumpType = std::string()
190+
std::string const& _value = std::string(),
191+
std::string const& _jumpType = std::string()
177192
);
178193
static std::string toStringInHex(u256 _value);
179194

@@ -222,6 +237,8 @@ class Assembly
222237
std::string m_name;
223238

224239
langutil::SourceLocation m_currentSourceLocation;
240+
std::vector<std::shared_ptr<std::string const>> m_sources;
241+
225242
public:
226243
size_t m_currentModifierDepth = 0;
227244
};

0 commit comments

Comments
 (0)