mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Assembly: Added missing source field to legacy assembly json output to complete the source reference
This commit is contained in:
parent
2d1c4b770f
commit
18dea6b69c
1
.gitignore
vendored
1
.gitignore
vendored
@ -40,6 +40,7 @@ docs/utils/*.pyc
|
||||
/deps/downloads/
|
||||
deps/install
|
||||
deps/cache
|
||||
cmake-build-debug/
|
||||
|
||||
# vim stuff
|
||||
[._]*.sw[a-p]
|
||||
|
@ -15,6 +15,7 @@ Compiler Features:
|
||||
Bugfixes:
|
||||
* Parser: Fix an internal error for ``abstract`` without ``contract``.
|
||||
* Type Checker: Make invalid calls to uncallable types fatal errors.
|
||||
* Assembly: Added missing `source` field to legacy assembly json output to complete the source reference.
|
||||
|
||||
|
||||
|
||||
|
@ -197,10 +197,11 @@ string Assembly::assemblyString(StringMap const& _sourceCodes) const
|
||||
return tmp.str();
|
||||
}
|
||||
|
||||
Json::Value Assembly::createJsonValue(string _name, int _begin, int _end, string _value, string _jumpType)
|
||||
Json::Value Assembly::createJsonValue(string _name, int _source, int _begin, int _end, string _value, string _jumpType)
|
||||
{
|
||||
Json::Value value;
|
||||
value["name"] = _name;
|
||||
value["source"] = _source;
|
||||
value["begin"] = _begin;
|
||||
value["end"] = _end;
|
||||
if (!_value.empty())
|
||||
@ -217,65 +218,79 @@ string Assembly::toStringInHex(u256 _value)
|
||||
return hexStr.str();
|
||||
}
|
||||
|
||||
Json::Value Assembly::assemblyJSON(StringMap const& _sourceCodes) const
|
||||
Json::Value Assembly::assemblyJSON(map<string, unsigned> const& _sourceIndices) const
|
||||
{
|
||||
Json::Value root;
|
||||
|
||||
Json::Value& collection = root[".code"] = Json::arrayValue;
|
||||
for (AssemblyItem const& i: m_items)
|
||||
{
|
||||
unsigned sourceIndex = unsigned(-1);
|
||||
if (i.location().source)
|
||||
{
|
||||
auto iter = _sourceIndices.find(i.location().source->name());
|
||||
if (iter != _sourceIndices.end())
|
||||
sourceIndex = iter->second;
|
||||
}
|
||||
|
||||
switch (i.type())
|
||||
{
|
||||
case Operation:
|
||||
collection.append(
|
||||
createJsonValue(instructionInfo(i.instruction()).name, i.location().start, i.location().end, i.getJumpTypeAsString()));
|
||||
createJsonValue(
|
||||
instructionInfo(i.instruction()).name,
|
||||
sourceIndex,
|
||||
i.location().start,
|
||||
i.location().end,
|
||||
i.getJumpTypeAsString())
|
||||
);
|
||||
break;
|
||||
case Push:
|
||||
collection.append(
|
||||
createJsonValue("PUSH", i.location().start, i.location().end, toStringInHex(i.data()), i.getJumpTypeAsString()));
|
||||
createJsonValue("PUSH", sourceIndex, i.location().start, i.location().end, toStringInHex(i.data()), i.getJumpTypeAsString()));
|
||||
break;
|
||||
case PushString:
|
||||
collection.append(
|
||||
createJsonValue("PUSH tag", i.location().start, i.location().end, m_strings.at((h256)i.data())));
|
||||
createJsonValue("PUSH tag", sourceIndex, i.location().start, i.location().end, m_strings.at((h256)i.data())));
|
||||
break;
|
||||
case PushTag:
|
||||
if (i.data() == 0)
|
||||
collection.append(
|
||||
createJsonValue("PUSH [ErrorTag]", i.location().start, i.location().end, ""));
|
||||
createJsonValue("PUSH [ErrorTag]", sourceIndex, i.location().start, i.location().end, ""));
|
||||
else
|
||||
collection.append(
|
||||
createJsonValue("PUSH [tag]", i.location().start, i.location().end, toString(i.data())));
|
||||
createJsonValue("PUSH [tag]", sourceIndex, i.location().start, i.location().end, toString(i.data())));
|
||||
break;
|
||||
case PushSub:
|
||||
collection.append(
|
||||
createJsonValue("PUSH [$]", i.location().start, i.location().end, toString(h256(i.data()))));
|
||||
createJsonValue("PUSH [$]", sourceIndex, i.location().start, i.location().end, toString(h256(i.data()))));
|
||||
break;
|
||||
case PushSubSize:
|
||||
collection.append(
|
||||
createJsonValue("PUSH #[$]", i.location().start, i.location().end, toString(h256(i.data()))));
|
||||
createJsonValue("PUSH #[$]", sourceIndex, i.location().start, i.location().end, toString(h256(i.data()))));
|
||||
break;
|
||||
case PushProgramSize:
|
||||
collection.append(
|
||||
createJsonValue("PUSHSIZE", i.location().start, i.location().end));
|
||||
createJsonValue("PUSHSIZE", sourceIndex, i.location().start, i.location().end));
|
||||
break;
|
||||
case PushLibraryAddress:
|
||||
collection.append(
|
||||
createJsonValue("PUSHLIB", i.location().start, i.location().end, m_libraries.at(h256(i.data())))
|
||||
createJsonValue("PUSHLIB", sourceIndex, i.location().start, i.location().end, m_libraries.at(h256(i.data())))
|
||||
);
|
||||
break;
|
||||
case PushDeployTimeAddress:
|
||||
collection.append(
|
||||
createJsonValue("PUSHDEPLOYADDRESS", i.location().start, i.location().end)
|
||||
createJsonValue("PUSHDEPLOYADDRESS", sourceIndex, i.location().start, i.location().end)
|
||||
);
|
||||
break;
|
||||
case Tag:
|
||||
collection.append(
|
||||
createJsonValue("tag", i.location().start, i.location().end, toString(i.data())));
|
||||
createJsonValue("tag", sourceIndex, i.location().start, i.location().end, toString(i.data())));
|
||||
collection.append(
|
||||
createJsonValue("JUMPDEST", i.location().start, i.location().end));
|
||||
createJsonValue("JUMPDEST", sourceIndex, i.location().start, i.location().end));
|
||||
break;
|
||||
case PushData:
|
||||
collection.append(createJsonValue("PUSH data", i.location().start, i.location().end, toStringInHex(i.data())));
|
||||
collection.append(createJsonValue("PUSH data", sourceIndex, i.location().start, i.location().end, toStringInHex(i.data())));
|
||||
break;
|
||||
default:
|
||||
assertThrow(false, InvalidOpcode, "");
|
||||
@ -293,7 +308,7 @@ Json::Value Assembly::assemblyJSON(StringMap const& _sourceCodes) const
|
||||
{
|
||||
std::stringstream hexStr;
|
||||
hexStr << hex << i;
|
||||
data[hexStr.str()] = m_subs[i]->assemblyJSON(_sourceCodes);
|
||||
data[hexStr.str()] = m_subs[i]->assemblyJSON(_sourceIndices);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -133,7 +133,7 @@ public:
|
||||
|
||||
/// Create a JSON representation of the assembly.
|
||||
Json::Value assemblyJSON(
|
||||
StringMap const& _sourceCodes = StringMap()
|
||||
std::map<std::string, unsigned> const& _sourceIndices = std::map<std::string, unsigned>()
|
||||
) const;
|
||||
|
||||
protected:
|
||||
@ -145,7 +145,14 @@ protected:
|
||||
unsigned bytesRequired(unsigned subTagSize) const;
|
||||
|
||||
private:
|
||||
static Json::Value createJsonValue(std::string _name, int _begin, int _end, std::string _value = std::string(), std::string _jumpType = std::string());
|
||||
static Json::Value createJsonValue(
|
||||
std::string _name,
|
||||
int _source,
|
||||
int _begin,
|
||||
int _end,
|
||||
std::string _value = std::string(),
|
||||
std::string _jumpType = std::string()
|
||||
);
|
||||
static std::string toStringInHex(u256 _value);
|
||||
|
||||
protected:
|
||||
|
@ -64,9 +64,9 @@ public:
|
||||
return m_context.assemblyString(_sourceCodes);
|
||||
}
|
||||
/// @arg _sourceCodes is the map of input files to source code strings
|
||||
Json::Value assemblyJSON(StringMap const& _sourceCodes = StringMap()) const
|
||||
Json::Value assemblyJSON(std::map<std::string, unsigned> const& _indices = std::map<std::string, unsigned>()) const
|
||||
{
|
||||
return m_context.assemblyJSON(_sourceCodes);
|
||||
return m_context.assemblyJSON(_indices);
|
||||
}
|
||||
/// @returns Assembly items of the normal compiler context
|
||||
evmasm::AssemblyItems const& assemblyItems() const { return m_context.assembly().items(); }
|
||||
|
@ -262,9 +262,9 @@ public:
|
||||
}
|
||||
|
||||
/// @arg _sourceCodes is the map of input files to source code strings
|
||||
Json::Value assemblyJSON(StringMap const& _sourceCodes = StringMap()) const
|
||||
Json::Value assemblyJSON(std::map<std::string, unsigned> const& _indicies = std::map<std::string, unsigned>()) const
|
||||
{
|
||||
return m_asm->assemblyJSON(_sourceCodes);
|
||||
return m_asm->assemblyJSON(_indicies);
|
||||
}
|
||||
|
||||
evmasm::LinkerObject const& assembledObject() const { return m_asm->assemble(); }
|
||||
|
@ -670,14 +670,14 @@ string CompilerStack::assemblyString(string const& _contractName, StringMap _sou
|
||||
}
|
||||
|
||||
/// TODO: cache the JSON
|
||||
Json::Value CompilerStack::assemblyJSON(string const& _contractName, StringMap const& _sourceCodes) const
|
||||
Json::Value CompilerStack::assemblyJSON(string const& _contractName) const
|
||||
{
|
||||
if (m_stackState != CompilationSuccessful)
|
||||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
|
||||
|
||||
Contract const& currentContract = contract(_contractName);
|
||||
if (currentContract.compiler)
|
||||
return currentContract.compiler->assemblyJSON(_sourceCodes);
|
||||
return currentContract.compiler->assemblyJSON(sourceIndices());
|
||||
else
|
||||
return Json::Value();
|
||||
}
|
||||
|
@ -287,7 +287,7 @@ public:
|
||||
/// @returns a JSON representation of the assembly.
|
||||
/// @arg _sourceCodes is the map of input files to source code strings
|
||||
/// Prerequisite: Successful compilation.
|
||||
Json::Value assemblyJSON(std::string const& _contractName, StringMap const& _sourceCodes = StringMap()) const;
|
||||
Json::Value assemblyJSON(std::string const& _contractName) const;
|
||||
|
||||
/// @returns a JSON representing the contract ABI.
|
||||
/// Prerequisite: Successful call to parse or compile.
|
||||
|
@ -967,7 +967,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
|
||||
if (compilationSuccess && isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "evm.assembly", wildcardMatchesExperimental))
|
||||
evmData["assembly"] = compilerStack.assemblyString(contractName, sourceList);
|
||||
if (compilationSuccess && isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "evm.legacyAssembly", wildcardMatchesExperimental))
|
||||
evmData["legacyAssembly"] = compilerStack.assemblyJSON(contractName, sourceList);
|
||||
evmData["legacyAssembly"] = compilerStack.assemblyJSON(contractName);
|
||||
if (isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "evm.methodIdentifiers", wildcardMatchesExperimental))
|
||||
evmData["methodIdentifiers"] = compilerStack.methodIdentifiers(contractName);
|
||||
if (compilationSuccess && isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "evm.gasEstimates", wildcardMatchesExperimental))
|
||||
|
@ -1258,7 +1258,7 @@ void CommandLineInterface::handleCombinedJSON()
|
||||
if (requests.count(g_strOpcodes) && m_compiler->compilationSuccessful())
|
||||
contractData[g_strOpcodes] = evmasm::disassemble(m_compiler->object(contractName).bytecode);
|
||||
if (requests.count(g_strAsm) && m_compiler->compilationSuccessful())
|
||||
contractData[g_strAsm] = m_compiler->assemblyJSON(contractName, m_sourceCodes);
|
||||
contractData[g_strAsm] = m_compiler->assemblyJSON(contractName);
|
||||
if (requests.count(g_strSrcMap) && m_compiler->compilationSuccessful())
|
||||
{
|
||||
auto map = m_compiler->sourceMapping(contractName);
|
||||
@ -1612,7 +1612,7 @@ void CommandLineInterface::outputCompilationResults()
|
||||
{
|
||||
string ret;
|
||||
if (m_args.count(g_argAsmJson))
|
||||
ret = jsonPrettyPrint(m_compiler->assemblyJSON(contract, m_sourceCodes));
|
||||
ret = jsonPrettyPrint(m_compiler->assemblyJSON(contract));
|
||||
else
|
||||
ret = m_compiler->assemblyString(contract, m_sourceCodes);
|
||||
|
||||
|
@ -50,6 +50,10 @@ BOOST_AUTO_TEST_SUITE(Assembler)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(all_assembly_items)
|
||||
{
|
||||
map<string, unsigned> indices = {
|
||||
{ "root.asm", 0 },
|
||||
{ "sub.asm", 1 }
|
||||
};
|
||||
Assembly _assembly;
|
||||
auto root_asm = make_shared<CharStream>("lorem ipsum", "root.asm");
|
||||
_assembly.setSourceLocation({1, 3, root_asm});
|
||||
@ -119,22 +123,23 @@ BOOST_AUTO_TEST_CASE(all_assembly_items)
|
||||
"auxdata: 0x4266eeaa\n"
|
||||
);
|
||||
BOOST_CHECK_EQUAL(
|
||||
util::jsonCompactPrint(_assembly.assemblyJSON()),
|
||||
"{\".auxdata\":\"4266eeaa\",\".code\":[{\"begin\":1,\"end\":3,\"name\":\"tag\",\"value\":\"1\"},"
|
||||
"{\"begin\":1,\"end\":3,\"name\":\"JUMPDEST\"},"
|
||||
"{\"begin\":1,\"end\":3,\"name\":\"PUSH\",\"value\":\"1\"},"
|
||||
"{\"begin\":1,\"end\":3,\"name\":\"PUSH\",\"value\":\"2\"},"
|
||||
"{\"begin\":1,\"end\":3,\"name\":\"KECCAK256\"},"
|
||||
"{\"begin\":1,\"end\":3,\"name\":\"PUSHSIZE\"},"
|
||||
"{\"begin\":1,\"end\":3,\"name\":\"PUSHLIB\",\"value\":\"someLibrary\"},"
|
||||
"{\"begin\":1,\"end\":3,\"name\":\"PUSH [tag]\",\"value\":\"1\"},"
|
||||
"{\"begin\":1,\"end\":3,\"name\":\"JUMP\"},"
|
||||
"{\"begin\":1,\"end\":3,\"name\":\"PUSH data\",\"value\":\"A6885B3731702DA62E8E4A8F584AC46A7F6822F4E2BA50FBA902F67B1588D23B\"},"
|
||||
"{\"begin\":1,\"end\":3,\"name\":\"PUSH #[$]\",\"value\":\"0000000000000000000000000000000000000000000000000000000000000000\"},"
|
||||
"{\"begin\":1,\"end\":3,\"name\":\"PUSH [$]\",\"value\":\"0000000000000000000000000000000000000000000000000000000000000000\"},"
|
||||
"{\"begin\":1,\"end\":3,\"name\":\"PUSHDEPLOYADDRESS\"},"
|
||||
"{\"begin\":1,\"end\":3,\"name\":\"STOP\"}],"
|
||||
"\".data\":{\"0\":{\".code\":[{\"begin\":6,\"end\":8,\"name\":\"INVALID\"}]},"
|
||||
util::jsonCompactPrint(_assembly.assemblyJSON(indices)),
|
||||
"{\".auxdata\":\"4266eeaa\",\".code\":["
|
||||
"{\"begin\":1,\"end\":3,\"name\":\"tag\",\"source\":0,\"value\":\"1\"},"
|
||||
"{\"begin\":1,\"end\":3,\"name\":\"JUMPDEST\",\"source\":0},"
|
||||
"{\"begin\":1,\"end\":3,\"name\":\"PUSH\",\"source\":0,\"value\":\"1\"},"
|
||||
"{\"begin\":1,\"end\":3,\"name\":\"PUSH\",\"source\":0,\"value\":\"2\"},"
|
||||
"{\"begin\":1,\"end\":3,\"name\":\"KECCAK256\",\"source\":0},"
|
||||
"{\"begin\":1,\"end\":3,\"name\":\"PUSHSIZE\",\"source\":0},"
|
||||
"{\"begin\":1,\"end\":3,\"name\":\"PUSHLIB\",\"source\":0,\"value\":\"someLibrary\"},"
|
||||
"{\"begin\":1,\"end\":3,\"name\":\"PUSH [tag]\",\"source\":0,\"value\":\"1\"},"
|
||||
"{\"begin\":1,\"end\":3,\"name\":\"JUMP\",\"source\":0},"
|
||||
"{\"begin\":1,\"end\":3,\"name\":\"PUSH data\",\"source\":0,\"value\":\"A6885B3731702DA62E8E4A8F584AC46A7F6822F4E2BA50FBA902F67B1588D23B\"},"
|
||||
"{\"begin\":1,\"end\":3,\"name\":\"PUSH #[$]\",\"source\":0,\"value\":\"0000000000000000000000000000000000000000000000000000000000000000\"},"
|
||||
"{\"begin\":1,\"end\":3,\"name\":\"PUSH [$]\",\"source\":0,\"value\":\"0000000000000000000000000000000000000000000000000000000000000000\"},"
|
||||
"{\"begin\":1,\"end\":3,\"name\":\"PUSHDEPLOYADDRESS\",\"source\":0},"
|
||||
"{\"begin\":1,\"end\":3,\"name\":\"STOP\",\"source\":0}"
|
||||
"],\".data\":{\"0\":{\".code\":[{\"begin\":6,\"end\":8,\"name\":\"INVALID\",\"source\":1}]},"
|
||||
"\"A6885B3731702DA62E8E4A8F584AC46A7F6822F4E2BA50FBA902F67B1588D23B\":\"01020304\"}}"
|
||||
);
|
||||
}
|
||||
|
@ -394,27 +394,27 @@ BOOST_AUTO_TEST_CASE(basic_compilation)
|
||||
BOOST_CHECK(contract["evm"]["legacyAssembly"][".code"].isArray());
|
||||
BOOST_CHECK_EQUAL(
|
||||
util::jsonCompactPrint(contract["evm"]["legacyAssembly"][".code"]),
|
||||
"[{\"begin\":0,\"end\":14,\"name\":\"PUSH\",\"value\":\"80\"},"
|
||||
"{\"begin\":0,\"end\":14,\"name\":\"PUSH\",\"value\":\"40\"},"
|
||||
"{\"begin\":0,\"end\":14,\"name\":\"MSTORE\"},"
|
||||
"{\"begin\":0,\"end\":14,\"name\":\"CALLVALUE\"},"
|
||||
"{\"begin\":5,\"end\":14,\"name\":\"DUP1\"},"
|
||||
"{\"begin\":2,\"end\":4,\"name\":\"ISZERO\"},"
|
||||
"{\"begin\":2,\"end\":4,\"name\":\"PUSH [tag]\",\"value\":\"1\"},"
|
||||
"{\"begin\":2,\"end\":4,\"name\":\"JUMPI\"},"
|
||||
"{\"begin\":27,\"end\":28,\"name\":\"PUSH\",\"value\":\"0\"},"
|
||||
"{\"begin\":24,\"end\":25,\"name\":\"DUP1\"},"
|
||||
"{\"begin\":17,\"end\":29,\"name\":\"REVERT\"},"
|
||||
"{\"begin\":2,\"end\":4,\"name\":\"tag\",\"value\":\"1\"},"
|
||||
"{\"begin\":2,\"end\":4,\"name\":\"JUMPDEST\"},"
|
||||
"{\"begin\":0,\"end\":14,\"name\":\"POP\"},"
|
||||
"{\"begin\":0,\"end\":14,\"name\":\"PUSH #[$]\",\"value\":\"0000000000000000000000000000000000000000000000000000000000000000\"},"
|
||||
"{\"begin\":0,\"end\":14,\"name\":\"DUP1\"},"
|
||||
"{\"begin\":0,\"end\":14,\"name\":\"PUSH [$]\",\"value\":\"0000000000000000000000000000000000000000000000000000000000000000\"},"
|
||||
"{\"begin\":0,\"end\":14,\"name\":\"PUSH\",\"value\":\"0\"},"
|
||||
"{\"begin\":0,\"end\":14,\"name\":\"CODECOPY\"},"
|
||||
"{\"begin\":0,\"end\":14,\"name\":\"PUSH\",\"value\":\"0\"},"
|
||||
"{\"begin\":0,\"end\":14,\"name\":\"RETURN\"}]"
|
||||
"[{\"begin\":0,\"end\":14,\"name\":\"PUSH\",\"source\":0,\"value\":\"80\"},"
|
||||
"{\"begin\":0,\"end\":14,\"name\":\"PUSH\",\"source\":0,\"value\":\"40\"},"
|
||||
"{\"begin\":0,\"end\":14,\"name\":\"MSTORE\",\"source\":0},"
|
||||
"{\"begin\":0,\"end\":14,\"name\":\"CALLVALUE\",\"source\":0},"
|
||||
"{\"begin\":5,\"end\":14,\"name\":\"DUP1\",\"source\":-1},"
|
||||
"{\"begin\":2,\"end\":4,\"name\":\"ISZERO\",\"source\":-1},"
|
||||
"{\"begin\":2,\"end\":4,\"name\":\"PUSH [tag]\",\"source\":-1,\"value\":\"1\"},"
|
||||
"{\"begin\":2,\"end\":4,\"name\":\"JUMPI\",\"source\":-1},"
|
||||
"{\"begin\":27,\"end\":28,\"name\":\"PUSH\",\"source\":-1,\"value\":\"0\"},"
|
||||
"{\"begin\":24,\"end\":25,\"name\":\"DUP1\",\"source\":-1},"
|
||||
"{\"begin\":17,\"end\":29,\"name\":\"REVERT\",\"source\":-1},"
|
||||
"{\"begin\":2,\"end\":4,\"name\":\"tag\",\"source\":-1,\"value\":\"1\"},"
|
||||
"{\"begin\":2,\"end\":4,\"name\":\"JUMPDEST\",\"source\":-1},"
|
||||
"{\"begin\":0,\"end\":14,\"name\":\"POP\",\"source\":0},"
|
||||
"{\"begin\":0,\"end\":14,\"name\":\"PUSH #[$]\",\"source\":0,\"value\":\"0000000000000000000000000000000000000000000000000000000000000000\"},"
|
||||
"{\"begin\":0,\"end\":14,\"name\":\"DUP1\",\"source\":0},"
|
||||
"{\"begin\":0,\"end\":14,\"name\":\"PUSH [$]\",\"source\":0,\"value\":\"0000000000000000000000000000000000000000000000000000000000000000\"},"
|
||||
"{\"begin\":0,\"end\":14,\"name\":\"PUSH\",\"source\":0,\"value\":\"0\"},"
|
||||
"{\"begin\":0,\"end\":14,\"name\":\"CODECOPY\",\"source\":0},"
|
||||
"{\"begin\":0,\"end\":14,\"name\":\"PUSH\",\"source\":0,\"value\":\"0\"},"
|
||||
"{\"begin\":0,\"end\":14,\"name\":\"RETURN\",\"source\":0}]"
|
||||
);
|
||||
BOOST_CHECK(contract["metadata"].isString());
|
||||
BOOST_CHECK(solidity::test::isValidMetadata(contract["metadata"].asString()));
|
||||
|
Loading…
Reference in New Issue
Block a user