Skip to content

Commit 87a0819

Browse files
committed
libevmasm: refactor asm-json export & add support for source list.
1 parent 430ecb6 commit 87a0819

File tree

6 files changed

+149
-125
lines changed

6 files changed

+149
-125
lines changed

libevmasm/Assembly.cpp

Lines changed: 46 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -222,33 +222,11 @@ 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)
226-
{
227-
Json::Value value{Json::objectValue};
228-
value["name"] = _name;
229-
value["source"] = _source;
230-
value["begin"] = _begin;
231-
value["end"] = _end;
232-
if (!_value.empty())
233-
value["value"] = _value;
234-
if (!_jumpType.empty())
235-
value["jumpType"] = _jumpType;
236-
return value;
237-
}
238-
239-
string Assembly::toStringInHex(u256 _value)
240-
{
241-
std::stringstream hexStr;
242-
hexStr << std::uppercase << hex << _value;
243-
return hexStr.str();
244-
}
245-
246-
Json::Value Assembly::assemblyJSON(map<string, unsigned> const& _sourceIndices) const
225+
Json::Value Assembly::assemblyJSON(map<string, unsigned> const& _sourceIndices, bool _includeSourceList) const
247226
{
248227
Json::Value root;
249228
root[".code"] = Json::arrayValue;
250-
251-
Json::Value& collection = root[".code"];
229+
Json::Value& code = root[".code"];
252230
for (AssemblyItem const& i: m_items)
253231
{
254232
int sourceIndex = -1;
@@ -259,104 +237,68 @@ Json::Value Assembly::assemblyJSON(map<string, unsigned> const& _sourceIndices)
259237
sourceIndex = static_cast<int>(iter->second);
260238
}
261239

262-
switch (i.type())
240+
auto [name, data] = i.nameAndData();
241+
Json::Value item;
242+
item["name"] = name;
243+
item["begin"] = i.location().start;
244+
item["end"] = i.location().end;
245+
if (i.m_modifierDepth != 0)
246+
item["modifierDepth"] = static_cast<int>(i.m_modifierDepth);
247+
std::string jumpType = i.getJumpTypeAsString();
248+
if (!jumpType.empty())
263249
{
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, "");
250+
if (name == "JUMP")
251+
item["value"] = jumpType;
252+
if (name == "PUSH")
253+
item["jumpType"] = jumpType;
254+
}
255+
if (name == "PUSHLIB")
256+
data = m_libraries.at(h256(data));
257+
else if (name == "PUSHIMMUTABLE" || name == "ASSIGNIMMUTABLE")
258+
data = m_immutables.at(h256(data));
259+
if (!data.empty())
260+
item["value"] = data;
261+
item["source"] = sourceIndex;
262+
code.append(item);
263+
264+
if (name == "tag")
265+
{
266+
Json::Value jumpdest;
267+
jumpdest["name"] = "JUMPDEST";
268+
jumpdest["begin"] = i.location().start;
269+
jumpdest["end"] = i.location().end;
270+
jumpdest["source"] = sourceIndex;
271+
code.append(jumpdest);
340272
}
341273
}
274+
if (_includeSourceList)
275+
{
276+
root["sourceList"] = Json::arrayValue;
277+
Json::Value& jsonSourceList = root["sourceList"];
278+
vector<string> sourceNames(_sourceIndices.size());
279+
for (auto const& [name, index]: _sourceIndices)
280+
sourceNames[index] = name;
281+
for (auto const& item: sourceNames)
282+
jsonSourceList.append(item);
283+
}
342284

343285
if (!m_data.empty() || !m_subs.empty())
344286
{
345287
root[".data"] = Json::objectValue;
346288
Json::Value& data = root[".data"];
347289
for (auto const& i: m_data)
348290
if (u256(i.first) >= m_subs.size())
349-
data[toStringInHex((u256)i.first)] = util::toHex(i.second);
291+
data[util::toHex(toBigEndian((u256)i.first), util::HexPrefix::DontAdd, util::HexCase::Upper)] = util::toHex(i.second);
350292

351293
for (size_t i = 0; i < m_subs.size(); ++i)
352294
{
353295
std::stringstream hexStr;
354296
hexStr << hex << i;
355-
data[hexStr.str()] = m_subs[i]->assemblyJSON(_sourceIndices);
297+
data[hexStr.str()] = m_subs[i]->assemblyJSON(_sourceIndices, /*_includeSourceList = */false);
356298
}
357299
}
358300

359-
if (m_auxiliaryData.size() > 0)
301+
if (!m_auxiliaryData.empty())
360302
root[".auxdata"] = util::toHex(m_auxiliaryData);
361303

362304
return root;

libevmasm/Assembly.h

Lines changed: 4 additions & 11 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.
@@ -167,16 +169,6 @@ class Assembly
167169
unsigned codeSize(unsigned subTagSize) const;
168170

169171
private:
170-
static Json::Value createJsonValue(
171-
std::string _name,
172-
int _source,
173-
int _begin,
174-
int _end,
175-
std::string _value = std::string(),
176-
std::string _jumpType = std::string()
177-
);
178-
static std::string toStringInHex(u256 _value);
179-
180172
bool m_invalid = false;
181173

182174
Assembly const* subAssemblyById(size_t _subId) const;
@@ -222,6 +214,7 @@ class Assembly
222214
std::string m_name;
223215

224216
langutil::SourceLocation m_currentSourceLocation;
217+
225218
public:
226219
size_t m_currentModifierDepth = 0;
227220
};

libevmasm/AssemblyItem.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <libevmasm/Assembly.h>
2222

2323
#include <libsolutil/CommonData.h>
24+
#include <libsolutil/CommonIO.h>
2425
#include <libsolutil/Numeric.h>
2526
#include <libsolutil/StringUtils.h>
2627
#include <libsolutil/FixedHash.h>
@@ -56,6 +57,51 @@ pair<size_t, size_t> AssemblyItem::splitForeignPushTag() const
5657
return make_pair(subId, tag);
5758
}
5859

60+
string AssemblyItem::toStringInHex(u256 _value)
61+
{
62+
std::stringstream hexStr;
63+
hexStr << std::uppercase << hex << _value;
64+
return hexStr.str();
65+
}
66+
67+
pair<string, string> AssemblyItem::nameAndData() const
68+
{
69+
switch (type())
70+
{
71+
case Operation:
72+
return {instructionInfo(instruction()).name, m_data != nullptr ? toStringInHex(*m_data) : ""};
73+
case Push:
74+
return {"PUSH", toStringInHex(data())};
75+
case PushTag:
76+
if (data() == 0)
77+
return {"PUSH [ErrorTag]", ""};
78+
else
79+
return {"PUSH [tag]", util::toString(data())};
80+
case PushSub:
81+
return {"PUSH [$]", toString(util::h256(data()))};
82+
case PushSubSize:
83+
return {"PUSH #[$]", toString(util::h256(data()))};
84+
case PushProgramSize:
85+
return {"PUSHSIZE", ""};
86+
case PushLibraryAddress:
87+
return {"PUSHLIB", toString(util::h256(data()))};
88+
case PushDeployTimeAddress:
89+
return {"PUSHDEPLOYADDRESS", ""};
90+
case PushImmutable:
91+
return {"PUSHIMMUTABLE", toString(util::h256(data()))};
92+
case AssignImmutable:
93+
return {"ASSIGNIMMUTABLE", toString(util::h256(data()))};
94+
case Tag:
95+
return {"tag", util::toString(data())};
96+
case PushData:
97+
return {"PUSH data", toStringInHex(data())};
98+
case VerbatimBytecode:
99+
return {"VERBATIM", util::toHex(verbatimData())};
100+
default:
101+
assertThrow(false, InvalidOpcode, "");
102+
}
103+
}
104+
59105
void AssemblyItem::setPushTagSubIdAndTag(size_t _subId, size_t _tag)
60106
{
61107
assertThrow(m_type == PushTag || m_type == Tag, util::Exception, "");

libevmasm/AssemblyItem.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ class AssemblyItem
105105
AssemblyItemType type() const { return m_type; }
106106
u256 const& data() const { assertThrow(m_type != Operation, util::Exception, ""); return *m_data; }
107107
void setData(u256 const& _data) { assertThrow(m_type != Operation, util::Exception, ""); m_data = std::make_shared<u256>(_data); }
108+
std::pair<std::string, std::string> nameAndData() const;
108109

109110
bytes const& verbatimData() const { assertThrow(m_type == VerbatimBytecode, util::Exception, ""); return std::get<2>(*m_verbatimBytecode); }
110111

@@ -179,6 +180,7 @@ class AssemblyItem
179180
void setImmutableOccurrences(size_t _n) const { m_immutableOccurrences = _n; }
180181

181182
private:
183+
static std::string toStringInHex(u256 _value);
182184
size_t opcodeCount() const noexcept;
183185

184186
AssemblyItemType m_type;

test/cmdlineTests/asm_json/output

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1582,5 +1582,10 @@ EVM assembly:
15821582
}
15831583
]
15841584
}
1585-
}
1585+
},
1586+
"sourceList":
1587+
[
1588+
"asm_json/input.sol",
1589+
"#utility.yul"
1590+
]
15861591
}

0 commit comments

Comments
 (0)