From f9c94d7c427dfd8dd27dd388f8d48739684f3a35 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 7 May 2020 14:46:47 +0200 Subject: [PATCH] Note function entry points. --- Changelog.md | 1 + docs/using-the-compiler.rst | 12 ++++ libevmasm/Assembly.cpp | 32 +++++++++-- libevmasm/Assembly.h | 14 ++++- libevmasm/LinkerObject.h | 11 ++++ libsolidity/codegen/CompilerContext.cpp | 20 ++++++- libsolidity/codegen/CompilerContext.h | 5 +- libsolidity/interface/StandardCompiler.cpp | 29 +++++++++- libsolidity/interface/StandardCompiler.h | 4 ++ libyul/backends/evm/AbstractAssembly.h | 3 +- libyul/backends/evm/EVMAssembly.cpp | 2 +- libyul/backends/evm/EVMAssembly.h | 2 +- libyul/backends/evm/EVMCodeTransform.cpp | 2 +- libyul/backends/evm/EthAssemblyAdapter.cpp | 4 +- libyul/backends/evm/EthAssemblyAdapter.h | 2 +- libyul/backends/evm/NoOutputAssembly.cpp | 2 +- libyul/backends/evm/NoOutputAssembly.h | 2 +- solc/CommandLineInterface.cpp | 12 ++++ test/cmdlineTests/function_debug_info/args | 1 + test/cmdlineTests/function_debug_info/err | 1 + .../function_debug_info/input.sol | 11 ++++ test/cmdlineTests/function_debug_info/output | 57 +++++++++++++++++++ .../function_debug_info_via_yul/args | 1 + .../function_debug_info_via_yul/err | 1 + .../function_debug_info_via_yul/input.sol | 7 +++ .../function_debug_info_via_yul/output | 11 ++++ .../standard_function_debug_info/input.json | 18 ++++++ .../standard_function_debug_info/output.json | 1 + test/cmdlineTests/standard_yul/output.json | 2 +- .../standard_yul_object/output.json | 2 +- .../standard_yul_object_name/output.json | 2 +- .../standard_yul_optimiserSteps/output.json | 2 +- .../standard_yul_optimized/output.json | 2 +- 33 files changed, 252 insertions(+), 26 deletions(-) create mode 100644 test/cmdlineTests/function_debug_info/args create mode 100644 test/cmdlineTests/function_debug_info/err create mode 100644 test/cmdlineTests/function_debug_info/input.sol create mode 100644 test/cmdlineTests/function_debug_info/output create mode 100644 test/cmdlineTests/function_debug_info_via_yul/args create mode 100644 test/cmdlineTests/function_debug_info_via_yul/err create mode 100644 test/cmdlineTests/function_debug_info_via_yul/input.sol create mode 100644 test/cmdlineTests/function_debug_info_via_yul/output create mode 100644 test/cmdlineTests/standard_function_debug_info/input.json create mode 100644 test/cmdlineTests/standard_function_debug_info/output.json diff --git a/Changelog.md b/Changelog.md index 0179f7524..87f108a3f 100644 --- a/Changelog.md +++ b/Changelog.md @@ -6,6 +6,7 @@ Language Features: Compiler Features: + * Standard JSON / combined JSON: New artifact "functionDebugData" that contains bytecode offsets of entry points of functions and potentially more information in the future. * Yul Optimizer: Evaluate ``keccak256(a, c)``, when the value at memory location ``a`` is known at compile time and ``c`` is a constant ``<= 32``. diff --git a/docs/using-the-compiler.rst b/docs/using-the-compiler.rst index 1ccebf359..4e66b8f34 100644 --- a/docs/using-the-compiler.rst +++ b/docs/using-the-compiler.rst @@ -344,6 +344,7 @@ Input Description // storageLayout - Slots, offsets and types of the contract's state variables. // evm.assembly - New assembly format // evm.legacyAssembly - Old-style assembly format in JSON + // evm.bytecode.functionDebugData - Debugging information at function level // evm.bytecode.object - Bytecode object // evm.bytecode.opcodes - Opcodes list // evm.bytecode.sourceMap - Source mapping (useful for debugging) @@ -476,6 +477,17 @@ Output Description "legacyAssembly": {}, // Bytecode and related details. "bytecode": { + // Debugging data at the level of functions. + "functionDebugData": { + // Now follows a set of functions including compiler-internal and + // user-defined function. The set does not have to be complete. + "@mint_13": { // Internal name of the function + "entryPoint": 128, // Byte offset into the bytecode where the function starts (optional) + "id": 13, // AST ID of the function definition or null for compiler-internal functions (optional) + "parameterSlots": 2, // Number of EVM stack slots for the function parameters (optional) + "returnSlots": 1 // Number of EVM stack slots for the return values (optional) + } + }, // The bytecode as a hex string. "object": "00fe", // Opcodes list (string) diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index 50be995a8..f63f3ede6 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -348,12 +348,18 @@ Json::Value Assembly::assemblyJSON(map const& _sourceIndices) return root; } -AssemblyItem Assembly::namedTag(string const& _name) +AssemblyItem Assembly::namedTag(string const& _name, size_t _params, size_t _returns, optional _sourceID) { assertThrow(!_name.empty(), AssemblyException, "Empty named tag."); - if (!m_namedTags.count(_name)) - m_namedTags[_name] = static_cast(newTag().data()); - return AssemblyItem{Tag, m_namedTags.at(_name)}; + if (m_namedTags.count(_name)) + { + assertThrow(m_namedTags.at(_name).params == _params, AssemblyException, ""); + assertThrow(m_namedTags.at(_name).returns == _returns, AssemblyException, ""); + assertThrow(m_namedTags.at(_name).sourceID == _sourceID, AssemblyException, ""); + } + else + m_namedTags[_name] = {static_cast(newTag().data()), _sourceID, _params, _returns}; + return AssemblyItem{Tag, m_namedTags.at(_name).id}; } AssemblyItem Assembly::newPushLibraryAddress(string const& _identifier) @@ -722,13 +728,16 @@ LinkerObject const& Assembly::assemble() const ret.bytecode.resize(ret.bytecode.size() + 20); break; case Tag: + { assertThrow(i.data() != 0, AssemblyException, "Invalid tag position."); assertThrow(i.splitForeignPushTag().first == numeric_limits::max(), AssemblyException, "Foreign tag."); + size_t tagId = static_cast(i.data()); assertThrow(ret.bytecode.size() < 0xffffffffL, AssemblyException, "Tag too large."); - assertThrow(m_tagPositionsInBytecode[static_cast(i.data())] == numeric_limits::max(), AssemblyException, "Duplicate tag position."); - m_tagPositionsInBytecode[static_cast(i.data())] = ret.bytecode.size(); + assertThrow(m_tagPositionsInBytecode[tagId] == numeric_limits::max(), AssemblyException, "Duplicate tag position."); + m_tagPositionsInBytecode[tagId] = ret.bytecode.size(); ret.bytecode.push_back(static_cast(Instruction::JUMPDEST)); break; + } default: assertThrow(false, InvalidOpcode, "Unexpected opcode while assembling."); } @@ -770,6 +779,17 @@ LinkerObject const& Assembly::assemble() const bytesRef r(ret.bytecode.data() + i.first, bytesPerTag); toBigEndian(pos, r); } + for (auto const& [name, tagInfo]: m_namedTags) + { + size_t position = m_tagPositionsInBytecode.at(tagInfo.id); + ret.functionDebugData[name] = { + position == numeric_limits::max() ? nullopt : optional{position}, + tagInfo.sourceID, + tagInfo.params, + tagInfo.returns + }; + } + for (auto const& dataItem: m_data) { auto references = dataRef.equal_range(dataItem.first); diff --git a/libevmasm/Assembly.h b/libevmasm/Assembly.h index e16023ad9..cce06ccb7 100644 --- a/libevmasm/Assembly.h +++ b/libevmasm/Assembly.h @@ -35,6 +35,7 @@ #include #include #include +#include namespace solidity::evmasm { @@ -49,7 +50,7 @@ public: AssemblyItem newTag() { assertThrow(m_usedTags < 0xffffffff, AssemblyException, ""); return AssemblyItem(Tag, m_usedTags++); } AssemblyItem newPushTag() { assertThrow(m_usedTags < 0xffffffff, AssemblyException, ""); return AssemblyItem(PushTag, m_usedTags++); } /// Returns a tag identified by the given name. Creates it if it does not yet exist. - AssemblyItem namedTag(std::string const& _name); + AssemblyItem namedTag(std::string const& _name, size_t _params, size_t _returns, std::optional _sourceID); AssemblyItem newData(bytes const& _data) { util::h256 h(util::keccak256(util::asString(_data))); m_data[h] = _data; return AssemblyItem(PushData, h); } bytes const& data(util::h256 const& _i) const { return m_data.at(_i); } AssemblyItem newSub(AssemblyPointer const& _sub) { m_subs.push_back(_sub); return AssemblyItem(PushSub, m_subs.size() - 1); } @@ -184,7 +185,16 @@ private: protected: /// 0 is reserved for exception unsigned m_usedTags = 1; - std::map m_namedTags; + + struct NamedTagInfo + { + size_t id; + std::optional sourceID; + size_t params; + size_t returns; + }; + + std::map m_namedTags; AssemblyItems m_items; std::map m_data; /// Data that is appended to the very end of the contract. diff --git a/libevmasm/LinkerObject.h b/libevmasm/LinkerObject.h index 03d01cc2c..e512dd7ab 100644 --- a/libevmasm/LinkerObject.h +++ b/libevmasm/LinkerObject.h @@ -45,6 +45,17 @@ struct LinkerObject /// to a list of offsets into the bytecode that refer to their values. std::map>> immutableReferences; + struct FunctionDebugData + { + std::optional bytecodeOffset; + std::optional sourceID; + size_t params = {}; + size_t returns = {}; + }; + + /// Bytecode offsets of named tags like function entry points. + std::map functionDebugData; + /// Appends the bytecode of @a _other and incorporates its link references. void append(LinkerObject const& _other); diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index ab1a67b96..35ff45965 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -148,7 +148,7 @@ void CompilerContext::callYulFunction( m_externallyUsedYulFunctions.insert(_name); auto const retTag = pushNewTag(); CompilerUtils(*this).moveIntoStack(_inArgs); - appendJumpTo(namedTag(_name), evmasm::AssemblyItem::JumpType::IntoFunction); + appendJumpTo(namedTag(_name, _inArgs, _outArgs, {}), evmasm::AssemblyItem::JumpType::IntoFunction); adjustStackOffset(static_cast(_outArgs) - 1 - static_cast(_inArgs)); *this << retTag.tag(); } @@ -596,7 +596,23 @@ evmasm::AssemblyItem CompilerContext::FunctionCompilationQueue::entryLabel( auto res = m_entryLabels.find(&_declaration); if (res == m_entryLabels.end()) { - evmasm::AssemblyItem tag(_context.newTag()); + size_t params = 0; + size_t returns = 0; + if (auto const* function = dynamic_cast(&_declaration)) + { + FunctionType functionType(*function, FunctionType::Kind::Internal); + params = CompilerUtils::sizeOnStack(functionType.parameterTypes()); + returns = CompilerUtils::sizeOnStack(functionType.returnParameterTypes()); + } + + // some name that cannot clash with yul function names. + string labelName = "@" + _declaration.name() + "_" + to_string(_declaration.id()); + evmasm::AssemblyItem tag = _context.namedTag( + labelName, + params, + returns, + _declaration.id() + ); m_entryLabels.insert(make_pair(&_declaration, tag)); m_functionsToCompile.push(&_declaration); return tag.tag(); diff --git a/libsolidity/codegen/CompilerContext.h b/libsolidity/codegen/CompilerContext.h index bdf9abc7d..e4358ccb5 100644 --- a/libsolidity/codegen/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -216,7 +216,10 @@ public: /// @returns a new tag without pushing any opcodes or data evmasm::AssemblyItem newTag() { return m_asm->newTag(); } /// @returns a new tag identified by name. - evmasm::AssemblyItem namedTag(std::string const& _name) { return m_asm->namedTag(_name); } + evmasm::AssemblyItem namedTag(std::string const& _name, size_t _params, size_t _returns, std::optional _sourceID) + { + return m_asm->namedTag(_name, _params, _returns, _sourceID); + } /// Adds a subroutine to the code (in the data section) and pushes its size (via a tag) /// on the stack. @returns the pushsub assembly item. evmasm::AssemblyItem addSubroutine(evmasm::AssemblyPointer const& _assembly) { return m_asm->appendSubroutine(_assembly); } diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 88857203f..ba9e5e23e 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -241,7 +241,7 @@ bool isArtifactRequested(Json::Value const& _outputSelection, string const& _fil vector evmObjectComponents(string const& _objectKind) { solAssert(_objectKind == "bytecode" || _objectKind == "deployedBytecode", ""); - vector components{"", ".object", ".opcodes", ".sourceMap", ".generatedSources", ".linkReferences"}; + vector components{"", ".object", ".opcodes", ".sourceMap", ".functionDebugData", ".generatedSources", ".linkReferences"}; if (_objectKind == "deployedBytecode") components.push_back(".immutableReferences"); return util::applyMap(components, [&](auto const& _s) { return "evm." + _objectKind + _s; }); @@ -388,6 +388,8 @@ Json::Value collectEVMObject( output["opcodes"] = evmasm::disassemble(_object.bytecode); if (_artifactRequested("sourceMap")) output["sourceMap"] = _sourceMap ? *_sourceMap : ""; + if (_artifactRequested("functionDebugData")) + output["functionDebugData"] = StandardCompiler::formatFunctionDebugData(_object.functionDebugData); if (_artifactRequested("linkReferences")) output["linkReferences"] = formatLinkReferences(_object.linkReferences); if (_runtimeObject && _artifactRequested("immutableReferences")) @@ -614,6 +616,7 @@ std::variant parseOptimizerSettings(Json::Value } + std::variant StandardCompiler::parseInput(Json::Value const& _input) { InputsAndSettings ret; @@ -1423,3 +1426,27 @@ string StandardCompiler::compile(string const& _input) noexcept return "{\"errors\":[{\"type\":\"JSONError\",\"component\":\"general\",\"severity\":\"error\",\"message\":\"Error writing output JSON.\"}]}"; } } + +Json::Value StandardCompiler::formatFunctionDebugData( + map const& _debugInfo +) +{ + Json::Value ret(Json::objectValue); + for (auto const& [name, info]: _debugInfo) + { + Json::Value fun; + if (info.sourceID) + fun["id"] = Json::UInt64(*info.sourceID); + else + fun["id"] = Json::nullValue; + if (info.bytecodeOffset) + fun["entryPoint"] = Json::UInt64(*info.bytecodeOffset); + else + fun["entryPoint"] = Json::nullValue; + fun["parameterSlots"] = Json::UInt64(info.params); + fun["returnSlots"] = Json::UInt64(info.returns); + ret[name] = move(fun); + } + + return ret; +} diff --git a/libsolidity/interface/StandardCompiler.h b/libsolidity/interface/StandardCompiler.h index 0eba42789..da193b3a1 100644 --- a/libsolidity/interface/StandardCompiler.h +++ b/libsolidity/interface/StandardCompiler.h @@ -58,6 +58,10 @@ public: /// output. Parsing errors are returned as regular errors. std::string compile(std::string const& _input) noexcept; + static Json::Value formatFunctionDebugData( + std::map const& _debugInfo + ); + private: struct InputsAndSettings { diff --git a/libyul/backends/evm/AbstractAssembly.h b/libyul/backends/evm/AbstractAssembly.h index 18d36953a..ef5c73c67 100644 --- a/libyul/backends/evm/AbstractAssembly.h +++ b/libyul/backends/evm/AbstractAssembly.h @@ -30,6 +30,7 @@ #include #include +#include namespace solidity::langutil { @@ -74,7 +75,7 @@ public: /// Generate a new unique label. virtual LabelID newLabelId() = 0; /// Returns a label identified by the given name. Creates it if it does not yet exist. - virtual LabelID namedLabel(std::string const& _name) = 0; + virtual LabelID namedLabel(std::string const& _name, size_t _params, size_t _returns, std::optional _sourceID) = 0; /// Append a reference to a to-be-linked symbol. /// Currently, we assume that the value is always a 20 byte number. virtual void appendLinkerSymbol(std::string const& _name) = 0; diff --git a/libyul/backends/evm/EVMAssembly.cpp b/libyul/backends/evm/EVMAssembly.cpp index 63f54419f..2e843b268 100644 --- a/libyul/backends/evm/EVMAssembly.cpp +++ b/libyul/backends/evm/EVMAssembly.cpp @@ -78,7 +78,7 @@ EVMAssembly::LabelID EVMAssembly::newLabelId() return m_nextLabelId++; } -AbstractAssembly::LabelID EVMAssembly::namedLabel(string const& _name) +AbstractAssembly::LabelID EVMAssembly::namedLabel(string const& _name, size_t, size_t, std::optional) { yulAssert(!_name.empty(), ""); if (!m_namedLabels.count(_name)) diff --git a/libyul/backends/evm/EVMAssembly.h b/libyul/backends/evm/EVMAssembly.h index 00cea1208..25c2765f5 100644 --- a/libyul/backends/evm/EVMAssembly.h +++ b/libyul/backends/evm/EVMAssembly.h @@ -58,7 +58,7 @@ public: /// Generate a new unique label. LabelID newLabelId() override; /// Returns a label identified by the given name. Creates it if it does not yet exist. - LabelID namedLabel(std::string const& _name) override; + LabelID namedLabel(std::string const& _name, size_t _params, size_t _returns, std::optional _sourceID) override; /// Append a reference to a to-be-linked symbol. /// Currently, we assume that the value is always a 20 byte number. void appendLinkerSymbol(std::string const& _name) override; diff --git a/libyul/backends/evm/EVMCodeTransform.cpp b/libyul/backends/evm/EVMCodeTransform.cpp index 49bfed968..c54a5e9a9 100644 --- a/libyul/backends/evm/EVMCodeTransform.cpp +++ b/libyul/backends/evm/EVMCodeTransform.cpp @@ -578,7 +578,7 @@ AbstractAssembly::LabelID CodeTransform::functionEntryID(YulString _name, Scope: { AbstractAssembly::LabelID id = m_useNamedLabelsForFunctions ? - m_assembly.namedLabel(_name.str()) : + m_assembly.namedLabel(_name.str(), _function.arguments.size(), _function.returns.size(), {}) : m_assembly.newLabelId(); m_context->functionEntryIDs[&_function] = id; } diff --git a/libyul/backends/evm/EthAssemblyAdapter.cpp b/libyul/backends/evm/EthAssemblyAdapter.cpp index ed2c81777..85af84fc3 100644 --- a/libyul/backends/evm/EthAssemblyAdapter.cpp +++ b/libyul/backends/evm/EthAssemblyAdapter.cpp @@ -84,9 +84,9 @@ size_t EthAssemblyAdapter::newLabelId() return assemblyTagToIdentifier(m_assembly.newTag()); } -size_t EthAssemblyAdapter::namedLabel(std::string const& _name) +size_t EthAssemblyAdapter::namedLabel(std::string const& _name, size_t _params, size_t _returns, std::optional _sourceID) { - return assemblyTagToIdentifier(m_assembly.namedTag(_name)); + return assemblyTagToIdentifier(m_assembly.namedTag(_name, _params, _returns, _sourceID)); } void EthAssemblyAdapter::appendLinkerSymbol(std::string const& _linkerSymbol) diff --git a/libyul/backends/evm/EthAssemblyAdapter.h b/libyul/backends/evm/EthAssemblyAdapter.h index 26c256d5b..e40719020 100644 --- a/libyul/backends/evm/EthAssemblyAdapter.h +++ b/libyul/backends/evm/EthAssemblyAdapter.h @@ -46,7 +46,7 @@ public: void appendLabel(LabelID _labelId) override; void appendLabelReference(LabelID _labelId) override; size_t newLabelId() override; - size_t namedLabel(std::string const& _name) override; + size_t namedLabel(std::string const& _name, size_t _params, size_t _returns, std::optional _sourceID) override; void appendLinkerSymbol(std::string const& _linkerSymbol) override; void appendVerbatim(bytes _data, size_t _arguments, size_t _returnVariables) override; void appendJump(int _stackDiffAfter, JumpType _jumpType) override; diff --git a/libyul/backends/evm/NoOutputAssembly.cpp b/libyul/backends/evm/NoOutputAssembly.cpp index 50cbf1c78..c8016d4a5 100644 --- a/libyul/backends/evm/NoOutputAssembly.cpp +++ b/libyul/backends/evm/NoOutputAssembly.cpp @@ -59,7 +59,7 @@ NoOutputAssembly::LabelID NoOutputAssembly::newLabelId() return 1; } -AbstractAssembly::LabelID NoOutputAssembly::namedLabel(string const&) +AbstractAssembly::LabelID NoOutputAssembly::namedLabel(string const&, size_t, size_t, optional) { return 1; } diff --git a/libyul/backends/evm/NoOutputAssembly.h b/libyul/backends/evm/NoOutputAssembly.h index fbb51a9c6..ebd83fe57 100644 --- a/libyul/backends/evm/NoOutputAssembly.h +++ b/libyul/backends/evm/NoOutputAssembly.h @@ -56,7 +56,7 @@ public: void appendLabel(LabelID _labelId) override; void appendLabelReference(LabelID _labelId) override; LabelID newLabelId() override; - LabelID namedLabel(std::string const& _name) override; + LabelID namedLabel(std::string const& _name, size_t _params, size_t _returns, std::optional _sourceID) override; void appendLinkerSymbol(std::string const& _name) override; void appendVerbatim(bytes _data, size_t _arguments, size_t _returnVariables) override; diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index 79587d78d..30a193403 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -189,6 +189,8 @@ static string const g_strSources = "sources"; static string const g_strSourceList = "sourceList"; static string const g_strSrcMap = "srcmap"; static string const g_strSrcMapRuntime = "srcmap-runtime"; +static string const g_strFunDebug = "function-debug"; +static string const g_strFunDebugRuntime = "function-debug-runtime"; static string const g_strStandardJSON = "standard-json"; static string const g_strStrictAssembly = "strict-assembly"; static string const g_strSwarm = "swarm"; @@ -257,6 +259,8 @@ static set const g_combinedJsonArgs g_strBinary, g_strBinaryRuntime, g_strCompactJSON, + g_strFunDebug, + g_strFunDebugRuntime, g_strGeneratedSources, g_strGeneratedSourcesRuntime, g_strInterface, @@ -1672,6 +1676,14 @@ void CommandLineInterface::handleCombinedJSON() auto map = m_compiler->runtimeSourceMapping(contractName); contractData[g_strSrcMapRuntime] = map ? *map : ""; } + if (requests.count(g_strFunDebug) && m_compiler->compilationSuccessful()) + contractData[g_strFunDebug] = StandardCompiler::formatFunctionDebugData( + m_compiler->object(contractName).functionDebugData + ); + if (requests.count(g_strFunDebugRuntime) && m_compiler->compilationSuccessful()) + contractData[g_strFunDebugRuntime] = StandardCompiler::formatFunctionDebugData( + m_compiler->runtimeObject(contractName).functionDebugData + ); if (requests.count(g_strSignatureHashes)) contractData[g_strSignatureHashes] = m_compiler->methodIdentifiers(contractName); if (requests.count(g_strNatspecDev)) diff --git a/test/cmdlineTests/function_debug_info/args b/test/cmdlineTests/function_debug_info/args new file mode 100644 index 000000000..ff730a4ce --- /dev/null +++ b/test/cmdlineTests/function_debug_info/args @@ -0,0 +1 @@ +--optimize --combined-json function-debug,function-debug-runtime --pretty-json diff --git a/test/cmdlineTests/function_debug_info/err b/test/cmdlineTests/function_debug_info/err new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/test/cmdlineTests/function_debug_info/err @@ -0,0 +1 @@ + diff --git a/test/cmdlineTests/function_debug_info/input.sol b/test/cmdlineTests/function_debug_info/input.sol new file mode 100644 index 000000000..7b4c59676 --- /dev/null +++ b/test/cmdlineTests/function_debug_info/input.sol @@ -0,0 +1,11 @@ +pragma solidity >=0.0; +// SPDX-License-Identifier: GPL-3.0 +contract C { + function f(uint[] calldata x) pure external returns (uint) { return x[0]; } + // This will be optimized out + function g() pure internal {} + mapping(uint => uint) public t; + constructor(uint x) { + t[0] = x; + } +} diff --git a/test/cmdlineTests/function_debug_info/output b/test/cmdlineTests/function_debug_info/output new file mode 100644 index 000000000..4889b15ea --- /dev/null +++ b/test/cmdlineTests/function_debug_info/output @@ -0,0 +1,57 @@ +{ + "contracts": + { + "function_debug_info/input.sol:C": + { + "function-debug": + { + "@_34": + { + "id": 34, + "parameterSlots": 1, + "returnSlots": 0 + }, + "abi_decode_tuple_t_uint256_fromMemory": + { + "entryPoint": 94, + "parameterSlots": 2, + "returnSlots": 1 + } + }, + "function-debug-runtime": + { + "@f_14": + { + "entryPoint": 128, + "id": 14, + "parameterSlots": 2, + "returnSlots": 1 + }, + "@t_22": + { + "id": 22, + "parameterSlots": 0, + "returnSlots": 0 + }, + "abi_decode_tuple_t_array$_t_uint256_$dyn_calldata_ptr": + { + "entryPoint": 178, + "parameterSlots": 2, + "returnSlots": 2 + }, + "abi_decode_tuple_t_uint256": + { + "entryPoint": 295, + "parameterSlots": 2, + "returnSlots": 1 + }, + "abi_encode_tuple_t_uint256__to_t_uint256__fromStack_reversed": + { + "parameterSlots": 2, + "returnSlots": 1 + } + } + } + }, + "version": "" +} diff --git a/test/cmdlineTests/function_debug_info_via_yul/args b/test/cmdlineTests/function_debug_info_via_yul/args new file mode 100644 index 000000000..ab626e663 --- /dev/null +++ b/test/cmdlineTests/function_debug_info_via_yul/args @@ -0,0 +1 @@ +--experimental-via-ir --optimize --combined-json function-debug,function-debug-runtime --pretty-json diff --git a/test/cmdlineTests/function_debug_info_via_yul/err b/test/cmdlineTests/function_debug_info_via_yul/err new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/test/cmdlineTests/function_debug_info_via_yul/err @@ -0,0 +1 @@ + diff --git a/test/cmdlineTests/function_debug_info_via_yul/input.sol b/test/cmdlineTests/function_debug_info_via_yul/input.sol new file mode 100644 index 000000000..23040af0f --- /dev/null +++ b/test/cmdlineTests/function_debug_info_via_yul/input.sol @@ -0,0 +1,7 @@ +pragma solidity >=0.0; +// SPDX-License-Identifier: GPL-3.0 +contract C { + function f(uint[] calldata x) pure external returns (uint) { return x[0]; } + // This will be optimized out + function g() pure internal {} +} diff --git a/test/cmdlineTests/function_debug_info_via_yul/output b/test/cmdlineTests/function_debug_info_via_yul/output new file mode 100644 index 000000000..5af245ce4 --- /dev/null +++ b/test/cmdlineTests/function_debug_info_via_yul/output @@ -0,0 +1,11 @@ +{ + "contracts": + { + "function_debug_info_via_yul/input.sol:C": + { + "function-debug": {}, + "function-debug-runtime": {} + } + }, + "version": "" +} diff --git a/test/cmdlineTests/standard_function_debug_info/input.json b/test/cmdlineTests/standard_function_debug_info/input.json new file mode 100644 index 000000000..653c61151 --- /dev/null +++ b/test/cmdlineTests/standard_function_debug_info/input.json @@ -0,0 +1,18 @@ +{ + "language": "Solidity", + "sources": { + "a.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; pragma abicoder v2; contract A { function f(uint[] memory x) public pure returns (uint256) { return x[0] + x[1];} }" + } + }, + "settings": { + "outputSelection": { + "*": { + "A": [ + "evm.deployedBytecode.functionDebugData", + "evm.bytecode.functionDebugData" + ] + } + } + } +} diff --git a/test/cmdlineTests/standard_function_debug_info/output.json b/test/cmdlineTests/standard_function_debug_info/output.json new file mode 100644 index 000000000..5dc180875 --- /dev/null +++ b/test/cmdlineTests/standard_function_debug_info/output.json @@ -0,0 +1 @@ +{"contracts":{"a.sol":{"A":{"evm":{"bytecode":{"functionDebugData":{}},"deployedBytecode":{"functionDebugData":{"@f_19":{"entryPoint":96,"id":19,"parameterSlots":1,"returnSlots":1},"abi_decode_available_length_t_array$_t_uint256_$dyn_memory_ptr":{"entryPoint":247,"id":null,"parameterSlots":3,"returnSlots":1},"abi_decode_t_array$_t_uint256_$dyn_memory_ptr":{"entryPoint":359,"id":null,"parameterSlots":2,"returnSlots":1},"abi_decode_t_uint256":{"entryPoint":405,"id":null,"parameterSlots":2,"returnSlots":1},"abi_decode_tuple_t_array$_t_uint256_$dyn_memory_ptr":{"entryPoint":426,"id":null,"parameterSlots":2,"returnSlots":1},"abi_encode_t_uint256_to_t_uint256_fromStack":{"entryPoint":499,"id":null,"parameterSlots":2,"returnSlots":0},"abi_encode_tuple_t_uint256__to_t_uint256__fromStack_reversed":{"entryPoint":514,"id":null,"parameterSlots":2,"returnSlots":1},"allocate_memory":{"entryPoint":541,"id":null,"parameterSlots":1,"returnSlots":1},"allocate_unbounded":{"entryPoint":568,"id":null,"parameterSlots":0,"returnSlots":1},"array_allocation_size_t_array$_t_uint256_$dyn_memory_ptr":{"entryPoint":578,"id":null,"parameterSlots":1,"returnSlots":1},"checked_add_t_uint256":{"entryPoint":622,"id":null,"parameterSlots":2,"returnSlots":1},"cleanup_t_uint256":{"entryPoint":708,"id":null,"parameterSlots":1,"returnSlots":1},"finalize_allocation":{"entryPoint":718,"id":null,"parameterSlots":2,"returnSlots":0},"panic_error_0x11":{"entryPoint":767,"id":null,"parameterSlots":0,"returnSlots":0},"panic_error_0x41":{"entryPoint":814,"id":null,"parameterSlots":0,"returnSlots":0},"revert_error_1b9f4a0a5773e33b91aa01db23bf8c55fce1411167c872835e7fa00a4f17d46d":{"entryPoint":861,"id":null,"parameterSlots":0,"returnSlots":0},"revert_error_81385d8c0b31fffe14be1da910c8bd3a80be4cfa248e04f42ec0faea3132a8ef":{"entryPoint":866,"id":null,"parameterSlots":0,"returnSlots":0},"revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db":{"entryPoint":871,"id":null,"parameterSlots":0,"returnSlots":0},"revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b":{"entryPoint":876,"id":null,"parameterSlots":0,"returnSlots":0},"round_up_to_mul_of_32":{"entryPoint":881,"id":null,"parameterSlots":1,"returnSlots":1},"validator_revert_t_uint256":{"entryPoint":898,"id":null,"parameterSlots":1,"returnSlots":0}}}}}}},"sources":{"a.sol":{"id":0}}} diff --git a/test/cmdlineTests/standard_yul/output.json b/test/cmdlineTests/standard_yul/output.json index e6c6e1390..e9e49f0b5 100644 --- a/test/cmdlineTests/standard_yul/output.json +++ b/test/cmdlineTests/standard_yul/output.json @@ -14,7 +14,7 @@ sstore /* \"A\":0:42 */ pop -","bytecode":{"generatedSources":[],"linkReferences":{},"object":"","opcodes":"","sourceMap":""}},"ir":"object \"object\" { +","bytecode":{"functionDebugData":{},"generatedSources":[],"linkReferences":{},"object":"","opcodes":"","sourceMap":""}},"ir":"object \"object\" { code { let x := mload(0) sstore(add(x, 0), 0) diff --git a/test/cmdlineTests/standard_yul_object/output.json b/test/cmdlineTests/standard_yul_object/output.json index d4dcb7acd..0db26c4a1 100644 --- a/test/cmdlineTests/standard_yul_object/output.json +++ b/test/cmdlineTests/standard_yul_object/output.json @@ -13,7 +13,7 @@ pop stop data_4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45 616263 -","bytecode":{"generatedSources":[],"linkReferences":{},"object":"","opcodes":"","sourceMap":""}},"ir":"object \"NamedObject\" { +","bytecode":{"functionDebugData":{},"generatedSources":[],"linkReferences":{},"object":"","opcodes":"","sourceMap":""}},"ir":"object \"NamedObject\" { code { let x := dataoffset(\"DataName\") sstore(add(x, 0), 0) diff --git a/test/cmdlineTests/standard_yul_object_name/output.json b/test/cmdlineTests/standard_yul_object_name/output.json index 0abd732e4..10139b5a2 100644 --- a/test/cmdlineTests/standard_yul_object_name/output.json +++ b/test/cmdlineTests/standard_yul_object_name/output.json @@ -22,7 +22,7 @@ sub_0: assembly { /* \"A\":137:149 */ revert } -","bytecode":{"generatedSources":[],"linkReferences":{},"object":"","opcodes":"","sourceMap":""},"deployedBytecode":{"generatedSources":[],"linkReferences":{},"object":"","opcodes":"","sourceMap":""}},"ir":"object \"NamedObject\" { +","bytecode":{"functionDebugData":{},"generatedSources":[],"linkReferences":{},"object":"","opcodes":"","sourceMap":""},"deployedBytecode":{"functionDebugData":{},"generatedSources":[],"linkReferences":{},"object":"","opcodes":"","sourceMap":""}},"ir":"object \"NamedObject\" { code { let x := dataoffset(\"DataName\") sstore(add(x, 0), 0) diff --git a/test/cmdlineTests/standard_yul_optimiserSteps/output.json b/test/cmdlineTests/standard_yul_optimiserSteps/output.json index 536ee0047..de08a24b7 100644 --- a/test/cmdlineTests/standard_yul_optimiserSteps/output.json +++ b/test/cmdlineTests/standard_yul_optimiserSteps/output.json @@ -13,7 +13,7 @@ /* \"A\":20:40 */ sstore pop -","bytecode":{"generatedSources":[],"linkReferences":{},"object":"","opcodes":"","sourceMap":""}},"ir":"object \"object\" { +","bytecode":{"functionDebugData":{},"generatedSources":[],"linkReferences":{},"object":"","opcodes":"","sourceMap":""}},"ir":"object \"object\" { code { let x := mload(0) sstore(add(x, 0), 0) diff --git a/test/cmdlineTests/standard_yul_optimized/output.json b/test/cmdlineTests/standard_yul_optimized/output.json index 758904e93..2aa40d5b7 100644 --- a/test/cmdlineTests/standard_yul_optimized/output.json +++ b/test/cmdlineTests/standard_yul_optimized/output.json @@ -5,7 +5,7 @@ mload /* \"A\":20:40 */ sstore -","bytecode":{"generatedSources":[],"linkReferences":{},"object":"","opcodes":"","sourceMap":""}},"ir":"object \"object\" { +","bytecode":{"functionDebugData":{},"generatedSources":[],"linkReferences":{},"object":"","opcodes":"","sourceMap":""}},"ir":"object \"object\" { code { let x := mload(0) sstore(add(x, 0), 0)