diff --git a/.gitignore b/.gitignore index bbdf9d68d..f6eeba75f 100644 --- a/.gitignore +++ b/.gitignore @@ -40,6 +40,7 @@ docs/utils/*.pyc /deps/downloads/ deps/install deps/cache +cmake-build-debug/ # vim stuff [._]*.sw[a-p] diff --git a/Changelog.md b/Changelog.md index 683e2928d..0432babb5 100644 --- a/Changelog.md +++ b/Changelog.md @@ -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. diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index 10503c484..7ed44d236 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -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 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); } } diff --git a/libevmasm/Assembly.h b/libevmasm/Assembly.h index e859951bd..a76538375 100644 --- a/libevmasm/Assembly.h +++ b/libevmasm/Assembly.h @@ -133,7 +133,7 @@ public: /// Create a JSON representation of the assembly. Json::Value assemblyJSON( - StringMap const& _sourceCodes = StringMap() + std::map const& _sourceIndices = std::map() ) 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: diff --git a/libsolidity/codegen/Compiler.h b/libsolidity/codegen/Compiler.h index 8bd21e586..e12332015 100644 --- a/libsolidity/codegen/Compiler.h +++ b/libsolidity/codegen/Compiler.h @@ -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 const& _indices = std::map()) 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(); } diff --git a/libsolidity/codegen/CompilerContext.h b/libsolidity/codegen/CompilerContext.h index 0ee379f5a..c37afbfa5 100644 --- a/libsolidity/codegen/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -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 const& _indicies = std::map()) const { - return m_asm->assemblyJSON(_sourceCodes); + return m_asm->assemblyJSON(_indicies); } evmasm::LinkerObject const& assembledObject() const { return m_asm->assemble(); } diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 572b3bbbf..89ab13818 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -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(); } diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index 42279a499..099375879 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -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. diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 1b09b2f2c..9f837a996 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -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)) diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index 243d6dd72..ccb192ba1 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -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); diff --git a/test/libevmasm/Assembler.cpp b/test/libevmasm/Assembler.cpp index eac83e1bb..2d7057f7c 100644 --- a/test/libevmasm/Assembler.cpp +++ b/test/libevmasm/Assembler.cpp @@ -50,6 +50,10 @@ BOOST_AUTO_TEST_SUITE(Assembler) BOOST_AUTO_TEST_CASE(all_assembly_items) { + map indices = { + { "root.asm", 0 }, + { "sub.asm", 1 } + }; Assembly _assembly; auto root_asm = make_shared("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\"}}" ); } diff --git a/test/libsolidity/StandardCompiler.cpp b/test/libsolidity/StandardCompiler.cpp index 6ade0849f..df2aecbf5 100644 --- a/test/libsolidity/StandardCompiler.cpp +++ b/test/libsolidity/StandardCompiler.cpp @@ -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()));