diff --git a/libevmasm/AbstractAssemblyStack.h b/libevmasm/AbstractAssemblyStack.h index 278edf5c273b..c4eb804eea41 100644 --- a/libevmasm/AbstractAssemblyStack.h +++ b/libevmasm/AbstractAssemblyStack.h @@ -40,6 +40,10 @@ class AbstractAssemblyStack virtual std::string const* sourceMapping(std::string const& _contractName) const = 0; virtual std::string const* runtimeSourceMapping(std::string const& _contractName) const = 0; + virtual Json ethdebug(std::string const& _contractName) const = 0; + virtual Json ethdebugRuntime(std::string const& _contractName) const = 0; + virtual Json ethdebug() const = 0; + virtual Json assemblyJSON(std::string const& _contractName) const = 0; virtual std::string assemblyString(std::string const& _contractName, StringMap const& _sourceCodes) const = 0; diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index 22bff5415333..ac9f14b15498 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -444,7 +444,7 @@ std::string Assembly::assemblyString( { std::ostringstream tmp; assemblyStream(tmp, _debugInfoSelection, "", _sourceCodes); - return tmp.str(); + return (_debugInfoSelection.ethdebug ? "/// ethdebug: enabled\n" : "") + tmp.str(); } Json Assembly::assemblyJSON(std::map const& _sourceIndices, bool _includeSourceList) const diff --git a/libevmasm/EVMAssemblyStack.cpp b/libevmasm/EVMAssemblyStack.cpp index df4517fc522b..f8b8b4b54d0e 100644 --- a/libevmasm/EVMAssemblyStack.cpp +++ b/libevmasm/EVMAssemblyStack.cpp @@ -103,6 +103,25 @@ std::string const* EVMAssemblyStack::runtimeSourceMapping(std::string const& _co return &m_runtimeSourceMapping; } +Json EVMAssemblyStack::ethdebug(std::string const& _contractName) const +{ + solAssert(_contractName == m_name); + solAssert(m_ethdebug != nullptr); + return *m_ethdebug; +} + +Json EVMAssemblyStack::ethdebugRuntime(std::string const& _contractName) const +{ + solAssert(_contractName == m_name); + solAssert(m_ethdebugRuntime != nullptr); + return *m_ethdebugRuntime; +} + +Json EVMAssemblyStack::ethdebug() const +{ + return {}; +} + Json EVMAssemblyStack::assemblyJSON(std::string const& _contractName) const { solAssert(_contractName == m_name); diff --git a/libevmasm/EVMAssemblyStack.h b/libevmasm/EVMAssemblyStack.h index 55c9fd684ecc..e3888afadc3e 100644 --- a/libevmasm/EVMAssemblyStack.h +++ b/libevmasm/EVMAssemblyStack.h @@ -59,6 +59,10 @@ class EVMAssemblyStack: public AbstractAssemblyStack std::string const* sourceMapping(std::string const& _contractName) const override; std::string const* runtimeSourceMapping(std::string const& _contractName) const override; + Json ethdebug(std::string const& _contractName) const override; + Json ethdebugRuntime(std::string const& _contractName) const override; + Json ethdebug() const override; + Json assemblyJSON(std::string const& _contractName) const override; std::string assemblyString(std::string const& _contractName, StringMap const& _sourceCodes) const override; @@ -87,6 +91,8 @@ class EVMAssemblyStack: public AbstractAssemblyStack langutil::DebugInfoSelection m_debugInfoSelection = langutil::DebugInfoSelection::Default(); std::string m_sourceMapping; std::string m_runtimeSourceMapping; + std::unique_ptr m_ethdebug; + std::unique_ptr m_ethdebugRuntime; }; } // namespace solidity::evmasm diff --git a/liblangutil/DebugInfoSelection.cpp b/liblangutil/DebugInfoSelection.cpp index ad0b615c1c1e..dfd623646e3a 100644 --- a/liblangutil/DebugInfoSelection.cpp +++ b/liblangutil/DebugInfoSelection.cpp @@ -49,6 +49,14 @@ DebugInfoSelection const DebugInfoSelection::Only(bool DebugInfoSelection::* _me return result; } +DebugInfoSelection const DebugInfoSelection::AllExcept(std::vector const& _members) noexcept +{ + DebugInfoSelection result = All(); + for (bool DebugInfoSelection::* member: _members) + result.*member = false; + return result; +} + std::optional DebugInfoSelection::fromString(std::string_view _input) { // TODO: Make more stuff constexpr and make it a static_assert(). @@ -56,7 +64,7 @@ std::optional DebugInfoSelection::fromString(std::string_vie solAssert(componentMap().count("none") == 0, ""); if (_input == "all") - return All(); + return AllExceptExperimental(); if (_input == "none") return None(); @@ -74,7 +82,7 @@ std::optional DebugInfoSelection::fromComponents( for (auto const& component: _componentNames) { if (component == "*") - return (_acceptWildcards ? std::make_optional(DebugInfoSelection::All()) : std::nullopt); + return (_acceptWildcards ? std::make_optional(AllExceptExperimental()) : std::nullopt); if (!selection.enable(component)) return std::nullopt; diff --git a/liblangutil/DebugInfoSelection.h b/liblangutil/DebugInfoSelection.h index 3a9432de6d02..daf4b950f2e9 100644 --- a/liblangutil/DebugInfoSelection.h +++ b/liblangutil/DebugInfoSelection.h @@ -42,7 +42,9 @@ struct DebugInfoSelection static DebugInfoSelection const All(bool _value = true) noexcept; static DebugInfoSelection const None() noexcept { return All(false); } static DebugInfoSelection const Only(bool DebugInfoSelection::* _member) noexcept; - static DebugInfoSelection const Default() noexcept { return All(); } + static DebugInfoSelection const Default() noexcept { return AllExceptExperimental(); } + static DebugInfoSelection const AllExcept(std::vector const& _members) noexcept; + static DebugInfoSelection const AllExceptExperimental() noexcept { return AllExcept({&DebugInfoSelection::ethdebug}); } static std::optional fromString(std::string_view _input); static std::optional fromComponents( @@ -72,13 +74,24 @@ struct DebugInfoSelection {"location", &DebugInfoSelection::location}, {"snippet", &DebugInfoSelection::snippet}, {"ast-id", &DebugInfoSelection::astID}, + {"ethdebug", &DebugInfoSelection::ethdebug}, }; return components; } + std::vector selectedNames() const + { + std::vector result; + for (auto const& component: componentMap()) + if (this->*(component.second)) + result.push_back(component.first); + return result; + } + bool location = false; ///< Include source location. E.g. `@src 3:50:100` bool snippet = false; ///< Include source code snippet next to location. E.g. `@src 3:50:100 "contract C {..."` bool astID = false; ///< Include ID of the Solidity AST node. E.g. `@ast-id 15` + bool ethdebug = false; ///< Include ethdebug related debug information. }; std::ostream& operator<<(std::ostream& _stream, DebugInfoSelection const& _selection); diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index ae2a12c71c32..dd6503ca1fbf 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -120,7 +120,7 @@ std::string IRGenerator::generate( ); }; - Whiskers t(R"( + Whiskers t(R"(/// ethdebug: enabled /// @use-src object "" { code { @@ -164,6 +164,7 @@ std::string IRGenerator::generate( for (VariableDeclaration const* var: ContractType(_contract).immutableVariables()) m_context.registerImmutableVariable(*var); + t("isEthdebugEnabled", m_context.debugInfoSelection().ethdebug); t("CreationObject", IRNames::creationObject(_contract)); t("sourceLocationCommentCreation", dispenseLocationComment(_contract)); t("library", _contract.isLibrary()); diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 2a859ea24517..1791ad45a9d5 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -1181,6 +1181,39 @@ Json CompilerStack::interfaceSymbols(std::string const& _contractName) const return interfaceSymbols; } +Json CompilerStack::ethdebug() const +{ + solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful."); + solAssert(!m_contracts.empty()); + Json result = Json::object(); + result["sources"] = sourceNames(); + return result; +} + +Json CompilerStack::ethdebug(std::string const& _contractName) const +{ + return ethdebug(contract(_contractName), /* runtime */ false); +} + +Json CompilerStack::ethdebugRuntime(std::string const& _contractName) const +{ + return ethdebug(contract(_contractName), /* runtime */ true); +} + +Json CompilerStack::ethdebug(Contract const& _contract, bool _runtime) const +{ + solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful."); + solAssert(_contract.contract); + solUnimplementedAssert(!isExperimentalSolidity()); + if (_runtime) + { + Json result = Json::object(); + return result; + } + Json result = Json::object(); + return result; +} + bytes CompilerStack::cborMetadata(std::string const& _contractName, bool _forIR) const { solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful."); diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index f36eedde0611..2731787a4b88 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -391,6 +391,18 @@ class CompilerStack: public langutil::CharStreamProvider, public evmasm::Abstrac /// @returns a JSON object with the three members ``methods``, ``events``, ``errors``. Each is a map, mapping identifiers (hashes) to function names. Json interfaceSymbols(std::string const& _contractName) const; + /// @returns a JSON representing the ethdebug data of the specified contract. + /// Prerequisite: Successful call to parse or compile. + Json ethdebug(std::string const& _contractName) const override; + + /// @returns a JSON representing the ethdebug data of the specified contract. + /// Prerequisite: Successful call to parse or compile. + Json ethdebugRuntime(std::string const& _contractName) const override; + + /// @returns a JSON representing the top-level ethdebug data (types, etc.). + /// Prerequisite: Successful call to parse or compile. + Json ethdebug() const override; + /// @returns the Contract Metadata matching the pipeline selected using the viaIR setting. std::string const& metadata(std::string const& _contractName) const { return metadata(contract(_contractName)); } @@ -571,6 +583,11 @@ class CompilerStack: public langutil::CharStreamProvider, public evmasm::Abstrac /// This will generate the metadata and store it in the Contract object if it is not present yet. std::string const& metadata(Contract const& _contract) const; + /// @returns the Contract ethdebug data. + /// This will generate the JSON object and store it in the Contract object if it is not present yet. + /// Prerequisite: Successful call to parse or compile. + Json ethdebug(Contract const& _contract, bool _runtime) const; + /// @returns the offset of the entry point of the given function into the list of assembly items /// or zero if it is not found or does not exist. size_t functionEntryPoint( diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 9357310c07e4..520f4d5f1c8f 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -165,7 +165,7 @@ bool hashMatchesContent(std::string const& _hash, std::string const& _content) bool isArtifactRequested(Json const& _outputSelection, std::string const& _artifact, bool _wildcardMatchesExperimental) { - static std::set experimental{"ir", "irAst", "irOptimized", "irOptimizedAst", "yulCFGJson"}; + static std::set experimental{"ir", "irAst", "irOptimized", "irOptimizedAst", "yulCFGJson", "ethdebug"}; for (auto const& selectedArtifactJson: _outputSelection) { std::string const& selectedArtifact = selectedArtifactJson.get(); @@ -173,12 +173,20 @@ bool isArtifactRequested(Json const& _outputSelection, std::string const& _artif _artifact == selectedArtifact || boost::algorithm::starts_with(_artifact, selectedArtifact + ".") ) + { + if (_artifact.find("ethdebug") != std::string::npos) + // only accept exact matches for ethdebug, e.g. evm.bytecode.ethdebug + return selectedArtifact == _artifact; return true; + } else if (selectedArtifact == "*") { // TODO: yulCFGJson is only experimental now, so it should not be matched by "*". if (_artifact == "yulCFGJson") return false; + // TODO: everything ethdebug related is only experimental for now, so it should not be matched by "*". + if (_artifact.find("ethdebug") != std::string::npos) + return false; // "ir", "irOptimized" can only be matched by "*" if activated. if (experimental.count(_artifact) == 0 || _wildcardMatchesExperimental) return true; @@ -237,7 +245,7 @@ bool isArtifactRequested(Json const& _outputSelection, std::string const& _file, std::vector evmObjectComponents(std::string const& _objectKind) { solAssert(_objectKind == "bytecode" || _objectKind == "deployedBytecode", ""); - std::vector components{"", ".object", ".opcodes", ".sourceMap", ".functionDebugData", ".generatedSources", ".linkReferences"}; + std::vector components{"", ".object", ".opcodes", ".sourceMap", ".functionDebugData", ".generatedSources", ".linkReferences", ".ethdebug"}; if (_objectKind == "deployedBytecode") components.push_back(".immutableReferences"); return util::applyMap(components, [&](auto const& _s) { return "evm." + _objectKind + _s; }); @@ -253,7 +261,7 @@ bool isBinaryRequested(Json const& _outputSelection) static std::vector const outputsThatRequireBinaries = std::vector{ "*", "ir", "irAst", "irOptimized", "irOptimizedAst", "yulCFGJson", - "evm.gasEstimates", "evm.legacyAssembly", "evm.assembly" + "evm.gasEstimates", "evm.legacyAssembly", "evm.assembly", "ethdebug" } + evmObjectComponents("bytecode") + evmObjectComponents("deployedBytecode"); for (auto const& fileRequests: _outputSelection) @@ -283,6 +291,21 @@ bool isEvmBytecodeRequested(Json const& _outputSelection) return false; } +/// @returns true if ethdebug was requested. +bool isEthdebugRequested(Json const& _outputSelection) +{ + if (!_outputSelection.is_object()) + return false; + + for (auto const& fileRequests: _outputSelection) + for (auto const& requests: fileRequests) + for (auto const& request: requests) + if (request == "evm.bytecode.ethdebug" || request == "evm.deployedBytecode.ethdebug") + return true; + + return false; +} + /// @returns The set of selected contracts, along with their compiler pipeline configuration, based /// on outputs requested in the JSON. Translates wildcards to the ones understood by CompilerStack. /// Note that as an exception, '*' does not yet match "ir", "irAst", "irOptimized" or "irOptimizedAst". @@ -1152,6 +1175,38 @@ std::variant StandardCompiler::parseI ret.modelCheckerSettings.timeout = modelCheckerSettings["timeout"].get(); } + if ((ret.debugInfoSelection.has_value() && ret.debugInfoSelection->ethdebug) || isEthdebugRequested(ret.outputSelection)) + { + if (ret.language != "Solidity" && ret.language != "Yul") + return formatFatalError(Error::Type::FatalError, "'settings.debug.debugInfo' 'ethdebug' is only supported for languages 'Solidity' and 'Yul'."); + } + + if (isEthdebugRequested(ret.outputSelection)) + { + if (ret.language == "Solidity" && !ret.viaIR) + return formatFatalError(Error::Type::FatalError, "'evm.bytecode.ethdebug' or 'evm.deployedBytecode.ethdebug' can only be selected as output, if 'viaIR' was set."); + + if (!ret.debugInfoSelection.has_value()) + { + ret.debugInfoSelection = DebugInfoSelection::Default(); + ret.debugInfoSelection->enable("ethdebug"); + } + else + { + if (!ret.debugInfoSelection->ethdebug && ret.language == "Solidity") + return formatFatalError(Error::Type::FatalError, "'ethdebug' needs to be enabled in 'settings.debug.debugInfo', if 'evm.bytecode.ethdebug' or 'evm.deployedBytecode.ethdebug' was selected as output."); + } + } + + if ( + ret.debugInfoSelection.has_value() && ret.debugInfoSelection->ethdebug && ret.language == "Solidity" && + !pipelineConfig(ret.outputSelection)[""][""].irCodegen && !isEthdebugRequested(ret.outputSelection) + ) + return formatFatalError(Error::Type::FatalError, "'settings.debug.debugInfo' can only include 'ethdebug', if output 'ir', 'irOptimized', 'evm.bytecode.ethdebug', or 'evm.deployedBytecode.ethdebug' was selected."); + + if (isEthdebugRequested(ret.outputSelection) && (ret.optimiserSettings.runYulOptimiser || isArtifactRequested(ret.outputSelection, "*", "*", "irOptimized", false))) + return formatFatalError(Error::Type::FatalError, "Optimization is not yet supported with ethdebug."); + return {std::move(ret)}; } @@ -1235,6 +1290,8 @@ Json StandardCompiler::importEVMAssembly(StandardCompiler::InputsAndSettings _in creationJSON["functionDebugData"] = formatFunctionDebugData(stack.object(sourceName).functionDebugData); if (evmCreationArtifactRequested("linkReferences")) creationJSON["linkReferences"] = formatLinkReferences(stack.object(sourceName).linkReferences); + if (evmCreationArtifactRequested("ethdebug")) + creationJSON["ethdebug"] = stack.ethdebug(sourceName); evmData["bytecode"] = creationJSON; } @@ -1263,6 +1320,8 @@ Json StandardCompiler::importEVMAssembly(StandardCompiler::InputsAndSettings _in deployedJSON["linkReferences"] = formatLinkReferences(stack.runtimeObject(sourceName).linkReferences); if (evmDeployedArtifactRequested("immutableReferences")) deployedJSON["immutableReferences"] = formatImmutableReferences(stack.runtimeObject(sourceName).immutableReferences); + if (evmDeployedArtifactRequested("ethdebug")) + deployedJSON["ethdebug"] = stack.ethdebugRuntime(sourceName); evmData["deployedBytecode"] = deployedJSON; } @@ -1503,6 +1562,8 @@ Json StandardCompiler::compileSolidity(StandardCompiler::InputsAndSettings _inpu creationJSON["linkReferences"] = formatLinkReferences(compilerStack.object(contractName).linkReferences); if (evmCreationArtifactRequested("generatedSources")) creationJSON["generatedSources"] = compilerStack.generatedSources(contractName, /* _runtime */ false); + if (evmCreationArtifactRequested("ethdebug")) + creationJSON["ethdebug"] = compilerStack.ethdebug(contractName); evmData["bytecode"] = creationJSON; } @@ -1533,6 +1594,8 @@ Json StandardCompiler::compileSolidity(StandardCompiler::InputsAndSettings _inpu deployedJSON["immutableReferences"] = formatImmutableReferences(compilerStack.runtimeObject(contractName).immutableReferences); if (evmDeployedArtifactRequested("generatedSources")) deployedJSON["generatedSources"] = compilerStack.generatedSources(contractName, /* _runtime */ true); + if (evmDeployedArtifactRequested("ethdebug")) + deployedJSON["ethdebug"] = compilerStack.ethdebugRuntime(contractName); evmData["deployedBytecode"] = deployedJSON; } @@ -1546,6 +1609,10 @@ Json StandardCompiler::compileSolidity(StandardCompiler::InputsAndSettings _inpu contractsOutput[file][name] = contractData; } } + + if (isEthdebugRequested(_inputsAndSettings.outputSelection)) + output["ethdebug"] = compilerStack.ethdebug(); + if (!contractsOutput.empty()) output["contracts"] = contractsOutput; @@ -1597,6 +1664,19 @@ Json StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings) return output; } + for (auto const& fileRequests: _inputsAndSettings.outputSelection) + for (auto const& requests: fileRequests) + for (auto const& request: requests) + if (request == "evm.deployedBytecode.ethdebug") + { + output["errors"].emplace_back(formatError( + Error::Type::JSONError, + "general", + "\"evm.deployedBytecode.ethdebug\" cannot be used for Yul." + )); + return output; + } + YulStack stack( _inputsAndSettings.evmVersion, _inputsAndSettings.eofVersion, @@ -1687,6 +1767,8 @@ Json StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings) bytecodeJSON["functionDebugData"] = formatFunctionDebugData(selectedObject.bytecode->functionDebugData); if (evmArtifactRequested(kind, "linkReferences")) bytecodeJSON["linkReferences"] = formatLinkReferences(selectedObject.bytecode->linkReferences); + if (evmArtifactRequested(kind, "ethdebug")) + bytecodeJSON["ethdebug"] = selectedObject.ethdebug; if (isDeployed && evmArtifactRequested(kind, "immutableReferences")) bytecodeJSON["immutableReferences"] = formatImmutableReferences(selectedObject.bytecode->immutableReferences); output["contracts"][sourceName][contractName]["evm"][kind] = bytecodeJSON; @@ -1700,6 +1782,9 @@ Json StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings) if (isArtifactRequested(_inputsAndSettings.outputSelection, sourceName, contractName, "yulCFGJson", wildcardMatchesExperimental)) output["contracts"][sourceName][contractName]["yulCFGJson"] = stack.cfgJson(); + if (isEthdebugRequested(_inputsAndSettings.outputSelection)) + output["ethdebug"] = stack.ethdebug(); + return output; } diff --git a/libyul/YulStack.cpp b/libyul/YulStack.cpp index aa8a328204d2..f58705e9cb9d 100644 --- a/libyul/YulStack.cpp +++ b/libyul/YulStack.cpp @@ -273,6 +273,7 @@ YulStack::assembleWithDeployed(std::optional _deployName) {{m_charStream->name(), 0}} ); } + creationObject.ethdebug["not yet implemented @ MachineAssemblyObject::ethdebug"] = true; if (deployedAssembly) { @@ -368,7 +369,7 @@ std::string YulStack::print() const yulAssert(m_stackState >= Parsed); yulAssert(m_parserResult, ""); yulAssert(m_parserResult->hasCode(), ""); - return m_parserResult->toString( + return (m_debugInfoSelection.ethdebug ? "/// ethdebug: enabled\n" : "") + m_parserResult->toString( m_debugInfoSelection, m_soliditySourceProvider ) + "\n"; @@ -382,6 +383,17 @@ Json YulStack::astJson() const return m_parserResult->toJson(); } +Json YulStack::ethdebug() const +{ + yulAssert(m_parserResult, ""); + yulAssert(m_parserResult->hasCode(), ""); + yulAssert(m_parserResult->analysisInfo, ""); + + Json result = Json::object(); + result["sources"] = Json::array({m_charStream->name()}); + return result; +} + Json YulStack::cfgJson() const { yulAssert(m_parserResult, ""); diff --git a/libyul/YulStack.h b/libyul/YulStack.h index 94688fddcaaf..b745f1b80538 100644 --- a/libyul/YulStack.h +++ b/libyul/YulStack.h @@ -60,6 +60,7 @@ struct MachineAssemblyObject std::shared_ptr bytecode; std::shared_ptr assembly; std::unique_ptr sourceMappings; + Json ethdebug = Json::object(); }; /* @@ -148,6 +149,9 @@ class YulStack: public langutil::CharStreamProvider // return the JSON representation of the YuL CFG (experimental) Json cfgJson() const; + /// @returns a JSON representing the top-level ethdebug data (types, etc.). + Json ethdebug() const; + /// Return the parsed and analyzed object. std::shared_ptr parserResult() const; diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index f2bb4af107bb..d97e56638947 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -151,6 +151,8 @@ static bool needsHumanTargetedStdout(CommandLineOptions const& _options) _options.compiler.outputs.yulCFGJson || _options.compiler.outputs.binary || _options.compiler.outputs.binaryRuntime || + _options.compiler.outputs.ethdebug || + _options.compiler.outputs.ethdebugRuntime || _options.compiler.outputs.metadata || _options.compiler.outputs.natspecUser || _options.compiler.outputs.natspecDev || @@ -551,6 +553,44 @@ void CommandLineInterface::handleGasEstimation(std::string const& _contract) } } +void CommandLineInterface::handleEthdebug() +{ + if (m_options.compiler.outputs.ethdebug || m_options.compiler.outputs.ethdebugRuntime) + { + std::string ethdebug{jsonPrint(removeNullMembers(m_compiler->ethdebug()), m_options.formatting.json)}; + if (!m_options.output.dir.empty()) + createFile("ethdebug.json", ethdebug); + else + sout() << "======= Debug Data (ethdebug/format/info/resources) =======" << std::endl << ethdebug << std::endl; + } +} + +void CommandLineInterface::handleEthdebug(std::string const& _contract) +{ + solAssert(CompilerInputModes.count(m_options.input.mode) == 1); + + if (!(m_options.compiler.outputs.ethdebug || m_options.compiler.outputs.ethdebugRuntime)) + return; + + if (m_options.compiler.outputs.ethdebug) + { + std::string ethdebug{jsonPrint(removeNullMembers(m_compiler->ethdebug(_contract)), m_options.formatting.json)}; + if (!m_options.output.dir.empty()) + createFile(m_compiler->filesystemFriendlyName(_contract) + "_ethdebug.json", ethdebug); + else + sout() << "Debug Data (ethdebug/format/program):" << std::endl << ethdebug << std::endl; + } + + if (m_options.compiler.outputs.ethdebugRuntime) + { + std::string ethdebugRuntime{jsonPrint(removeNullMembers(m_compiler->ethdebugRuntime(_contract)), m_options.formatting.json)}; + if (!m_options.output.dir.empty()) + createFile(m_compiler->filesystemFriendlyName(_contract) + "_ethdebug-runtime.json", ethdebugRuntime); + else + sout() << "Debug Data of the runtime part (ethdebug/format/program):" << std::endl << ethdebugRuntime << std::endl; + } +} + void CommandLineInterface::readInputFiles() { solAssert(!m_standardJsonInput.has_value()); @@ -912,6 +952,8 @@ void CommandLineInterface::compile() m_options.compiler.outputs.opcodes || m_options.compiler.outputs.binary || m_options.compiler.outputs.binaryRuntime || + m_options.compiler.outputs.ethdebug || + m_options.compiler.outputs.ethdebugRuntime || (m_options.compiler.combinedJsonRequests && ( m_options.compiler.combinedJsonRequests->binary || m_options.compiler.combinedJsonRequests->binaryRuntime || @@ -1290,6 +1332,17 @@ void CommandLineInterface::assembleYul(yul::YulStack::Language _language, yul::Y solThrow(CommandLineExecutionError, ""); } + if (m_options.compiler.outputs.ethdebug) + { + Json ethdebugObject = Json::object(); + ethdebugObject["sources"] = m_fileReader.sourceUnits() | ranges::views::keys; + sout() << "======= Debug Data (ethdebug/format/info/resources) =======" << std::endl; + sout() << util::jsonPrint( + ethdebugObject, + m_options.formatting.json + ) << std::endl; + } + for (auto const& [sourceUnitName, yulSource]: m_fileReader.sourceUnits()) { solAssert(_targetMachine == yul::YulStack::Machine::EVM); @@ -1345,6 +1398,14 @@ void CommandLineInterface::assembleYul(yul::YulStack::Language _language, yul::Y m_options.formatting.json ) << std::endl; } + if (m_options.compiler.outputs.ethdebug) + { + sout() << std::endl << "Debug Data (ethdebug/format/program):" << std::endl; + sout() << util::jsonPrint( + object.ethdebug, + m_options.formatting.json + ) << std::endl; + } } } @@ -1357,6 +1418,8 @@ void CommandLineInterface::outputCompilationResults() // do we need AST output? handleAst(); + handleEthdebug(); + CompilerOutputs astOutputSelection; astOutputSelection.astCompactJson = true; if (m_options.compiler.outputs != CompilerOutputs() && m_options.compiler.outputs != astOutputSelection) @@ -1388,6 +1451,7 @@ void CommandLineInterface::outputCompilationResults() handleTransientStorageLayout(contract); handleNatspec(true, contract); handleNatspec(false, contract); + handleEthdebug(contract); } // end of contracts iteration } diff --git a/solc/CommandLineInterface.h b/solc/CommandLineInterface.h index ce30a4d71db7..b8a10c372db2 100644 --- a/solc/CommandLineInterface.h +++ b/solc/CommandLineInterface.h @@ -101,6 +101,7 @@ class CommandLineInterface void handleCombinedJSON(); void handleAst(); + void handleEthdebug(); void handleEVMAssembly(std::string const& _contract); void handleBinary(std::string const& _contract); void handleOpcode(std::string const& _contract); @@ -117,6 +118,7 @@ class CommandLineInterface void handleGasEstimation(std::string const& _contract); void handleStorageLayout(std::string const& _contract); void handleTransientStorageLayout(std::string const& _contract); + void handleEthdebug(std::string const& _contract); /// Tries to read @ m_sourceCodes as a JSONs holding ASTs /// such that they can be imported into the compiler (importASTs()) diff --git a/solc/CommandLineParser.cpp b/solc/CommandLineParser.cpp index 5929144049a2..56be4195dcc8 100644 --- a/solc/CommandLineParser.cpp +++ b/solc/CommandLineParser.cpp @@ -474,6 +474,7 @@ void CommandLineParser::parseOutputSelection() CompilerOutputs::componentName(&CompilerOutputs::astCompactJson), CompilerOutputs::componentName(&CompilerOutputs::asmJson), CompilerOutputs::componentName(&CompilerOutputs::yulCFGJson), + CompilerOutputs::componentName(&CompilerOutputs::ethdebug), }; static std::set const evmAssemblyJsonImportModeOutputs = { CompilerOutputs::componentName(&CompilerOutputs::asm_), @@ -651,7 +652,7 @@ General Information)").c_str(), po::value()->default_value(util::toString(DebugInfoSelection::Default())), ("Debug info components to be included in the produced EVM assembly and Yul code. " "Value can be all, none or a comma-separated list containing one or more of the " - "following components: " + util::joinHumanReadable(DebugInfoSelection::componentMap() | ranges::views::keys) + ".").c_str() + "following components: " + util::joinHumanReadable(DebugInfoSelection::Default().selectedNames()) + ".").c_str() ) ( g_strStopAfter.c_str(), @@ -773,9 +774,23 @@ General Information)").c_str(), (CompilerOutputs::componentName(&CompilerOutputs::transientStorageLayout).c_str(), "Slots, offsets and types of the contract's state variables located in transient storage.") ; if (!_forHelp) // Note: We intentionally keep this undocumented for now. + { outputComponents.add_options() - (CompilerOutputs::componentName(&CompilerOutputs::yulCFGJson).c_str(), "Control Flow Graph (CFG) of Yul code in JSON format.") - ; + ( + CompilerOutputs::componentName(&CompilerOutputs::yulCFGJson).c_str(), + "Control Flow Graph (CFG) of Yul code in JSON format." + ); + outputComponents.add_options() + ( + CompilerOutputs::componentName(&CompilerOutputs::ethdebug).c_str(), + "Ethdebug output of all contracts." + ); + outputComponents.add_options() + ( + CompilerOutputs::componentName(&CompilerOutputs::ethdebugRuntime).c_str(), + "Ethdebug output of the runtime part of all contracts." + ); + } desc.add(outputComponents); po::options_description extraOutput("Extra Output"); @@ -1321,6 +1336,14 @@ void CommandLineParser::processArgs() CommandLineValidationError, "Optimizer can only be used for strict assembly. Use --" + g_strStrictAssembly + "." ); + + if (m_options.compiler.outputs.ethdebug || m_options.compiler.outputs.ethdebugRuntime) + if (!m_options.output.debugInfoSelection.has_value()) + { + m_options.output.debugInfoSelection = DebugInfoSelection::Default(); + m_options.output.debugInfoSelection->enable("ethdebug"); + } + return; } else if (countEnabledOptions({g_strYulDialect, g_strMachine}) >= 1) @@ -1460,6 +1483,64 @@ void CommandLineParser::processArgs() m_options.input.mode == InputMode::CompilerWithASTImport || m_options.input.mode == InputMode::EVMAssemblerJSON ); + + bool incompatibleEthdebugOutputs = + m_options.compiler.outputs.asmJson || m_options.compiler.outputs.irAstJson || m_options.compiler.outputs.irOptimizedAstJson || + m_options.compiler.outputs.irOptimized || m_options.optimizer.optimizeYul || m_options.optimizer.optimizeEvmasm; + + bool incompatibleEthdebugInputs = m_options.input.mode != InputMode::Compiler; + + static std::string enableEthdebugMessage = + "--" + CompilerOutputs::componentName(&CompilerOutputs::ethdebug) + " / --" + CompilerOutputs::componentName(&CompilerOutputs::ethdebugRuntime); + + static std::string incompatibleEthdebugOptimizerMessage = + "--" + g_strOptimize + " / --" + CompilerOutputs::componentName(&CompilerOutputs::irOptimized); + + static std::string enableIrMessage = "--" + CompilerOutputs::componentName(&CompilerOutputs::ir); + + if (m_options.compiler.outputs.ethdebug || m_options.compiler.outputs.ethdebugRuntime) + { + if (!m_options.output.viaIR) + solThrow( + CommandLineValidationError, + enableEthdebugMessage + " output can only be selected, if --via-ir was specified." + ); + + if (incompatibleEthdebugOutputs) + solThrow( + CommandLineValidationError, + enableEthdebugMessage + " output can only be used with " + enableIrMessage + ". Optimization is not yet supported with ethdebug, e.g. no support for " + incompatibleEthdebugOptimizerMessage + " yet." + ); + + if (!m_options.output.debugInfoSelection.has_value()) + { + m_options.output.debugInfoSelection = DebugInfoSelection::Default(); + m_options.output.debugInfoSelection->enable("ethdebug"); + } + else + { + if (!m_options.output.debugInfoSelection->ethdebug) + solThrow( + CommandLineValidationError, + "--debug-info must contain ethdebug, when compiling with " + enableEthdebugMessage + "." + ); + } + } + + if ( + m_options.output.debugInfoSelection.has_value() && m_options.output.debugInfoSelection->ethdebug && + (!(m_options.compiler.outputs.ir || m_options.compiler.outputs.ethdebug || m_options.compiler.outputs.ethdebugRuntime) || incompatibleEthdebugOutputs) + ) + solThrow( + CommandLineValidationError, + "--debug-info ethdebug can only be used with " + enableIrMessage + " and/or " + enableEthdebugMessage + ". Optimization is not yet supported with ethdebug, e.g. no support for " + incompatibleEthdebugOptimizerMessage + " yet." + ); + + if (m_options.output.debugInfoSelection.has_value() && m_options.output.debugInfoSelection->ethdebug && incompatibleEthdebugInputs) + solThrow( + CommandLineValidationError, + "Invalid input mode for --debug-info ethdebug / --ethdebug / --ethdebug-runtime." + ); } void CommandLineParser::parseCombinedJsonOption() diff --git a/solc/CommandLineParser.h b/solc/CommandLineParser.h index 3d187694e2e0..d8141cb4fcf0 100644 --- a/solc/CommandLineParser.h +++ b/solc/CommandLineParser.h @@ -88,6 +88,8 @@ struct CompilerOutputs {"storage-layout", &CompilerOutputs::storageLayout}, {"transient-storage-layout", &CompilerOutputs::transientStorageLayout}, {"yul-cfg-json", &CompilerOutputs::yulCFGJson}, + {"ethdebug", &CompilerOutputs::ethdebug}, + {"ethdebug-runtime", &CompilerOutputs::ethdebugRuntime}, }; return components; } @@ -110,6 +112,8 @@ struct CompilerOutputs bool metadata = false; bool storageLayout = false; bool transientStorageLayout = false; + bool ethdebug = false; + bool ethdebugRuntime = false; }; struct CombinedJsonRequests diff --git a/test/cmdlineTests/ethdebug/args b/test/cmdlineTests/ethdebug/args new file mode 100644 index 000000000000..ac83894b301f --- /dev/null +++ b/test/cmdlineTests/ethdebug/args @@ -0,0 +1 @@ +--ethdebug --via-ir --ir \ No newline at end of file diff --git a/test/cmdlineTests/ethdebug/input.sol b/test/cmdlineTests/ethdebug/input.sol new file mode 100644 index 000000000000..25b9640ca565 --- /dev/null +++ b/test/cmdlineTests/ethdebug/input.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 +pragma solidity >=0.0; + +contract C { + function f() public {} +} + diff --git a/test/cmdlineTests/ethdebug/output b/test/cmdlineTests/ethdebug/output new file mode 100644 index 000000000000..375c5cf900af --- /dev/null +++ b/test/cmdlineTests/ethdebug/output @@ -0,0 +1,121 @@ +======= Debug Data (ethdebug/format/info/resources) ======= +{"sources":["ethdebug/input.sol"]} + +======= ethdebug/input.sol:C ======= +IR: +/// ethdebug: enabled +/// @use-src 0:"ethdebug/input.sol" +object "C_6" { + code { + /// @src 0:60:101 "contract C {..." + mstore(64, memoryguard(128)) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_C_6() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset("C_6_deployed"), datasize("C_6_deployed")) + + return(_1, datasize("C_6_deployed")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 0:60:101 "contract C {..." + function constructor_C_6() { + + /// @src 0:60:101 "contract C {..." + + } + /// @src 0:60:101 "contract C {..." + + } + /// @use-src 0:"ethdebug/input.sol" + object "C_6_deployed" { + code { + /// @src 0:60:101 "contract C {..." + mstore(64, memoryguard(128)) + + if iszero(lt(calldatasize(), 4)) + { + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0x26121ff0 + { + // f() + + external_fun_f_5() + } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function abi_decode_tuple_(headStart, dataEnd) { + if slt(sub(dataEnd, headStart), 0) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function external_fun_f_5() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + fun_f_5() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) + } + + /// @ast-id 5 + /// @src 0:77:99 "function f() public {}" + function fun_f_5() { + + } + /// @src 0:60:101 "contract C {..." + + } + + data ".metadata" hex"" + } + +} + + +Debug Data (ethdebug/format/program): +{} diff --git a/test/cmdlineTests/ethdebug_and_ethdebug_runtime/args b/test/cmdlineTests/ethdebug_and_ethdebug_runtime/args new file mode 100644 index 000000000000..18053bcdac95 --- /dev/null +++ b/test/cmdlineTests/ethdebug_and_ethdebug_runtime/args @@ -0,0 +1 @@ +--ethdebug-runtime --ethdebug --via-ir --ir \ No newline at end of file diff --git a/test/cmdlineTests/ethdebug_and_ethdebug_runtime/input.sol b/test/cmdlineTests/ethdebug_and_ethdebug_runtime/input.sol new file mode 100644 index 000000000000..25b9640ca565 --- /dev/null +++ b/test/cmdlineTests/ethdebug_and_ethdebug_runtime/input.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 +pragma solidity >=0.0; + +contract C { + function f() public {} +} + diff --git a/test/cmdlineTests/ethdebug_and_ethdebug_runtime/output b/test/cmdlineTests/ethdebug_and_ethdebug_runtime/output new file mode 100644 index 000000000000..000f29c4df1a --- /dev/null +++ b/test/cmdlineTests/ethdebug_and_ethdebug_runtime/output @@ -0,0 +1,123 @@ +======= Debug Data (ethdebug/format/info/resources) ======= +{"sources":["ethdebug_and_ethdebug_runtime/input.sol"]} + +======= ethdebug_and_ethdebug_runtime/input.sol:C ======= +IR: +/// ethdebug: enabled +/// @use-src 0:"ethdebug_and_ethdebug_runtime/input.sol" +object "C_6" { + code { + /// @src 0:60:101 "contract C {..." + mstore(64, memoryguard(128)) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_C_6() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset("C_6_deployed"), datasize("C_6_deployed")) + + return(_1, datasize("C_6_deployed")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 0:60:101 "contract C {..." + function constructor_C_6() { + + /// @src 0:60:101 "contract C {..." + + } + /// @src 0:60:101 "contract C {..." + + } + /// @use-src 0:"ethdebug_and_ethdebug_runtime/input.sol" + object "C_6_deployed" { + code { + /// @src 0:60:101 "contract C {..." + mstore(64, memoryguard(128)) + + if iszero(lt(calldatasize(), 4)) + { + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0x26121ff0 + { + // f() + + external_fun_f_5() + } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function abi_decode_tuple_(headStart, dataEnd) { + if slt(sub(dataEnd, headStart), 0) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function external_fun_f_5() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + fun_f_5() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) + } + + /// @ast-id 5 + /// @src 0:77:99 "function f() public {}" + function fun_f_5() { + + } + /// @src 0:60:101 "contract C {..." + + } + + data ".metadata" hex"" + } + +} + + +Debug Data (ethdebug/format/program): +{} +Debug Data of the runtime part (ethdebug/format/program): +{} diff --git a/test/cmdlineTests/ethdebug_enabled_optimization/args b/test/cmdlineTests/ethdebug_enabled_optimization/args new file mode 100644 index 000000000000..6edc3b560136 --- /dev/null +++ b/test/cmdlineTests/ethdebug_enabled_optimization/args @@ -0,0 +1 @@ +--ethdebug --via-ir --optimize --ir-optimized \ No newline at end of file diff --git a/test/cmdlineTests/ethdebug_enabled_optimization/err b/test/cmdlineTests/ethdebug_enabled_optimization/err new file mode 100644 index 000000000000..082f6feee994 --- /dev/null +++ b/test/cmdlineTests/ethdebug_enabled_optimization/err @@ -0,0 +1 @@ +Error: --ethdebug / --ethdebug-runtime output can only be used with --ir. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet. diff --git a/test/cmdlineTests/ethdebug_enabled_optimization/exit b/test/cmdlineTests/ethdebug_enabled_optimization/exit new file mode 100644 index 000000000000..d00491fd7e5b --- /dev/null +++ b/test/cmdlineTests/ethdebug_enabled_optimization/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/ethdebug_enabled_optimization/input.sol b/test/cmdlineTests/ethdebug_enabled_optimization/input.sol new file mode 100644 index 000000000000..25b9640ca565 --- /dev/null +++ b/test/cmdlineTests/ethdebug_enabled_optimization/input.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 +pragma solidity >=0.0; + +contract C { + function f() public {} +} + diff --git a/test/cmdlineTests/ethdebug_runtime/args b/test/cmdlineTests/ethdebug_runtime/args new file mode 100644 index 000000000000..a2193034c8db --- /dev/null +++ b/test/cmdlineTests/ethdebug_runtime/args @@ -0,0 +1 @@ +--ethdebug-runtime --via-ir --ir \ No newline at end of file diff --git a/test/cmdlineTests/ethdebug_runtime/input.sol b/test/cmdlineTests/ethdebug_runtime/input.sol new file mode 100644 index 000000000000..25b9640ca565 --- /dev/null +++ b/test/cmdlineTests/ethdebug_runtime/input.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 +pragma solidity >=0.0; + +contract C { + function f() public {} +} + diff --git a/test/cmdlineTests/ethdebug_runtime/output b/test/cmdlineTests/ethdebug_runtime/output new file mode 100644 index 000000000000..8670e379d4e3 --- /dev/null +++ b/test/cmdlineTests/ethdebug_runtime/output @@ -0,0 +1,121 @@ +======= Debug Data (ethdebug/format/info/resources) ======= +{"sources":["ethdebug_runtime/input.sol"]} + +======= ethdebug_runtime/input.sol:C ======= +IR: +/// ethdebug: enabled +/// @use-src 0:"ethdebug_runtime/input.sol" +object "C_6" { + code { + /// @src 0:60:101 "contract C {..." + mstore(64, memoryguard(128)) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_C_6() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset("C_6_deployed"), datasize("C_6_deployed")) + + return(_1, datasize("C_6_deployed")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 0:60:101 "contract C {..." + function constructor_C_6() { + + /// @src 0:60:101 "contract C {..." + + } + /// @src 0:60:101 "contract C {..." + + } + /// @use-src 0:"ethdebug_runtime/input.sol" + object "C_6_deployed" { + code { + /// @src 0:60:101 "contract C {..." + mstore(64, memoryguard(128)) + + if iszero(lt(calldatasize(), 4)) + { + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0x26121ff0 + { + // f() + + external_fun_f_5() + } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function abi_decode_tuple_(headStart, dataEnd) { + if slt(sub(dataEnd, headStart), 0) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function external_fun_f_5() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + fun_f_5() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) + } + + /// @ast-id 5 + /// @src 0:77:99 "function f() public {}" + function fun_f_5() { + + } + /// @src 0:60:101 "contract C {..." + + } + + data ".metadata" hex"" + } + +} + + +Debug Data of the runtime part (ethdebug/format/program): +{} diff --git a/test/cmdlineTests/standard_output_selection_ethdebug_bytecode/input.json b/test/cmdlineTests/standard_output_selection_ethdebug_bytecode/input.json new file mode 100644 index 000000000000..6ac2691c2085 --- /dev/null +++ b/test/cmdlineTests/standard_output_selection_ethdebug_bytecode/input.json @@ -0,0 +1,24 @@ +{ + "language": "Solidity", + "sources": { + "a.sol": { + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;\ncontract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" + }, + "b.sol": { + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;\ncontract A1 { function b(uint x) public pure { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" + } + }, + "settings": { + "viaIR": true, + "optimizer": { + "enabled": false + }, + "outputSelection": { + "*": { + "*": [ + "evm.bytecode.ethdebug", "ir" + ] + } + } + } +} diff --git a/test/cmdlineTests/standard_output_selection_ethdebug_bytecode/output.json b/test/cmdlineTests/standard_output_selection_ethdebug_bytecode/output.json new file mode 100644 index 000000000000..fabb25ee6720 --- /dev/null +++ b/test/cmdlineTests/standard_output_selection_ethdebug_bytecode/output.json @@ -0,0 +1,730 @@ +{ + "contracts": { + "a.sol": { + "A1": { + "evm": { + "bytecode": { + "ethdebug": {} + } + }, + "ir": "/// ethdebug: enabled +/// @use-src 0:\"a.sol\" +object \"A1_14\" { + code { + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_A1_14() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset(\"A1_14_deployed\"), datasize(\"A1_14_deployed\")) + + return(_1, datasize(\"A1_14_deployed\")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + function constructor_A1_14() { + + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + + } + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + + } + /// @use-src 0:\"a.sol\" + object \"A1_14_deployed\" { + code { + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + + if iszero(lt(calldatasize(), 4)) + { + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0xf0fdf834 + { + // a(uint256) + + external_fun_a_13() + } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { + revert(0, 0) + } + + function cleanup_t_uint256(value) -> cleaned { + cleaned := value + } + + function validator_revert_t_uint256(value) { + if iszero(eq(value, cleanup_t_uint256(value))) { revert(0, 0) } + } + + function abi_decode_t_uint256(offset, end) -> value { + value := calldataload(offset) + validator_revert_t_uint256(value) + } + + function abi_decode_tuple_t_uint256(headStart, dataEnd) -> value0 { + if slt(sub(dataEnd, headStart), 32) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + { + + let offset := 0 + + value0 := abi_decode_t_uint256(add(headStart, offset), dataEnd) + } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function external_fun_a_13() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + let param_0 := abi_decode_tuple_t_uint256(4, calldatasize()) + fun_a_13(param_0) + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) + } + + function cleanup_t_rational_0_by_1(value) -> cleaned { + cleaned := value + } + + function identity(value) -> ret { + ret := value + } + + function convert_t_rational_0_by_1_to_t_uint256(value) -> converted { + converted := cleanup_t_uint256(identity(cleanup_t_rational_0_by_1(value))) + } + + function panic_error_0x01() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x01) + revert(0, 0x24) + } + + function assert_helper(condition) { + if iszero(condition) { panic_error_0x01() } + } + + /// @ast-id 13 + /// @src 0:72:121 \"function a(uint x) public pure { assert(x > 0); }\" + function fun_a_13(var_x_3) { + + /// @src 0:112:113 \"x\" + let _1 := var_x_3 + let expr_7 := _1 + /// @src 0:116:117 \"0\" + let expr_8 := 0x00 + /// @src 0:112:117 \"x > 0\" + let expr_9 := gt(cleanup_t_uint256(expr_7), convert_t_rational_0_by_1_to_t_uint256(expr_8)) + /// @src 0:105:118 \"assert(x > 0)\" + assert_helper(expr_9) + + } + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + + } + + data \".metadata\" hex\"\" + } + +} + +" + }, + "A2": { + "evm": { + "bytecode": { + "ethdebug": {} + } + }, + "ir": "/// ethdebug: enabled +/// @use-src 0:\"a.sol\" +object \"A2_27\" { + code { + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_A2_27() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset(\"A2_27_deployed\"), datasize(\"A2_27_deployed\")) + + return(_1, datasize(\"A2_27_deployed\")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + function constructor_A2_27() { + + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + + } + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + + } + /// @use-src 0:\"a.sol\" + object \"A2_27_deployed\" { + code { + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + + if iszero(lt(calldatasize(), 4)) + { + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0xf0fdf834 + { + // a(uint256) + + external_fun_a_26() + } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { + revert(0, 0) + } + + function cleanup_t_uint256(value) -> cleaned { + cleaned := value + } + + function validator_revert_t_uint256(value) { + if iszero(eq(value, cleanup_t_uint256(value))) { revert(0, 0) } + } + + function abi_decode_t_uint256(offset, end) -> value { + value := calldataload(offset) + validator_revert_t_uint256(value) + } + + function abi_decode_tuple_t_uint256(headStart, dataEnd) -> value0 { + if slt(sub(dataEnd, headStart), 32) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + { + + let offset := 0 + + value0 := abi_decode_t_uint256(add(headStart, offset), dataEnd) + } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function external_fun_a_26() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + let param_0 := abi_decode_tuple_t_uint256(4, calldatasize()) + fun_a_26(param_0) + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) + } + + function cleanup_t_rational_0_by_1(value) -> cleaned { + cleaned := value + } + + function identity(value) -> ret { + ret := value + } + + function convert_t_rational_0_by_1_to_t_uint256(value) -> converted { + converted := cleanup_t_uint256(identity(cleanup_t_rational_0_by_1(value))) + } + + function panic_error_0x01() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x01) + revert(0, 0x24) + } + + function assert_helper(condition) { + if iszero(condition) { panic_error_0x01() } + } + + /// @ast-id 26 + /// @src 0:138:187 \"function a(uint x) public pure { assert(x > 0); }\" + function fun_a_26(var_x_16) { + + /// @src 0:178:179 \"x\" + let _1 := var_x_16 + let expr_20 := _1 + /// @src 0:182:183 \"0\" + let expr_21 := 0x00 + /// @src 0:178:183 \"x > 0\" + let expr_22 := gt(cleanup_t_uint256(expr_20), convert_t_rational_0_by_1_to_t_uint256(expr_21)) + /// @src 0:171:184 \"assert(x > 0)\" + assert_helper(expr_22) + + } + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + + } + + data \".metadata\" hex\"\" + } + +} + +" + } + }, + "b.sol": { + "A1": { + "evm": { + "bytecode": { + "ethdebug": {} + } + }, + "ir": "/// ethdebug: enabled +/// @use-src 1:\"b.sol\" +object \"A1_42\" { + code { + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_A1_42() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset(\"A1_42_deployed\"), datasize(\"A1_42_deployed\")) + + return(_1, datasize(\"A1_42_deployed\")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + function constructor_A1_42() { + + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + + } + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + + } + /// @use-src 1:\"b.sol\" + object \"A1_42_deployed\" { + code { + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + + if iszero(lt(calldatasize(), 4)) + { + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0xcd580ff3 + { + // b(uint256) + + external_fun_b_41() + } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { + revert(0, 0) + } + + function cleanup_t_uint256(value) -> cleaned { + cleaned := value + } + + function validator_revert_t_uint256(value) { + if iszero(eq(value, cleanup_t_uint256(value))) { revert(0, 0) } + } + + function abi_decode_t_uint256(offset, end) -> value { + value := calldataload(offset) + validator_revert_t_uint256(value) + } + + function abi_decode_tuple_t_uint256(headStart, dataEnd) -> value0 { + if slt(sub(dataEnd, headStart), 32) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + { + + let offset := 0 + + value0 := abi_decode_t_uint256(add(headStart, offset), dataEnd) + } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function external_fun_b_41() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + let param_0 := abi_decode_tuple_t_uint256(4, calldatasize()) + fun_b_41(param_0) + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) + } + + function cleanup_t_rational_0_by_1(value) -> cleaned { + cleaned := value + } + + function identity(value) -> ret { + ret := value + } + + function convert_t_rational_0_by_1_to_t_uint256(value) -> converted { + converted := cleanup_t_uint256(identity(cleanup_t_rational_0_by_1(value))) + } + + function panic_error_0x01() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x01) + revert(0, 0x24) + } + + function assert_helper(condition) { + if iszero(condition) { panic_error_0x01() } + } + + /// @ast-id 41 + /// @src 1:72:121 \"function b(uint x) public pure { assert(x > 0); }\" + function fun_b_41(var_x_31) { + + /// @src 1:112:113 \"x\" + let _1 := var_x_31 + let expr_35 := _1 + /// @src 1:116:117 \"0\" + let expr_36 := 0x00 + /// @src 1:112:117 \"x > 0\" + let expr_37 := gt(cleanup_t_uint256(expr_35), convert_t_rational_0_by_1_to_t_uint256(expr_36)) + /// @src 1:105:118 \"assert(x > 0)\" + assert_helper(expr_37) + + } + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + + } + + data \".metadata\" hex\"\" + } + +} + +" + }, + "B2": { + "evm": { + "bytecode": { + "ethdebug": {} + } + }, + "ir": "/// ethdebug: enabled +/// @use-src 1:\"b.sol\" +object \"B2_55\" { + code { + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_B2_55() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset(\"B2_55_deployed\"), datasize(\"B2_55_deployed\")) + + return(_1, datasize(\"B2_55_deployed\")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + function constructor_B2_55() { + + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + + } + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + + } + /// @use-src 1:\"b.sol\" + object \"B2_55_deployed\" { + code { + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + + if iszero(lt(calldatasize(), 4)) + { + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0xcd580ff3 + { + // b(uint256) + + external_fun_b_54() + } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { + revert(0, 0) + } + + function cleanup_t_uint256(value) -> cleaned { + cleaned := value + } + + function validator_revert_t_uint256(value) { + if iszero(eq(value, cleanup_t_uint256(value))) { revert(0, 0) } + } + + function abi_decode_t_uint256(offset, end) -> value { + value := calldataload(offset) + validator_revert_t_uint256(value) + } + + function abi_decode_tuple_t_uint256(headStart, dataEnd) -> value0 { + if slt(sub(dataEnd, headStart), 32) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + { + + let offset := 0 + + value0 := abi_decode_t_uint256(add(headStart, offset), dataEnd) + } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function external_fun_b_54() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + let param_0 := abi_decode_tuple_t_uint256(4, calldatasize()) + fun_b_54(param_0) + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) + } + + function cleanup_t_rational_0_by_1(value) -> cleaned { + cleaned := value + } + + function identity(value) -> ret { + ret := value + } + + function convert_t_rational_0_by_1_to_t_uint256(value) -> converted { + converted := cleanup_t_uint256(identity(cleanup_t_rational_0_by_1(value))) + } + + function panic_error_0x01() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x01) + revert(0, 0x24) + } + + function assert_helper(condition) { + if iszero(condition) { panic_error_0x01() } + } + + /// @ast-id 54 + /// @src 1:138:187 \"function b(uint x) public pure { assert(x > 0); }\" + function fun_b_54(var_x_44) { + + /// @src 1:178:179 \"x\" + let _1 := var_x_44 + let expr_48 := _1 + /// @src 1:182:183 \"0\" + let expr_49 := 0x00 + /// @src 1:178:183 \"x > 0\" + let expr_50 := gt(cleanup_t_uint256(expr_48), convert_t_rational_0_by_1_to_t_uint256(expr_49)) + /// @src 1:171:184 \"assert(x > 0)\" + assert_helper(expr_50) + + } + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + + } + + data \".metadata\" hex\"\" + } + +} + +" + } + } + }, + "ethdebug": { + "sources": [ + "a.sol", + "b.sol" + ] + }, + "sources": { + "a.sol": { + "id": 0 + }, + "b.sol": { + "id": 1 + } + } +} diff --git a/test/cmdlineTests/standard_output_selection_ethdebug_bytecode_and_deployedbytecode/input.json b/test/cmdlineTests/standard_output_selection_ethdebug_bytecode_and_deployedbytecode/input.json new file mode 100644 index 000000000000..bb93f57a8256 --- /dev/null +++ b/test/cmdlineTests/standard_output_selection_ethdebug_bytecode_and_deployedbytecode/input.json @@ -0,0 +1,24 @@ +{ + "language": "Solidity", + "sources": { + "a.sol": { + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;\ncontract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" + }, + "b.sol": { + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;\ncontract A1 { function b(uint x) public pure { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" + } + }, + "settings": { + "viaIR": true, + "optimizer": { + "enabled": false + }, + "outputSelection": { + "*": { + "*": [ + "evm.bytecode.ethdebug", "evm.deployedBytecode.ethdebug", "ir" + ] + } + } + } +} diff --git a/test/cmdlineTests/standard_output_selection_ethdebug_bytecode_and_deployedbytecode/output.json b/test/cmdlineTests/standard_output_selection_ethdebug_bytecode_and_deployedbytecode/output.json new file mode 100644 index 000000000000..f8fb2ce274d0 --- /dev/null +++ b/test/cmdlineTests/standard_output_selection_ethdebug_bytecode_and_deployedbytecode/output.json @@ -0,0 +1,742 @@ +{ + "contracts": { + "a.sol": { + "A1": { + "evm": { + "bytecode": { + "ethdebug": {} + }, + "deployedBytecode": { + "ethdebug": {} + } + }, + "ir": "/// ethdebug: enabled +/// @use-src 0:\"a.sol\" +object \"A1_14\" { + code { + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_A1_14() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset(\"A1_14_deployed\"), datasize(\"A1_14_deployed\")) + + return(_1, datasize(\"A1_14_deployed\")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + function constructor_A1_14() { + + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + + } + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + + } + /// @use-src 0:\"a.sol\" + object \"A1_14_deployed\" { + code { + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + + if iszero(lt(calldatasize(), 4)) + { + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0xf0fdf834 + { + // a(uint256) + + external_fun_a_13() + } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { + revert(0, 0) + } + + function cleanup_t_uint256(value) -> cleaned { + cleaned := value + } + + function validator_revert_t_uint256(value) { + if iszero(eq(value, cleanup_t_uint256(value))) { revert(0, 0) } + } + + function abi_decode_t_uint256(offset, end) -> value { + value := calldataload(offset) + validator_revert_t_uint256(value) + } + + function abi_decode_tuple_t_uint256(headStart, dataEnd) -> value0 { + if slt(sub(dataEnd, headStart), 32) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + { + + let offset := 0 + + value0 := abi_decode_t_uint256(add(headStart, offset), dataEnd) + } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function external_fun_a_13() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + let param_0 := abi_decode_tuple_t_uint256(4, calldatasize()) + fun_a_13(param_0) + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) + } + + function cleanup_t_rational_0_by_1(value) -> cleaned { + cleaned := value + } + + function identity(value) -> ret { + ret := value + } + + function convert_t_rational_0_by_1_to_t_uint256(value) -> converted { + converted := cleanup_t_uint256(identity(cleanup_t_rational_0_by_1(value))) + } + + function panic_error_0x01() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x01) + revert(0, 0x24) + } + + function assert_helper(condition) { + if iszero(condition) { panic_error_0x01() } + } + + /// @ast-id 13 + /// @src 0:72:121 \"function a(uint x) public pure { assert(x > 0); }\" + function fun_a_13(var_x_3) { + + /// @src 0:112:113 \"x\" + let _1 := var_x_3 + let expr_7 := _1 + /// @src 0:116:117 \"0\" + let expr_8 := 0x00 + /// @src 0:112:117 \"x > 0\" + let expr_9 := gt(cleanup_t_uint256(expr_7), convert_t_rational_0_by_1_to_t_uint256(expr_8)) + /// @src 0:105:118 \"assert(x > 0)\" + assert_helper(expr_9) + + } + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + + } + + data \".metadata\" hex\"\" + } + +} + +" + }, + "A2": { + "evm": { + "bytecode": { + "ethdebug": {} + }, + "deployedBytecode": { + "ethdebug": {} + } + }, + "ir": "/// ethdebug: enabled +/// @use-src 0:\"a.sol\" +object \"A2_27\" { + code { + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_A2_27() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset(\"A2_27_deployed\"), datasize(\"A2_27_deployed\")) + + return(_1, datasize(\"A2_27_deployed\")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + function constructor_A2_27() { + + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + + } + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + + } + /// @use-src 0:\"a.sol\" + object \"A2_27_deployed\" { + code { + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + + if iszero(lt(calldatasize(), 4)) + { + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0xf0fdf834 + { + // a(uint256) + + external_fun_a_26() + } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { + revert(0, 0) + } + + function cleanup_t_uint256(value) -> cleaned { + cleaned := value + } + + function validator_revert_t_uint256(value) { + if iszero(eq(value, cleanup_t_uint256(value))) { revert(0, 0) } + } + + function abi_decode_t_uint256(offset, end) -> value { + value := calldataload(offset) + validator_revert_t_uint256(value) + } + + function abi_decode_tuple_t_uint256(headStart, dataEnd) -> value0 { + if slt(sub(dataEnd, headStart), 32) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + { + + let offset := 0 + + value0 := abi_decode_t_uint256(add(headStart, offset), dataEnd) + } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function external_fun_a_26() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + let param_0 := abi_decode_tuple_t_uint256(4, calldatasize()) + fun_a_26(param_0) + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) + } + + function cleanup_t_rational_0_by_1(value) -> cleaned { + cleaned := value + } + + function identity(value) -> ret { + ret := value + } + + function convert_t_rational_0_by_1_to_t_uint256(value) -> converted { + converted := cleanup_t_uint256(identity(cleanup_t_rational_0_by_1(value))) + } + + function panic_error_0x01() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x01) + revert(0, 0x24) + } + + function assert_helper(condition) { + if iszero(condition) { panic_error_0x01() } + } + + /// @ast-id 26 + /// @src 0:138:187 \"function a(uint x) public pure { assert(x > 0); }\" + function fun_a_26(var_x_16) { + + /// @src 0:178:179 \"x\" + let _1 := var_x_16 + let expr_20 := _1 + /// @src 0:182:183 \"0\" + let expr_21 := 0x00 + /// @src 0:178:183 \"x > 0\" + let expr_22 := gt(cleanup_t_uint256(expr_20), convert_t_rational_0_by_1_to_t_uint256(expr_21)) + /// @src 0:171:184 \"assert(x > 0)\" + assert_helper(expr_22) + + } + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + + } + + data \".metadata\" hex\"\" + } + +} + +" + } + }, + "b.sol": { + "A1": { + "evm": { + "bytecode": { + "ethdebug": {} + }, + "deployedBytecode": { + "ethdebug": {} + } + }, + "ir": "/// ethdebug: enabled +/// @use-src 1:\"b.sol\" +object \"A1_42\" { + code { + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_A1_42() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset(\"A1_42_deployed\"), datasize(\"A1_42_deployed\")) + + return(_1, datasize(\"A1_42_deployed\")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + function constructor_A1_42() { + + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + + } + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + + } + /// @use-src 1:\"b.sol\" + object \"A1_42_deployed\" { + code { + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + + if iszero(lt(calldatasize(), 4)) + { + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0xcd580ff3 + { + // b(uint256) + + external_fun_b_41() + } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { + revert(0, 0) + } + + function cleanup_t_uint256(value) -> cleaned { + cleaned := value + } + + function validator_revert_t_uint256(value) { + if iszero(eq(value, cleanup_t_uint256(value))) { revert(0, 0) } + } + + function abi_decode_t_uint256(offset, end) -> value { + value := calldataload(offset) + validator_revert_t_uint256(value) + } + + function abi_decode_tuple_t_uint256(headStart, dataEnd) -> value0 { + if slt(sub(dataEnd, headStart), 32) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + { + + let offset := 0 + + value0 := abi_decode_t_uint256(add(headStart, offset), dataEnd) + } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function external_fun_b_41() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + let param_0 := abi_decode_tuple_t_uint256(4, calldatasize()) + fun_b_41(param_0) + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) + } + + function cleanup_t_rational_0_by_1(value) -> cleaned { + cleaned := value + } + + function identity(value) -> ret { + ret := value + } + + function convert_t_rational_0_by_1_to_t_uint256(value) -> converted { + converted := cleanup_t_uint256(identity(cleanup_t_rational_0_by_1(value))) + } + + function panic_error_0x01() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x01) + revert(0, 0x24) + } + + function assert_helper(condition) { + if iszero(condition) { panic_error_0x01() } + } + + /// @ast-id 41 + /// @src 1:72:121 \"function b(uint x) public pure { assert(x > 0); }\" + function fun_b_41(var_x_31) { + + /// @src 1:112:113 \"x\" + let _1 := var_x_31 + let expr_35 := _1 + /// @src 1:116:117 \"0\" + let expr_36 := 0x00 + /// @src 1:112:117 \"x > 0\" + let expr_37 := gt(cleanup_t_uint256(expr_35), convert_t_rational_0_by_1_to_t_uint256(expr_36)) + /// @src 1:105:118 \"assert(x > 0)\" + assert_helper(expr_37) + + } + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + + } + + data \".metadata\" hex\"\" + } + +} + +" + }, + "B2": { + "evm": { + "bytecode": { + "ethdebug": {} + }, + "deployedBytecode": { + "ethdebug": {} + } + }, + "ir": "/// ethdebug: enabled +/// @use-src 1:\"b.sol\" +object \"B2_55\" { + code { + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_B2_55() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset(\"B2_55_deployed\"), datasize(\"B2_55_deployed\")) + + return(_1, datasize(\"B2_55_deployed\")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + function constructor_B2_55() { + + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + + } + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + + } + /// @use-src 1:\"b.sol\" + object \"B2_55_deployed\" { + code { + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + + if iszero(lt(calldatasize(), 4)) + { + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0xcd580ff3 + { + // b(uint256) + + external_fun_b_54() + } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { + revert(0, 0) + } + + function cleanup_t_uint256(value) -> cleaned { + cleaned := value + } + + function validator_revert_t_uint256(value) { + if iszero(eq(value, cleanup_t_uint256(value))) { revert(0, 0) } + } + + function abi_decode_t_uint256(offset, end) -> value { + value := calldataload(offset) + validator_revert_t_uint256(value) + } + + function abi_decode_tuple_t_uint256(headStart, dataEnd) -> value0 { + if slt(sub(dataEnd, headStart), 32) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + { + + let offset := 0 + + value0 := abi_decode_t_uint256(add(headStart, offset), dataEnd) + } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function external_fun_b_54() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + let param_0 := abi_decode_tuple_t_uint256(4, calldatasize()) + fun_b_54(param_0) + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) + } + + function cleanup_t_rational_0_by_1(value) -> cleaned { + cleaned := value + } + + function identity(value) -> ret { + ret := value + } + + function convert_t_rational_0_by_1_to_t_uint256(value) -> converted { + converted := cleanup_t_uint256(identity(cleanup_t_rational_0_by_1(value))) + } + + function panic_error_0x01() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x01) + revert(0, 0x24) + } + + function assert_helper(condition) { + if iszero(condition) { panic_error_0x01() } + } + + /// @ast-id 54 + /// @src 1:138:187 \"function b(uint x) public pure { assert(x > 0); }\" + function fun_b_54(var_x_44) { + + /// @src 1:178:179 \"x\" + let _1 := var_x_44 + let expr_48 := _1 + /// @src 1:182:183 \"0\" + let expr_49 := 0x00 + /// @src 1:178:183 \"x > 0\" + let expr_50 := gt(cleanup_t_uint256(expr_48), convert_t_rational_0_by_1_to_t_uint256(expr_49)) + /// @src 1:171:184 \"assert(x > 0)\" + assert_helper(expr_50) + + } + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + + } + + data \".metadata\" hex\"\" + } + +} + +" + } + } + }, + "ethdebug": { + "sources": [ + "a.sol", + "b.sol" + ] + }, + "sources": { + "a.sol": { + "id": 0 + }, + "b.sol": { + "id": 1 + } + } +} diff --git a/test/cmdlineTests/standard_output_selection_ethdebug_bytecode_and_deployedbytecode_optimizer/input.json b/test/cmdlineTests/standard_output_selection_ethdebug_bytecode_and_deployedbytecode_optimizer/input.json new file mode 100644 index 000000000000..e45f27f3caa8 --- /dev/null +++ b/test/cmdlineTests/standard_output_selection_ethdebug_bytecode_and_deployedbytecode_optimizer/input.json @@ -0,0 +1,24 @@ +{ + "language": "Solidity", + "sources": { + "a.sol": { + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;\ncontract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" + }, + "b.sol": { + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;\ncontract A1 { function b(uint x) public pure { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" + } + }, + "settings": { + "viaIR": true, + "optimizer": { + "enabled": true + }, + "outputSelection": { + "*": { + "*": [ + "evm.bytecode.ethdebug", "evm.deployedBytecode.ethdebug", "irOptimized" + ] + } + } + } +} diff --git a/test/cmdlineTests/standard_output_selection_ethdebug_bytecode_and_deployedbytecode_optimizer/output.json b/test/cmdlineTests/standard_output_selection_ethdebug_bytecode_and_deployedbytecode_optimizer/output.json new file mode 100644 index 000000000000..3ed2f577c7aa --- /dev/null +++ b/test/cmdlineTests/standard_output_selection_ethdebug_bytecode_and_deployedbytecode_optimizer/output.json @@ -0,0 +1,11 @@ +{ + "errors": [ + { + "component": "general", + "formattedMessage": "Optimization is not yet supported with ethdebug.", + "message": "Optimization is not yet supported with ethdebug.", + "severity": "error", + "type": "FatalError" + } + ] +} diff --git a/test/cmdlineTests/standard_output_selection_ethdebug_deployedbytecode/input.json b/test/cmdlineTests/standard_output_selection_ethdebug_deployedbytecode/input.json new file mode 100644 index 000000000000..f8e3ee312e6b --- /dev/null +++ b/test/cmdlineTests/standard_output_selection_ethdebug_deployedbytecode/input.json @@ -0,0 +1,24 @@ +{ + "language": "Solidity", + "sources": { + "a.sol": { + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;\ncontract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" + }, + "b.sol": { + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;\ncontract A1 { function b(uint x) public pure { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" + } + }, + "settings": { + "viaIR": true, + "optimizer": { + "enabled": false + }, + "outputSelection": { + "*": { + "*": [ + "evm.deployedBytecode.ethdebug", "ir" + ] + } + } + } +} diff --git a/test/cmdlineTests/standard_output_selection_ethdebug_deployedbytecode/output.json b/test/cmdlineTests/standard_output_selection_ethdebug_deployedbytecode/output.json new file mode 100644 index 000000000000..4c7b4ed67197 --- /dev/null +++ b/test/cmdlineTests/standard_output_selection_ethdebug_deployedbytecode/output.json @@ -0,0 +1,730 @@ +{ + "contracts": { + "a.sol": { + "A1": { + "evm": { + "deployedBytecode": { + "ethdebug": {} + } + }, + "ir": "/// ethdebug: enabled +/// @use-src 0:\"a.sol\" +object \"A1_14\" { + code { + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_A1_14() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset(\"A1_14_deployed\"), datasize(\"A1_14_deployed\")) + + return(_1, datasize(\"A1_14_deployed\")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + function constructor_A1_14() { + + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + + } + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + + } + /// @use-src 0:\"a.sol\" + object \"A1_14_deployed\" { + code { + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + + if iszero(lt(calldatasize(), 4)) + { + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0xf0fdf834 + { + // a(uint256) + + external_fun_a_13() + } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { + revert(0, 0) + } + + function cleanup_t_uint256(value) -> cleaned { + cleaned := value + } + + function validator_revert_t_uint256(value) { + if iszero(eq(value, cleanup_t_uint256(value))) { revert(0, 0) } + } + + function abi_decode_t_uint256(offset, end) -> value { + value := calldataload(offset) + validator_revert_t_uint256(value) + } + + function abi_decode_tuple_t_uint256(headStart, dataEnd) -> value0 { + if slt(sub(dataEnd, headStart), 32) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + { + + let offset := 0 + + value0 := abi_decode_t_uint256(add(headStart, offset), dataEnd) + } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function external_fun_a_13() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + let param_0 := abi_decode_tuple_t_uint256(4, calldatasize()) + fun_a_13(param_0) + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) + } + + function cleanup_t_rational_0_by_1(value) -> cleaned { + cleaned := value + } + + function identity(value) -> ret { + ret := value + } + + function convert_t_rational_0_by_1_to_t_uint256(value) -> converted { + converted := cleanup_t_uint256(identity(cleanup_t_rational_0_by_1(value))) + } + + function panic_error_0x01() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x01) + revert(0, 0x24) + } + + function assert_helper(condition) { + if iszero(condition) { panic_error_0x01() } + } + + /// @ast-id 13 + /// @src 0:72:121 \"function a(uint x) public pure { assert(x > 0); }\" + function fun_a_13(var_x_3) { + + /// @src 0:112:113 \"x\" + let _1 := var_x_3 + let expr_7 := _1 + /// @src 0:116:117 \"0\" + let expr_8 := 0x00 + /// @src 0:112:117 \"x > 0\" + let expr_9 := gt(cleanup_t_uint256(expr_7), convert_t_rational_0_by_1_to_t_uint256(expr_8)) + /// @src 0:105:118 \"assert(x > 0)\" + assert_helper(expr_9) + + } + /// @src 0:58:123 \"contract A1 { function a(uint x) public pure { assert(x > 0); } }\" + + } + + data \".metadata\" hex\"\" + } + +} + +" + }, + "A2": { + "evm": { + "deployedBytecode": { + "ethdebug": {} + } + }, + "ir": "/// ethdebug: enabled +/// @use-src 0:\"a.sol\" +object \"A2_27\" { + code { + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_A2_27() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset(\"A2_27_deployed\"), datasize(\"A2_27_deployed\")) + + return(_1, datasize(\"A2_27_deployed\")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + function constructor_A2_27() { + + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + + } + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + + } + /// @use-src 0:\"a.sol\" + object \"A2_27_deployed\" { + code { + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + + if iszero(lt(calldatasize(), 4)) + { + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0xf0fdf834 + { + // a(uint256) + + external_fun_a_26() + } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { + revert(0, 0) + } + + function cleanup_t_uint256(value) -> cleaned { + cleaned := value + } + + function validator_revert_t_uint256(value) { + if iszero(eq(value, cleanup_t_uint256(value))) { revert(0, 0) } + } + + function abi_decode_t_uint256(offset, end) -> value { + value := calldataload(offset) + validator_revert_t_uint256(value) + } + + function abi_decode_tuple_t_uint256(headStart, dataEnd) -> value0 { + if slt(sub(dataEnd, headStart), 32) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + { + + let offset := 0 + + value0 := abi_decode_t_uint256(add(headStart, offset), dataEnd) + } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function external_fun_a_26() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + let param_0 := abi_decode_tuple_t_uint256(4, calldatasize()) + fun_a_26(param_0) + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) + } + + function cleanup_t_rational_0_by_1(value) -> cleaned { + cleaned := value + } + + function identity(value) -> ret { + ret := value + } + + function convert_t_rational_0_by_1_to_t_uint256(value) -> converted { + converted := cleanup_t_uint256(identity(cleanup_t_rational_0_by_1(value))) + } + + function panic_error_0x01() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x01) + revert(0, 0x24) + } + + function assert_helper(condition) { + if iszero(condition) { panic_error_0x01() } + } + + /// @ast-id 26 + /// @src 0:138:187 \"function a(uint x) public pure { assert(x > 0); }\" + function fun_a_26(var_x_16) { + + /// @src 0:178:179 \"x\" + let _1 := var_x_16 + let expr_20 := _1 + /// @src 0:182:183 \"0\" + let expr_21 := 0x00 + /// @src 0:178:183 \"x > 0\" + let expr_22 := gt(cleanup_t_uint256(expr_20), convert_t_rational_0_by_1_to_t_uint256(expr_21)) + /// @src 0:171:184 \"assert(x > 0)\" + assert_helper(expr_22) + + } + /// @src 0:124:189 \"contract A2 { function a(uint x) public pure { assert(x > 0); } }\" + + } + + data \".metadata\" hex\"\" + } + +} + +" + } + }, + "b.sol": { + "A1": { + "evm": { + "deployedBytecode": { + "ethdebug": {} + } + }, + "ir": "/// ethdebug: enabled +/// @use-src 1:\"b.sol\" +object \"A1_42\" { + code { + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_A1_42() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset(\"A1_42_deployed\"), datasize(\"A1_42_deployed\")) + + return(_1, datasize(\"A1_42_deployed\")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + function constructor_A1_42() { + + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + + } + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + + } + /// @use-src 1:\"b.sol\" + object \"A1_42_deployed\" { + code { + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + + if iszero(lt(calldatasize(), 4)) + { + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0xcd580ff3 + { + // b(uint256) + + external_fun_b_41() + } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { + revert(0, 0) + } + + function cleanup_t_uint256(value) -> cleaned { + cleaned := value + } + + function validator_revert_t_uint256(value) { + if iszero(eq(value, cleanup_t_uint256(value))) { revert(0, 0) } + } + + function abi_decode_t_uint256(offset, end) -> value { + value := calldataload(offset) + validator_revert_t_uint256(value) + } + + function abi_decode_tuple_t_uint256(headStart, dataEnd) -> value0 { + if slt(sub(dataEnd, headStart), 32) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + { + + let offset := 0 + + value0 := abi_decode_t_uint256(add(headStart, offset), dataEnd) + } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function external_fun_b_41() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + let param_0 := abi_decode_tuple_t_uint256(4, calldatasize()) + fun_b_41(param_0) + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) + } + + function cleanup_t_rational_0_by_1(value) -> cleaned { + cleaned := value + } + + function identity(value) -> ret { + ret := value + } + + function convert_t_rational_0_by_1_to_t_uint256(value) -> converted { + converted := cleanup_t_uint256(identity(cleanup_t_rational_0_by_1(value))) + } + + function panic_error_0x01() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x01) + revert(0, 0x24) + } + + function assert_helper(condition) { + if iszero(condition) { panic_error_0x01() } + } + + /// @ast-id 41 + /// @src 1:72:121 \"function b(uint x) public pure { assert(x > 0); }\" + function fun_b_41(var_x_31) { + + /// @src 1:112:113 \"x\" + let _1 := var_x_31 + let expr_35 := _1 + /// @src 1:116:117 \"0\" + let expr_36 := 0x00 + /// @src 1:112:117 \"x > 0\" + let expr_37 := gt(cleanup_t_uint256(expr_35), convert_t_rational_0_by_1_to_t_uint256(expr_36)) + /// @src 1:105:118 \"assert(x > 0)\" + assert_helper(expr_37) + + } + /// @src 1:58:123 \"contract A1 { function b(uint x) public pure { assert(x > 0); } }\" + + } + + data \".metadata\" hex\"\" + } + +} + +" + }, + "B2": { + "evm": { + "deployedBytecode": { + "ethdebug": {} + } + }, + "ir": "/// ethdebug: enabled +/// @use-src 1:\"b.sol\" +object \"B2_55\" { + code { + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_B2_55() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset(\"B2_55_deployed\"), datasize(\"B2_55_deployed\")) + + return(_1, datasize(\"B2_55_deployed\")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + function constructor_B2_55() { + + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + + } + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + + } + /// @use-src 1:\"b.sol\" + object \"B2_55_deployed\" { + code { + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + mstore(64, memoryguard(128)) + + if iszero(lt(calldatasize(), 4)) + { + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0xcd580ff3 + { + // b(uint256) + + external_fun_b_54() + } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { + revert(0, 0) + } + + function cleanup_t_uint256(value) -> cleaned { + cleaned := value + } + + function validator_revert_t_uint256(value) { + if iszero(eq(value, cleanup_t_uint256(value))) { revert(0, 0) } + } + + function abi_decode_t_uint256(offset, end) -> value { + value := calldataload(offset) + validator_revert_t_uint256(value) + } + + function abi_decode_tuple_t_uint256(headStart, dataEnd) -> value0 { + if slt(sub(dataEnd, headStart), 32) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + { + + let offset := 0 + + value0 := abi_decode_t_uint256(add(headStart, offset), dataEnd) + } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function external_fun_b_54() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + let param_0 := abi_decode_tuple_t_uint256(4, calldatasize()) + fun_b_54(param_0) + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) + } + + function cleanup_t_rational_0_by_1(value) -> cleaned { + cleaned := value + } + + function identity(value) -> ret { + ret := value + } + + function convert_t_rational_0_by_1_to_t_uint256(value) -> converted { + converted := cleanup_t_uint256(identity(cleanup_t_rational_0_by_1(value))) + } + + function panic_error_0x01() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x01) + revert(0, 0x24) + } + + function assert_helper(condition) { + if iszero(condition) { panic_error_0x01() } + } + + /// @ast-id 54 + /// @src 1:138:187 \"function b(uint x) public pure { assert(x > 0); }\" + function fun_b_54(var_x_44) { + + /// @src 1:178:179 \"x\" + let _1 := var_x_44 + let expr_48 := _1 + /// @src 1:182:183 \"0\" + let expr_49 := 0x00 + /// @src 1:178:183 \"x > 0\" + let expr_50 := gt(cleanup_t_uint256(expr_48), convert_t_rational_0_by_1_to_t_uint256(expr_49)) + /// @src 1:171:184 \"assert(x > 0)\" + assert_helper(expr_50) + + } + /// @src 1:124:189 \"contract B2 { function b(uint x) public pure { assert(x > 0); } }\" + + } + + data \".metadata\" hex\"\" + } + +} + +" + } + } + }, + "ethdebug": { + "sources": [ + "a.sol", + "b.sol" + ] + }, + "sources": { + "a.sol": { + "id": 0 + }, + "b.sol": { + "id": 1 + } + } +} diff --git a/test/cmdlineTests/standard_output_selection_ethdebug_irOptimized/input.json b/test/cmdlineTests/standard_output_selection_ethdebug_irOptimized/input.json new file mode 100644 index 000000000000..ab13b27ea6ea --- /dev/null +++ b/test/cmdlineTests/standard_output_selection_ethdebug_irOptimized/input.json @@ -0,0 +1,21 @@ +{ + "language": "Solidity", + "sources": { + "a.sol": { + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;\ncontract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" + }, + "b.sol": { + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;\ncontract A1 { function b(uint x) public pure { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" + } + }, + "settings": { + "viaIR": true, + "outputSelection": { + "*": { + "*": [ + "evm.bytecode.ethdebug", "irOptimized" + ] + } + } + } +} diff --git a/test/cmdlineTests/standard_output_selection_ethdebug_irOptimized/output.json b/test/cmdlineTests/standard_output_selection_ethdebug_irOptimized/output.json new file mode 100644 index 000000000000..3ed2f577c7aa --- /dev/null +++ b/test/cmdlineTests/standard_output_selection_ethdebug_irOptimized/output.json @@ -0,0 +1,11 @@ +{ + "errors": [ + { + "component": "general", + "formattedMessage": "Optimization is not yet supported with ethdebug.", + "message": "Optimization is not yet supported with ethdebug.", + "severity": "error", + "type": "FatalError" + } + ] +} diff --git a/test/cmdlineTests/standard_output_selection_ethdebug_optimize/input.json b/test/cmdlineTests/standard_output_selection_ethdebug_optimize/input.json new file mode 100644 index 000000000000..a8a5cff05d0b --- /dev/null +++ b/test/cmdlineTests/standard_output_selection_ethdebug_optimize/input.json @@ -0,0 +1,24 @@ +{ + "language": "Solidity", + "sources": { + "a.sol": { + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;\ncontract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" + }, + "b.sol": { + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;\ncontract A1 { function b(uint x) public pure { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" + } + }, + "settings": { + "viaIR": true, + "optimizer": { + "enabled": true + }, + "outputSelection": { + "*": { + "*": [ + "evm.bytecode.ethdebug", "ir" + ] + } + } + } +} diff --git a/test/cmdlineTests/standard_output_selection_ethdebug_optimize/output.json b/test/cmdlineTests/standard_output_selection_ethdebug_optimize/output.json new file mode 100644 index 000000000000..3ed2f577c7aa --- /dev/null +++ b/test/cmdlineTests/standard_output_selection_ethdebug_optimize/output.json @@ -0,0 +1,11 @@ +{ + "errors": [ + { + "component": "general", + "formattedMessage": "Optimization is not yet supported with ethdebug.", + "message": "Optimization is not yet supported with ethdebug.", + "severity": "error", + "type": "FatalError" + } + ] +} diff --git a/test/cmdlineTests/standard_yul_ethdebug_bytecode/args b/test/cmdlineTests/standard_yul_ethdebug_bytecode/args new file mode 100644 index 000000000000..18532c5a6d3f --- /dev/null +++ b/test/cmdlineTests/standard_yul_ethdebug_bytecode/args @@ -0,0 +1 @@ +--allow-paths . diff --git a/test/cmdlineTests/standard_yul_ethdebug_bytecode/in.yul b/test/cmdlineTests/standard_yul_ethdebug_bytecode/in.yul new file mode 100644 index 000000000000..920aef8e9dc2 --- /dev/null +++ b/test/cmdlineTests/standard_yul_ethdebug_bytecode/in.yul @@ -0,0 +1,17 @@ +/// @use-src 0:"input.sol" +object "C_6_deployed" { + code { + /// @src 0:60:101 "contract C {..." + mstore(64, 128) + + // f() + fun_f_5() + + /// @src 0:77:99 "function f() public {}" + function fun_f_5() { + sstore(0, 42) + } + /// @src 0:60:101 "contract C {..." + } +} + diff --git a/test/cmdlineTests/standard_yul_ethdebug_bytecode/input.json b/test/cmdlineTests/standard_yul_ethdebug_bytecode/input.json new file mode 100644 index 000000000000..f3346fdd10e3 --- /dev/null +++ b/test/cmdlineTests/standard_yul_ethdebug_bytecode/input.json @@ -0,0 +1,11 @@ +{ + "language": "Yul", + "sources": { + "C": {"urls": ["standard_yul_debug_info_print_all/in.yul"]} + }, + "settings": { + "outputSelection": { + "*": {"*": ["evm.bytecode.ethdebug", "ir"]} + } + } +} diff --git a/test/cmdlineTests/standard_yul_ethdebug_bytecode/output.json b/test/cmdlineTests/standard_yul_ethdebug_bytecode/output.json new file mode 100644 index 000000000000..c9ab1d8f5e73 --- /dev/null +++ b/test/cmdlineTests/standard_yul_ethdebug_bytecode/output.json @@ -0,0 +1,33 @@ +{ + "contracts": { + "C": { + "C_6_deployed": { + "evm": { + "bytecode": { + "ethdebug": { + "not yet implemented @ MachineAssemblyObject::ethdebug": true + } + } + }, + "ir": "/// ethdebug: enabled +/// @use-src 0:\"input.sol\" +object \"C_6_deployed\" { + code { + /// @src 0:60:101 + mstore(64, 128) + fun_f_5() + /// @src 0:77:99 + function fun_f_5() + { sstore(0, 42) } + } +} +" + } + } + }, + "ethdebug": { + "sources": [ + "C" + ] + } +} diff --git a/test/cmdlineTests/standard_yul_ethdebug_deployed_bytecode/args b/test/cmdlineTests/standard_yul_ethdebug_deployed_bytecode/args new file mode 100644 index 000000000000..18532c5a6d3f --- /dev/null +++ b/test/cmdlineTests/standard_yul_ethdebug_deployed_bytecode/args @@ -0,0 +1 @@ +--allow-paths . diff --git a/test/cmdlineTests/standard_yul_ethdebug_deployed_bytecode/in.yul b/test/cmdlineTests/standard_yul_ethdebug_deployed_bytecode/in.yul new file mode 100644 index 000000000000..920aef8e9dc2 --- /dev/null +++ b/test/cmdlineTests/standard_yul_ethdebug_deployed_bytecode/in.yul @@ -0,0 +1,17 @@ +/// @use-src 0:"input.sol" +object "C_6_deployed" { + code { + /// @src 0:60:101 "contract C {..." + mstore(64, 128) + + // f() + fun_f_5() + + /// @src 0:77:99 "function f() public {}" + function fun_f_5() { + sstore(0, 42) + } + /// @src 0:60:101 "contract C {..." + } +} + diff --git a/test/cmdlineTests/standard_yul_ethdebug_deployed_bytecode/input.json b/test/cmdlineTests/standard_yul_ethdebug_deployed_bytecode/input.json new file mode 100644 index 000000000000..e132c654f042 --- /dev/null +++ b/test/cmdlineTests/standard_yul_ethdebug_deployed_bytecode/input.json @@ -0,0 +1,11 @@ +{ + "language": "Yul", + "sources": { + "C": {"urls": ["standard_yul_debug_info_print_all/in.yul"]} + }, + "settings": { + "outputSelection": { + "*": {"*": ["evm.deployedBytecode.ethdebug"]} + } + } +} diff --git a/test/cmdlineTests/standard_yul_ethdebug_deployed_bytecode/output.json b/test/cmdlineTests/standard_yul_ethdebug_deployed_bytecode/output.json new file mode 100644 index 000000000000..1380c31d7c10 --- /dev/null +++ b/test/cmdlineTests/standard_yul_ethdebug_deployed_bytecode/output.json @@ -0,0 +1,11 @@ +{ + "errors": [ + { + "component": "general", + "formattedMessage": "\"evm.deployedBytecode.ethdebug\" cannot be used for Yul.", + "message": "\"evm.deployedBytecode.ethdebug\" cannot be used for Yul.", + "severity": "error", + "type": "JSONError" + } + ] +} diff --git a/test/cmdlineTests/standard_yul_ethdebug_irOptimized/args b/test/cmdlineTests/standard_yul_ethdebug_irOptimized/args new file mode 100644 index 000000000000..18532c5a6d3f --- /dev/null +++ b/test/cmdlineTests/standard_yul_ethdebug_irOptimized/args @@ -0,0 +1 @@ +--allow-paths . diff --git a/test/cmdlineTests/standard_yul_ethdebug_irOptimized/in.yul b/test/cmdlineTests/standard_yul_ethdebug_irOptimized/in.yul new file mode 100644 index 000000000000..920aef8e9dc2 --- /dev/null +++ b/test/cmdlineTests/standard_yul_ethdebug_irOptimized/in.yul @@ -0,0 +1,17 @@ +/// @use-src 0:"input.sol" +object "C_6_deployed" { + code { + /// @src 0:60:101 "contract C {..." + mstore(64, 128) + + // f() + fun_f_5() + + /// @src 0:77:99 "function f() public {}" + function fun_f_5() { + sstore(0, 42) + } + /// @src 0:60:101 "contract C {..." + } +} + diff --git a/test/cmdlineTests/standard_yul_ethdebug_irOptimized/input.json b/test/cmdlineTests/standard_yul_ethdebug_irOptimized/input.json new file mode 100644 index 000000000000..89994857f418 --- /dev/null +++ b/test/cmdlineTests/standard_yul_ethdebug_irOptimized/input.json @@ -0,0 +1,11 @@ +{ + "language": "Yul", + "sources": { + "C": {"urls": ["standard_yul_debug_info_print_all/in.yul"]} + }, + "settings": { + "outputSelection": { + "*": {"*": ["evm.bytecode.ethdebug", "irOptimized"]} + } + } +} diff --git a/test/cmdlineTests/standard_yul_ethdebug_irOptimized/output.json b/test/cmdlineTests/standard_yul_ethdebug_irOptimized/output.json new file mode 100644 index 000000000000..3ed2f577c7aa --- /dev/null +++ b/test/cmdlineTests/standard_yul_ethdebug_irOptimized/output.json @@ -0,0 +1,11 @@ +{ + "errors": [ + { + "component": "general", + "formattedMessage": "Optimization is not yet supported with ethdebug.", + "message": "Optimization is not yet supported with ethdebug.", + "severity": "error", + "type": "FatalError" + } + ] +} diff --git a/test/cmdlineTests/standard_yul_ethdebug_optimize/args b/test/cmdlineTests/standard_yul_ethdebug_optimize/args new file mode 100644 index 000000000000..18532c5a6d3f --- /dev/null +++ b/test/cmdlineTests/standard_yul_ethdebug_optimize/args @@ -0,0 +1 @@ +--allow-paths . diff --git a/test/cmdlineTests/standard_yul_ethdebug_optimize/in.yul b/test/cmdlineTests/standard_yul_ethdebug_optimize/in.yul new file mode 100644 index 000000000000..920aef8e9dc2 --- /dev/null +++ b/test/cmdlineTests/standard_yul_ethdebug_optimize/in.yul @@ -0,0 +1,17 @@ +/// @use-src 0:"input.sol" +object "C_6_deployed" { + code { + /// @src 0:60:101 "contract C {..." + mstore(64, 128) + + // f() + fun_f_5() + + /// @src 0:77:99 "function f() public {}" + function fun_f_5() { + sstore(0, 42) + } + /// @src 0:60:101 "contract C {..." + } +} + diff --git a/test/cmdlineTests/standard_yul_ethdebug_optimize/input.json b/test/cmdlineTests/standard_yul_ethdebug_optimize/input.json new file mode 100644 index 000000000000..fb232f23a1fb --- /dev/null +++ b/test/cmdlineTests/standard_yul_ethdebug_optimize/input.json @@ -0,0 +1,14 @@ +{ + "language": "Yul", + "sources": { + "C": {"urls": ["standard_yul_debug_info_print_all/in.yul"]} + }, + "settings": { + "optimizer": { + "enabled": true + }, + "outputSelection": { + "*": {"*": ["evm.bytecode.ethdebug", "ir"]} + } + } +} diff --git a/test/cmdlineTests/standard_yul_ethdebug_optimize/output.json b/test/cmdlineTests/standard_yul_ethdebug_optimize/output.json new file mode 100644 index 000000000000..3ed2f577c7aa --- /dev/null +++ b/test/cmdlineTests/standard_yul_ethdebug_optimize/output.json @@ -0,0 +1,11 @@ +{ + "errors": [ + { + "component": "general", + "formattedMessage": "Optimization is not yet supported with ethdebug.", + "message": "Optimization is not yet supported with ethdebug.", + "severity": "error", + "type": "FatalError" + } + ] +} diff --git a/test/cmdlineTests/yul_ethdebug/args b/test/cmdlineTests/yul_ethdebug/args new file mode 100644 index 000000000000..715f3fb4848b --- /dev/null +++ b/test/cmdlineTests/yul_ethdebug/args @@ -0,0 +1 @@ +--ethdebug --strict-assembly --optimize --ir-optimized \ No newline at end of file diff --git a/test/cmdlineTests/yul_ethdebug/input.yul b/test/cmdlineTests/yul_ethdebug/input.yul new file mode 100644 index 000000000000..acd0b45f5335 --- /dev/null +++ b/test/cmdlineTests/yul_ethdebug/input.yul @@ -0,0 +1,18 @@ +object "object" { + code { + let a + let b + { + function z() -> y + { y := calldataload(0) } + a := z() + } + { + function z() -> y + { y := calldataload(0x20) } + b := z() + } + sstore(a, b) + } +} + diff --git a/test/cmdlineTests/yul_ethdebug/output b/test/cmdlineTests/yul_ethdebug/output new file mode 100644 index 000000000000..702fe057d532 --- /dev/null +++ b/test/cmdlineTests/yul_ethdebug/output @@ -0,0 +1,18 @@ +======= Debug Data (ethdebug/format/info/resources) ======= +{"sources":["yul_ethdebug/input.yul"]} + +======= yul_ethdebug/input.yul (EVM) ======= + +Pretty printed source: +/// ethdebug: enabled +object "object" { + code { + { + sstore(calldataload(0), calldataload(0x20)) + } + } +} + + +Debug Data (ethdebug/format/program): +{"not yet implemented @ MachineAssemblyObject::ethdebug":true} diff --git a/test/cmdlineTests/yul_ethdebug_runtime/args b/test/cmdlineTests/yul_ethdebug_runtime/args new file mode 100644 index 000000000000..3bedf2d9e437 --- /dev/null +++ b/test/cmdlineTests/yul_ethdebug_runtime/args @@ -0,0 +1 @@ +--ethdebug-runtime --strict-assembly \ No newline at end of file diff --git a/test/cmdlineTests/yul_ethdebug_runtime/err b/test/cmdlineTests/yul_ethdebug_runtime/err new file mode 100644 index 000000000000..ed5894632c43 --- /dev/null +++ b/test/cmdlineTests/yul_ethdebug_runtime/err @@ -0,0 +1 @@ +Error: The following outputs are not supported in assembler mode: --ethdebug-runtime. diff --git a/test/cmdlineTests/yul_ethdebug_runtime/exit b/test/cmdlineTests/yul_ethdebug_runtime/exit new file mode 100644 index 000000000000..d00491fd7e5b --- /dev/null +++ b/test/cmdlineTests/yul_ethdebug_runtime/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/yul_ethdebug_runtime/input.yul b/test/cmdlineTests/yul_ethdebug_runtime/input.yul new file mode 100644 index 000000000000..acd0b45f5335 --- /dev/null +++ b/test/cmdlineTests/yul_ethdebug_runtime/input.yul @@ -0,0 +1,18 @@ +object "object" { + code { + let a + let b + { + function z() -> y + { y := calldataload(0) } + a := z() + } + { + function z() -> y + { y := calldataload(0x20) } + b := z() + } + sstore(a, b) + } +} + diff --git a/test/libsolidity/StandardCompiler.cpp b/test/libsolidity/StandardCompiler.cpp index 4cb0b3c93068..3161eba2a868 100644 --- a/test/libsolidity/StandardCompiler.cpp +++ b/test/libsolidity/StandardCompiler.cpp @@ -33,6 +33,7 @@ #include #include +#include using namespace solidity::evmasm; using namespace std::string_literals; @@ -152,6 +153,147 @@ Json compile(std::string _input) return ret; } +Json createLanguageAndSourcesSection(std::string const& _language, std::map const& _sources, bool _contentNode = true) +{ + Json result = Json::object(); + result["language"] = _language; + result["sources"] = Json::object(); + for (auto const& source: _sources) + { + result["sources"][source.first] = Json::object(); + if (_contentNode) + result["sources"][source.first]["content"] = source.second; + else + result["sources"][source.first] = source.second; + } + return result; +} + +class Code +{ +public: + virtual ~Code() = default; + explicit Code(std::map _code = {}) : m_code(std::move(_code)) {} + [[nodiscard]] virtual Json json() const = 0; +protected: + std::map m_code; +}; + +class SolidityCode: public Code +{ +public: + explicit SolidityCode(std::map _code = { + {"fileA", "pragma solidity >=0.0; contract C { function f() public pure {} }"} + }) : Code(std::move(_code)) {} + [[nodiscard]] Json json() const override + { + return createLanguageAndSourcesSection("Solidity", m_code); + } +}; + +class YulCode: public Code +{ +public: + explicit YulCode(std::map _code = { + {"fileA", "{}"} + }) : Code(std::move(_code)) {} + [[nodiscard]] Json json() const override + { + return createLanguageAndSourcesSection("Yul", m_code); + } +}; + +class EvmAssemblyCode: public Code +{ +public: + explicit EvmAssemblyCode(std::map _code = { + {"fileA", Json::parse(R"( + { + "assemblyJson": { + ".code": [ + { + "begin": 36, + "end": 51, + "name": "PUSH", + "source": 0, + "value": "0" + } + ], + "sourceList": [ + "" + ] + } + } + )")} + }) : Code(std::move(_code)) {} + [[nodiscard]] Json json() const override + { + return createLanguageAndSourcesSection("EVMAssembly", m_code, false); + } +}; + +class SolidityAstCode: public Code +{ +public: + explicit SolidityAstCode(std::map _code = { + {"fileA", Json::parse(R"( + { + "ast": { + "absolutePath": "empty_contract.sol", + "exportedSymbols": { + "test": [ + 1 + ] + }, + "id": 2, + "nodeType": "SourceUnit", + "nodes": [ + { + "abstract": false, + "baseContracts": [], + "canonicalName": "test", + "contractDependencies": [], + "contractKind": "contract", + "fullyImplemented": true, + "id": 1, + "linearizedBaseContracts": [ + 1 + ], + "name": "test", + "nameLocation": "9:4:0", + "nodeType": "ContractDefinition", + "nodes": [], + "scope": 2, + "src": "0:17:0", + "usedErrors": [] + } + ], + "src": "0:124:0" + }, + "id": 0 + } + )")} + }) : Code(std::move(_code)) {} + [[nodiscard]] Json json() const override + { + return createLanguageAndSourcesSection("SolidityAST", m_code); + } +}; + +Json generateStandardJson(bool _viaIr, Json const& _debugInfoSelection, Json const& _outputSelection, Code const& _code = SolidityCode(), bool _advancedOutputSelection = false) +{ + Json result = _code.json(); + result["settings"] = Json::object(); + result["settings"]["viaIR"] = _viaIr; + if (!_debugInfoSelection.empty()) + result["settings"]["debug"]["debugInfo"] = _debugInfoSelection; + if (_advancedOutputSelection) + result["settings"]["outputSelection"] = _outputSelection; + else + result["settings"]["outputSelection"]["*"]["*"] = _outputSelection; + return result; +} + } // end anonymous namespace BOOST_AUTO_TEST_SUITE(StandardCompiler) @@ -1782,6 +1924,372 @@ BOOST_AUTO_TEST_CASE(source_location_of_bare_block) BOOST_REQUIRE(sourceMap.find(sourceRef) != std::string::npos); } +BOOST_AUTO_TEST_CASE(ethdebug_excluded_from_wildcards) +{ + frontend::StandardCompiler compiler; + // excluded from output selection wildcard + Json result = compiler.compile(generateStandardJson(true, {}, Json::array({"*"}))); + BOOST_REQUIRE(result.dump().find("ethdebug") == std::string::npos); + // excluded from debug info selection wildcard + result = compiler.compile(generateStandardJson(true, {"*"}, Json::array({"ir"}))); + BOOST_REQUIRE(result.dump().find("ethdebug") == std::string::npos); + // excluded from both - just in case ;) + result = compiler.compile(generateStandardJson(true, {"*"}, Json::array({"*"}))); + BOOST_REQUIRE(result.dump().find("ethdebug") == std::string::npos); +} + +BOOST_AUTO_TEST_CASE(ethdebug_debug_info_ethdebug) +{ + static std::vector>>> tests{ + { + generateStandardJson(false, Json::array({"ethdebug"}), Json::array({"*"})), + "'settings.debug.debugInfo' can only include 'ethdebug', if output 'ir', 'irOptimized', 'evm.bytecode.ethdebug', or 'evm.deployedBytecode.ethdebug' was selected.", + std::nullopt, + }, + { + generateStandardJson(true, Json::array({"ethdebug"}), Json::array({"*"})), + "'settings.debug.debugInfo' can only include 'ethdebug', if output 'ir', 'irOptimized', 'evm.bytecode.ethdebug', or 'evm.deployedBytecode.ethdebug' was selected.", + std::nullopt, + }, + { + generateStandardJson(false, Json::array({"ethdebug"}), Json::array({"evm.bytecode.ethdebug"})), + "'evm.bytecode.ethdebug' or 'evm.deployedBytecode.ethdebug' can only be selected as output, if 'viaIR' was set.", + std::nullopt, + }, + { + generateStandardJson(false, Json::array({"ethdebug"}), Json::array({"evm.deployedBytecode.ethdebug"})), + "'evm.bytecode.ethdebug' or 'evm.deployedBytecode.ethdebug' can only be selected as output, if 'viaIR' was set.", + std::nullopt, + }, + { + generateStandardJson(false, Json::array({"ethdebug"}), Json::array({"evm.bytecode.ethdebug", "evm.deployedBytecode.ethdebug"})), + "'evm.bytecode.ethdebug' or 'evm.deployedBytecode.ethdebug' can only be selected as output, if 'viaIR' was set.", + std::nullopt, + }, + { + generateStandardJson(false, Json::array({"ethdebug"}), Json::array({"ir"})), + {}, + [](const Json& result) + { + return result.dump().find("/// ethdebug: enabled") != std::string::npos; + } + }, + { + generateStandardJson(false, Json::array({"ethdebug"}), Json::array({"ir"})), + {}, + [](const Json& result) + { + return result.dump().find("/// ethdebug: enabled") != std::string::npos; + } + }, + { + generateStandardJson(true, {}, Json::array({"ir", "evm.bytecode.ethdebug"})), + {}, + [](const Json& result) + { + return result.dump().find("/// ethdebug: enabled") != std::string::npos; + } + }, + { + generateStandardJson(true, {}, Json::array({"ir", "evm.deployedBytecode.ethdebug"})), + {}, + [](const Json& result) + { + return result.dump().find("/// ethdebug: enabled") != std::string::npos; + } + }, + { + generateStandardJson(true, {}, Json::array({"ir", "evm.bytecode.ethdebug", "evm.deployedBytecode.ethdebug"})), + {}, + [](const Json& result) + { + return result.dump().find("/// ethdebug: enabled") != std::string::npos; + } + }, + { + generateStandardJson(true, {}, Json::array({"ir", "evm.bytecode.ethdebug"})), + {}, + [](const Json& result) + { + return result.dump().find("/// ethdebug: enabled") != std::string::npos; + } + }, + { + generateStandardJson(true, {}, Json::array({"ir", "evm.deployedBytecode.ethdebug"})), + {}, + [](const Json& result) + { + return result.dump().find("/// ethdebug: enabled") != std::string::npos; + } + }, + { + generateStandardJson(true, {}, Json::array({"ir", "evm.bytecode.ethdebug", "evm.deployedBytecode.ethdebug"})), + {}, + [](const Json& result) + { + return result.dump().find("/// ethdebug: enabled") != std::string::npos; + } + }, + { + generateStandardJson(true, Json::array({"ethdebug"}), Json::array({"ir"}), YulCode()), + {}, + [](const Json& result) + { + return result.dump().find("/// ethdebug: enabled") != std::string::npos; + } + }, + { + generateStandardJson(true, Json::array({"ethdebug"}), Json::array({"irOptimized"}), YulCode()), + "Optimization is not yet supported with ethdebug.", + {} + }, + { + generateStandardJson(true, Json::array({"ethdebugs"}), Json::array({"ir"}), YulCode()), + "Invalid value in settings.debug.debugInfo.", + {} + }, + { + generateStandardJson( + true, Json::array({"ethdebug"}), { + {"fileA", {{"contractA", Json::array({"evm.deployedBytecode.bin"})}}}, + {"fileB", {{"contractB", Json::array({"evm.bytecode.bin"})}}} + }, + SolidityCode({ + {"fileA", "pragma solidity >=0.0; contract contractA { function f() public pure {} }"}, + {"fileB", "pragma solidity >=0.0; contract contractB { function f() public pure {} }"} + }), true + ), + "'settings.debug.debugInfo' can only include 'ethdebug', if output 'ir', 'irOptimized', 'evm.bytecode.ethdebug', or 'evm.deployedBytecode.ethdebug' was selected.", + std::nullopt, + }, + { + generateStandardJson(true, Json::array({"ethdebug"}), Json::array({"*"}), EvmAssemblyCode()), + "'settings.debug.debugInfo' 'ethdebug' is only supported for languages 'Solidity' and 'Yul'.", + std::nullopt, + }, + { + generateStandardJson(true, Json::array({"ethdebug"}), Json::array({"*"}), SolidityAstCode()), + "'settings.debug.debugInfo' 'ethdebug' is only supported for languages 'Solidity' and 'Yul'.", + std::nullopt, + }, + }; + frontend::StandardCompiler compiler; + for (auto const& test: tests) + { + Json result = compiler.compile(std::get<0>(test)); + BOOST_REQUIRE(!std::get<1>(test).empty() ? result.contains("errors") : result.contains("contracts")); + if (!std::get<1>(test).empty()) + for (auto const& e: result["errors"]) + BOOST_REQUIRE(e["message"] == std::get<1>(test)); + if (std::get<2>(test).has_value()) + BOOST_REQUIRE((*std::get<2>(test))(result)); + } +} + +BOOST_AUTO_TEST_CASE(ethdebug_ethdebug_output) +{ + static std::vector>>> tests{ + { + generateStandardJson(false, Json::array({"ethdebug"}), Json::array({"evm.bytecode.ethdebug"})), + "'evm.bytecode.ethdebug' or 'evm.deployedBytecode.ethdebug' can only be selected as output, if 'viaIR' was set.", + std::nullopt + }, + { + generateStandardJson(false, {}, Json::array({"evm.bytecode.ethdebug"})), + "'evm.bytecode.ethdebug' or 'evm.deployedBytecode.ethdebug' can only be selected as output, if 'viaIR' was set.", + std::nullopt + }, + { + generateStandardJson(false, Json::array({"ethdebug"}), Json::array({"evm.deployedBytecode.ethdebug"})), + "'evm.bytecode.ethdebug' or 'evm.deployedBytecode.ethdebug' can only be selected as output, if 'viaIR' was set.", + std::nullopt + }, + { + generateStandardJson(false, {}, Json::array({"evm.deployedBytecode.ethdebug"})), + "'evm.bytecode.ethdebug' or 'evm.deployedBytecode.ethdebug' can only be selected as output, if 'viaIR' was set.", + std::nullopt + }, + { + generateStandardJson(false, Json::array({"ethdebug"}), Json::array({"evm.bytecode.ethdebug", "evm.deployedBytecode.ethdebug"})), + "'evm.bytecode.ethdebug' or 'evm.deployedBytecode.ethdebug' can only be selected as output, if 'viaIR' was set.", + std::nullopt + }, + { + generateStandardJson(false, {}, Json::array({"evm.bytecode.ethdebug", "evm.deployedBytecode.ethdebug"})), + "'evm.bytecode.ethdebug' or 'evm.deployedBytecode.ethdebug' can only be selected as output, if 'viaIR' was set.", + std::nullopt + }, + { + generateStandardJson(true, Json::array({"location"}), Json::array({"evm.bytecode.ethdebug"})), + "'ethdebug' needs to be enabled in 'settings.debug.debugInfo', if 'evm.bytecode.ethdebug' or 'evm.deployedBytecode.ethdebug' was selected as output.", + std::nullopt + }, + { + generateStandardJson(true, Json::array({"location"}), Json::array({"evm.deployedBytecode.ethdebug"})), + "'ethdebug' needs to be enabled in 'settings.debug.debugInfo', if 'evm.bytecode.ethdebug' or 'evm.deployedBytecode.ethdebug' was selected as output.", + std::nullopt + }, + { + generateStandardJson(true, Json::array({"location"}), Json::array({"evm.bytecode.ethdebug", "evm.deployedBytecode.ethdebug"})), + "'ethdebug' needs to be enabled in 'settings.debug.debugInfo', if 'evm.bytecode.ethdebug' or 'evm.deployedBytecode.ethdebug' was selected as output.", + std::nullopt + }, + { + generateStandardJson(true, Json::array({"ethdebug"}), Json::array({"evm.bytecode.ethdebug"})), + {}, + [](const Json& result) + { + return result.contains("ethdebug") && result["contracts"]["fileA"]["C"]["evm"]["bytecode"].contains("ethdebug"); + } + }, + { + generateStandardJson(true, Json::array({"ethdebug"}), Json::array({"evm.deployedBytecode.ethdebug"})), + {}, + [](const Json& result) + { + return result.contains("ethdebug") && result["contracts"]["fileA"]["C"]["evm"]["deployedBytecode"].contains("ethdebug"); + } + }, + { + generateStandardJson(true, Json::array({"ethdebug"}), Json::array({"evm.bytecode.ethdebug", "evm.deployedBytecode.ethdebug"})), + {}, + [](const Json& result) + { + return result.contains("ethdebug") && result["contracts"]["fileA"]["C"]["evm"]["deployedBytecode"].contains("ethdebug") && + result["contracts"]["fileA"]["C"]["evm"]["bytecode"].contains("ethdebug"); + } + }, + { + generateStandardJson(true, {}, Json::array({"evm.bytecode.ethdebug"})), + {}, + [](const Json& result) + { + return result.contains("ethdebug") && result["contracts"]["fileA"]["C"]["evm"]["bytecode"].contains("ethdebug"); + } + }, + { + generateStandardJson(true, {}, Json::array({"evm.deployedBytecode.ethdebug"})), + {}, + [](const Json& result) + { + return result.contains("ethdebug") && result["contracts"]["fileA"]["C"]["evm"]["deployedBytecode"].contains("ethdebug"); + } + }, + { + generateStandardJson(true, {}, Json::array({"evm.bytecode.ethdebug", "evm.deployedBytecode.ethdebug"})), + {}, + [](const Json& result) + { + return result.contains("ethdebug") && result["contracts"]["fileA"]["C"]["evm"]["deployedBytecode"].contains("ethdebug") && + result["contracts"]["fileA"]["C"]["evm"]["bytecode"].contains("ethdebug"); + } + }, + { + generateStandardJson(true, {}, Json::array({"evm.bytecode.ethdebug", "ir"})), + {}, + [](const Json& result) + { + return result.dump().find("/// ethdebug: enabled") != std::string::npos && result.contains("ethdebug") && result["contracts"]["fileA"]["C"]["evm"]["bytecode"].contains("ethdebug"); + } + }, + { + generateStandardJson(true, {}, Json::array({"evm.deployedBytecode.ethdebug", "ir"})), + {}, + [](const Json& result) + { + return result.dump().find("/// ethdebug: enabled") != std::string::npos && result.contains("ethdebug") && result["contracts"]["fileA"]["C"]["evm"]["deployedBytecode"].contains("ethdebug"); + } + }, + { + generateStandardJson(true, {}, Json::array({"evm.bytecode.ethdebugs"})), + {}, + [](const Json& result) + { + return !result.contains("ethdebug"); + } + }, + { + generateStandardJson(true, {}, Json::array({"evm.deployedBytecode.ethdebugs"})), + {}, + [](const Json& result) + { + return !result.contains("ethdebug"); + } + }, + { + generateStandardJson(true, {}, Json::array({"evm.bytecode.ethdebug", "evm.deployedBytecode.ethdebug", "ir"})), + {}, + [](const Json& result) + { + return result.dump().find("/// ethdebug: enabled") != std::string::npos && result.contains("ethdebug") && result["contracts"]["fileA"]["C"]["evm"]["deployedBytecode"].contains("ethdebug") && + result["contracts"]["fileA"]["C"]["evm"]["bytecode"].contains("ethdebug"); + } + }, + { + generateStandardJson(true, {}, Json::array({"evm.bytecode.ethdebug", "ir"}), YulCode()), + {}, + [](const Json& result) + { + return result.dump().find("/// ethdebug: enabled") != std::string::npos && result["contracts"]["fileA"]["object"]["evm"]["bytecode"].contains("ethdebug"); + } + }, + { + generateStandardJson(true, {}, Json::array({"evm.deployedBytecode.ethdebug", "ir"}), YulCode()), + {"\"evm.deployedBytecode.ethdebug\" cannot be used for Yul."}, + std::nullopt + }, + { + generateStandardJson(true, {}, Json::array({"evm.bytecode.ethdebug", "evm.deployedBytecode.ethdebug", "ir"}), YulCode()), + {"\"evm.deployedBytecode.ethdebug\" cannot be used for Yul."}, + std::nullopt + }, + { + generateStandardJson(true, {}, Json::array({"evm.bytecode"})), + {}, + [](const Json& result) + { + return result.dump().find("ethdebug") == std::string::npos; + } + }, + { + generateStandardJson(true, {}, Json::array({"evm.deployedBytecode"})), + {}, + [](const Json& result) + { + return result.dump().find("ethdebug") == std::string::npos; + } + }, + { + generateStandardJson( + true, {}, { + {"fileA", {{"contractA", Json::array({"evm.deployedBytecode.ethdebug"})}}}, + {"fileB", {{"contractB", Json::array({"evm.bytecode.ethdebug"})}}} + }, + SolidityCode({ + {"fileA", "pragma solidity >=0.0; contract contractA { function f() public pure {} }"}, + {"fileB", "pragma solidity >=0.0; contract contractB { function f() public pure {} }"} + }), true + ), + {}, + [](const Json& result) + { + return result["contracts"]["fileA"]["contractA"]["evm"]["deployedBytecode"].contains("ethdebug") && + result["contracts"]["fileB"]["contractB"]["evm"]["bytecode"].contains("ethdebug") && result.contains("ethdebug"); + } + } + }; + frontend::StandardCompiler compiler; + for (auto const& test: tests) + { + Json result = compiler.compile(std::get<0>(test)); + if (!std::get<1>(test).empty()) + for (auto const& e: result["errors"]) + BOOST_REQUIRE(e["message"] == std::get<1>(test)); + if (std::get<2>(test).has_value()) + BOOST_REQUIRE((*std::get<2>(test))(result)); + } +} + BOOST_AUTO_TEST_SUITE_END() } // end namespaces diff --git a/test/libyul/Common.cpp b/test/libyul/Common.cpp index e64558bd48a9..a9f4c59a74ac 100644 --- a/test/libyul/Common.cpp +++ b/test/libyul/Common.cpp @@ -63,7 +63,7 @@ YulStack yul::test::parseYul( _optimiserSettings.has_value() ? *_optimiserSettings : (CommonOptions::get().optimize ? OptimiserSettings::standard() : OptimiserSettings::minimal()), - DebugInfoSelection::All() + DebugInfoSelection::AllExceptExperimental() ); bool successful = yulStack.parseAndAnalyze(_sourceUnitName, _source); if (!successful) diff --git a/test/libyul/EVMCodeTransformTest.cpp b/test/libyul/EVMCodeTransformTest.cpp index 624a44c3e538..4fff5a22e70d 100644 --- a/test/libyul/EVMCodeTransformTest.cpp +++ b/test/libyul/EVMCodeTransformTest.cpp @@ -58,7 +58,7 @@ TestCase::TestResult EVMCodeTransformTest::run(std::ostream& _stream, std::strin CommonOptions::get().eofVersion(), YulStack::Language::StrictAssembly, settings, - DebugInfoSelection::All() + DebugInfoSelection::AllExceptExperimental() ); yulStack.parseAndAnalyze("", m_source); if (yulStack.hasErrors()) diff --git a/test/libyul/ObjectParser.cpp b/test/libyul/ObjectParser.cpp index 23d8aaa57f8e..446348fa0ba3 100644 --- a/test/libyul/ObjectParser.cpp +++ b/test/libyul/ObjectParser.cpp @@ -151,7 +151,7 @@ BOOST_AUTO_TEST_CASE(to_string) solidity::test::CommonOptions::get().eofVersion(), YulStack::Language::StrictAssembly, solidity::frontend::OptimiserSettings::none(), - DebugInfoSelection::All() + DebugInfoSelection::AllExceptExperimental() ); BOOST_REQUIRE(asmStack.parseAndAnalyze("source", code)); BOOST_CHECK_EQUAL(asmStack.print(), expectation); diff --git a/test/solc/CommandLineInterface.cpp b/test/solc/CommandLineInterface.cpp index 6d19df01b3f8..17166268a656 100644 --- a/test/solc/CommandLineInterface.cpp +++ b/test/solc/CommandLineInterface.cpp @@ -1412,6 +1412,369 @@ BOOST_AUTO_TEST_CASE(cli_include_paths_ambiguous_import) BOOST_REQUIRE(!result.success); } +BOOST_AUTO_TEST_CASE(cli_ethdebug_no_ethdebug_in_help) +{ + OptionsReaderAndMessages result = runCLI({"solc", "--help"}); + BOOST_REQUIRE(result.stdoutContent.find("ethdebug") == std::string::npos); + // just in case + BOOST_REQUIRE(result.stderrContent.find("ethdebug") == std::string::npos); +} + +BOOST_AUTO_TEST_CASE(cli_ethdebug_incompatible_outputs) +{ + TemporaryDirectory tempDir(TEST_CASE_NAME); + createFilesWithParentDirs({tempDir.path() / "input.sol"}); + static std::vector, std::string>> tests{ + { + {"solc", "--ethdebug", "--asm-json", tempDir.path().string() + "/input.sol"}, + "Error: --ethdebug / --ethdebug-runtime output can only be selected, if --via-ir was specified.\n" + }, + { + {"solc", "--via-ir", "--ethdebug", "--asm-json", tempDir.path().string() + "/input.sol"}, + "Error: --ethdebug / --ethdebug-runtime output can only be used with --ir. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n" + }, + { + {"solc", "--via-ir", "--ethdebug", "--optimize", tempDir.path().string() + "/input.sol"}, + "Error: --ethdebug / --ethdebug-runtime output can only be used with --ir. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n" + }, + { + {"solc", "--via-ir", "--ethdebug", "--ir-optimized", tempDir.path().string() + "/input.sol"}, + "Error: --ethdebug / --ethdebug-runtime output can only be used with --ir. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n" + }, + { + {"solc", "--via-ir", "--ethdebug", "--ir-ast-json", tempDir.path().string() + "/input.sol"}, + "Error: --ethdebug / --ethdebug-runtime output can only be used with --ir. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n" + }, + { + {"solc", "--via-ir", "--ethdebug", "--ir-optimized-ast-json", tempDir.path().string() + "/input.sol"}, + "Error: --ethdebug / --ethdebug-runtime output can only be used with --ir. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n" + }, + { + {"solc", "--ethdebug", "--import-asm-json", tempDir.path().string() + "/input.json"}, + "Error: Option --ethdebug is not supported with --import-asm-json.\n" + }, + { + {"solc", "--via-ir", "--ethdebug", "--asm-json", tempDir.path().string() + "/input.sol"}, + "Error: --ethdebug / --ethdebug-runtime output can only be used with --ir. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n" + }, + { + {"solc", "--ethdebug-runtime", "--asm-json", tempDir.path().string() + "/input.sol"}, + "Error: --ethdebug / --ethdebug-runtime output can only be selected, if --via-ir was specified.\n" + }, + { + {"solc", "--via-ir", "--ethdebug-runtime", "--asm-json", tempDir.path().string() + "/input.sol"}, + "Error: --ethdebug / --ethdebug-runtime output can only be used with --ir. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n" + }, + { + {"solc", "--via-ir", "--ethdebug-runtime", "--ir-ast-json", tempDir.path().string() + "/input.sol"}, + "Error: --ethdebug / --ethdebug-runtime output can only be used with --ir. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n" + }, + { + {"solc", "--via-ir", "--ethdebug-runtime", "--ir-optimized-ast-json", tempDir.path().string() + "/input.sol"}, + "Error: --ethdebug / --ethdebug-runtime output can only be used with --ir. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n" + }, + { + {"solc", "--ethdebug-runtime", "--import-asm-json", tempDir.path().string() + "/input.json"}, + "Error: Option --ethdebug-runtime is not supported with --import-asm-json.\n" + }, + { + {"solc", "--via-ir", "--ethdebug-runtime", "--asm-json", tempDir.path().string() + "/input.sol"}, + "Error: --ethdebug / --ethdebug-runtime output can only be used with --ir. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n" + }, + { + {"solc", "--debug-info", "ethdebug", "--asm-json", tempDir.path().string() + "/input.sol"}, + "Error: --debug-info ethdebug can only be used with --ir and/or --ethdebug / --ethdebug-runtime. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n" + }, + { + {"solc", "--debug-info", "ethdebug", "--asm-json", tempDir.path().string() + "/input.sol"}, + "Error: --debug-info ethdebug can only be used with --ir and/or --ethdebug / --ethdebug-runtime. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n" + }, + { + {"solc", "--debug-info", "ethdebug", "--ir-ast-json", tempDir.path().string() + "/input.sol"}, + "Error: --debug-info ethdebug can only be used with --ir and/or --ethdebug / --ethdebug-runtime. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n" + }, + { + {"solc", "--debug-info", "ethdebug", "--ir-optimized-ast-json", tempDir.path().string() + "/input.sol"}, + "Error: --debug-info ethdebug can only be used with --ir and/or --ethdebug / --ethdebug-runtime. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n" + }, + { + {"solc", "--debug-info", "ethdebug", "--import-asm-json", tempDir.path().string() + "/input.json"}, + "Error: Option --debug-info is not supported with --import-asm-json.\n" + }, + { + {"solc", "--debug-info", "ethdebug", "--import-asm-json", tempDir.path().string() + "/input.json"}, + "Error: Option --debug-info is not supported with --import-asm-json.\n" + }, + { + {"solc", "--debug-info", "ethdebug", "--asm-json", tempDir.path().string() + "/input.json"}, + "Error: --debug-info ethdebug can only be used with --ir and/or --ethdebug / --ethdebug-runtime. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n" + } + }; + for (auto const& test: tests) + { + OptionsReaderAndMessages result = runCLI(test.first, ""); + BOOST_REQUIRE(!result.success); + BOOST_CHECK_EQUAL(result.stderrContent, test.second); + } +} + +BOOST_AUTO_TEST_CASE(cli_ethdebug_incompatible_input_modes) +{ + TemporaryDirectory tempDir(TEST_CASE_NAME); + createFilesWithParentDirs({tempDir.path() / "input.json"}); + static std::vector, std::string>> tests{ + { + {"solc", "--ethdebug", "--import-asm-json", tempDir.path().string() + "/input.json"}, + "Error: Option --ethdebug is not supported with --import-asm-json.\n" + }, + { + {"solc", "--ethdebug", "--via-ir", "--import-asm-json", tempDir.path().string() + "/input.json"}, + "Error: The following options are not supported in the current input mode: --via-ir\n" + }, + { + {"solc", "--ethdebug", "--import-asm-json", tempDir.path().string() + "/input.json"}, + "Error: Option --ethdebug is not supported with --import-asm-json.\n" + }, + { + {"solc", "--debug-info", "ethdebug", "--import-asm-json", tempDir.path().string() + "/input.json"}, + "Error: Option --debug-info is not supported with --import-asm-json.\n" + }, + { + {"solc", "--ethdebug", "--import-ast", tempDir.path().string() + "/input.json"}, + "Error: --ethdebug / --ethdebug-runtime output can only be selected, if --via-ir was specified.\n" + }, + { + {"solc", "--ethdebug", "--via-ir", "--import-ast", tempDir.path().string() + "/input.json"}, + "Error: Invalid input mode for --debug-info ethdebug / --ethdebug / --ethdebug-runtime.\n" + }, + { + {"solc", "--debug-info", "ethdebug", "--ir", "--import-ast", tempDir.path().string() + "/input.json"}, + "Error: Invalid input mode for --debug-info ethdebug / --ethdebug / --ethdebug-runtime.\n" + } + }; + for (auto const& test: tests) + { + OptionsReaderAndMessages result = runCLI(test.first, ""); + BOOST_REQUIRE(!result.success); + BOOST_CHECK_EQUAL(result.stderrContent, test.second); + } +} + +BOOST_AUTO_TEST_CASE(cli_ethdebug_debug_info_ethdebug) +{ + TemporaryDirectory tempDir(TEST_CASE_NAME); + createFilesWithParentDirs({tempDir.path() / "input.sol"}, "pragma solidity >=0.0; contract C { function f() public pure {} }"); + createFilesWithParentDirs({tempDir.path() / "input.yul"}, "{}"); + static std::vector, std::vector, std::vector>> tests{ + { + {"solc", "--debug-info", "ethdebug", tempDir.path().string() + "/input.sol"}, + {"Error: --debug-info ethdebug can only be used with --ir and/or --ethdebug / --ethdebug-runtime. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n"}, + {}, + }, + { + {"solc", "--debug-info", "ethdebug", "--ir", tempDir.path().string() + "/input.sol"}, + {}, + {"/// ethdebug: enabled"}, + }, + { + {"solc", "--debug-info", "ethdebug", "--ir-optimized", tempDir.path().string() + "/input.sol"}, + {"Error: --debug-info ethdebug can only be used with --ir and/or --ethdebug / --ethdebug-runtime. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n"}, + {}, + }, + { + {"solc", "--debug-info", "ethdebug", "--optimize", tempDir.path().string() + "/input.sol"}, + {"Error: --debug-info ethdebug can only be used with --ir and/or --ethdebug / --ethdebug-runtime. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n"}, + {}, + }, + { + {"solc", "--debug-info", "ethdebug", "--ethdebug", tempDir.path().string() + "/input.sol"}, + {"Error: --ethdebug / --ethdebug-runtime output can only be selected, if --via-ir was specified.\n"}, + {}, + }, + { + {"solc", "--debug-info", "ethdebug", "--ethdebug", "--via-ir", tempDir.path().string() + "/input.sol"}, + {}, + {"======= Debug Data (ethdebug/format/info/resources) =======", "Debug Data (ethdebug/format/program):"}, + }, + { + {"solc", "--debug-info", "ethdebug", "--ethdebug-runtime", "--via-ir", tempDir.path().string() + "/input.sol"}, + {}, + {"======= Debug Data (ethdebug/format/info/resources) =======", "Debug Data of the runtime part (ethdebug/format/program):"}, + }, + { + {"solc", "--debug-info", "ethdebug", "--strict-assembly", tempDir.path().string() + "/input.yul"}, + {}, + {"/// ethdebug: enabled", "Pretty printed source", "Binary representation", "Text representation"}, + }, + { + {"solc", "--ethdebug", "--strict-assembly", tempDir.path().string() + "/input.yul"}, + {}, + {"======= Debug Data (ethdebug/format/info/resources) =======", "Debug Data (ethdebug/format/program):"}, + }, + { + {"solc", "--ethdebug-runtime", "--strict-assembly", tempDir.path().string() + "/input.yul"}, + {"Error: The following outputs are not supported in assembler mode: --ethdebug-runtime.\n"}, + {}, + }, + { + {"solc", "--ethdebug", "--ethdebug-runtime", "--strict-assembly", tempDir.path().string() + "/input.yul"}, + {"Error: The following outputs are not supported in assembler mode: --ethdebug-runtime.\n"}, + {}, + }, + { + {"solc", "--debug-info", "ethdebug", "--ethdebug", tempDir.path().string() + "/input.sol"}, + {"Error: --ethdebug / --ethdebug-runtime output can only be selected, if --via-ir was specified.\n"}, + {}, + }, + { + {"solc", "--debug-info", "ethdebug", "--ethdebug-runtime", tempDir.path().string() + "/input.sol"}, + {"Error: --ethdebug / --ethdebug-runtime output can only be selected, if --via-ir was specified.\n"}, + {}, + }, + { + {"solc", "--debug-info", "ethdebug", "--ethdebug", "--ethdebug-runtime", tempDir.path().string() + "/input.sol"}, + {"Error: --ethdebug / --ethdebug-runtime output can only be selected, if --via-ir was specified.\n"}, + {}, + }, + { + {"solc", "--debug-info", "ethdebug", "--ethdebug", "--ethdebug-runtime", "--via-ir", tempDir.path().string() + "/input.sol"}, + {}, + {"======= Debug Data (ethdebug/format/info/resources) =======", "Debug Data (ethdebug/format/program):", "Debug Data of the runtime part (ethdebug/format/program):"}, + }, + { + {"solc", "--debug-info", "location", "--ethdebug", "--via-ir", tempDir.path().string() + "/input.sol"}, + {"Error: --debug-info must contain ethdebug, when compiling with --ethdebug / --ethdebug-runtime.\n"}, + {}, + }, + { + {"solc", "--debug-info", "location", "--ethdebug-runtime", "--via-ir", tempDir.path().string() + "/input.sol"}, + {"Error: --debug-info must contain ethdebug, when compiling with --ethdebug / --ethdebug-runtime.\n"}, + {}, + }, + { + {"solc", "--debug-info", "location", "--ethdebug", "--ethdebug-runtime", "--via-ir", tempDir.path().string() + "/input.sol"}, + {"Error: --debug-info must contain ethdebug, when compiling with --ethdebug / --ethdebug-runtime.\n"}, + {}, + }, + { + {"solc", "--debug-info", "all", "--ethdebug", "--via-ir", tempDir.path().string() + "/input.sol"}, + {"Error: --debug-info must contain ethdebug, when compiling with --ethdebug / --ethdebug-runtime.\n"}, + {}, + }, + { + {"solc", "--debug-info", "all", "--ethdebug-runtime", "--via-ir", tempDir.path().string() + "/input.sol"}, + {"Error: --debug-info must contain ethdebug, when compiling with --ethdebug / --ethdebug-runtime.\n"}, + {}, + }, + { + {"solc", "--debug-info", "all", "--ethdebug", "--ethdebug-runtime", "--via-ir", tempDir.path().string() + "/input.sol"}, + {"Error: --debug-info must contain ethdebug, when compiling with --ethdebug / --ethdebug-runtime.\n"}, + {}, + }, + }; + for (auto const& test: tests) + { + OptionsReaderAndMessages result{runCLI(std::get<0>(test), "")}; + BOOST_REQUIRE(!std::get<1>(test).empty() ? !result.success : result.success); + for (auto const& error : std::get<1>(test)) + BOOST_REQUIRE(result.stderrContent == error); + for (auto const& output : std::get<2>(test)) + BOOST_REQUIRE(result.stdoutContent.find(output) != std::string::npos); + } +} + +BOOST_AUTO_TEST_CASE(cli_ethdebug_ethdebug_output) +{ + TemporaryDirectory tempDir(TEST_CASE_NAME); + createFilesWithParentDirs({tempDir.path() / "input.sol"}, "pragma solidity >=0.0; contract C { function f() public pure {} }"); + static std::vector, std::vector, std::vector>> tests{ + { + {"solc", "--ethdebug", tempDir.path().string() + "/input.sol"}, + {"Error: --ethdebug / --ethdebug-runtime output can only be selected, if --via-ir was specified.\n"}, + {}, + }, + { + {"solc", "--ethdebug", "--ethdebug-runtime", tempDir.path().string() + "/input.sol"}, + {"Error: --ethdebug / --ethdebug-runtime output can only be selected, if --via-ir was specified.\n"}, + {}, + }, + { + {"solc", "--ethdebug-runtime", tempDir.path().string() + "/input.sol"}, + {"Error: --ethdebug / --ethdebug-runtime output can only be selected, if --via-ir was specified.\n"}, + {}, + }, + { + {"solc", "--ethdebug", "--via-ir", tempDir.path().string() + "/input.sol"}, + {}, + {"======= Debug Data (ethdebug/format/info/resources) =======", "Debug Data (ethdebug/format/program)"}, + }, + { + {"solc", "--ethdebug-runtime", "--via-ir", tempDir.path().string() + "/input.sol"}, + {}, + {"======= Debug Data (ethdebug/format/info/resources) =======", "Debug Data of the runtime part (ethdebug/format/program)"}, + }, + { + {"solc", "--ethdebug", "--ethdebug-runtime", "--via-ir", tempDir.path().string() + "/input.sol"}, + {}, + {"======= Debug Data (ethdebug/format/info/resources) =======", "Debug Data (ethdebug/format/program)", "Debug Data of the runtime part (ethdebug/format/program)"}, + }, + { + {"solc", "--ethdebug", "--via-ir", "--ir", tempDir.path().string() + "/input.sol"}, + {}, + {"======= Debug Data (ethdebug/format/info/resources) =======", "Debug Data (ethdebug/format/program)", "/// ethdebug: enabled"}, + }, + { + {"solc", "--ethdebug-runtime", "--via-ir", "--ir", tempDir.path().string() + "/input.sol"}, + {}, + {"======= Debug Data (ethdebug/format/info/resources) =======", "Debug Data of the runtime part (ethdebug/format/program)", "/// ethdebug: enabled"}, + }, + { + {"solc", "--ethdebug", "--ethdebug-runtime", "--via-ir", "--ir", tempDir.path().string() + "/input.sol"}, + {}, + {"======= Debug Data (ethdebug/format/info/resources) =======", "Debug Data (ethdebug/format/program)", "Debug Data of the runtime part (ethdebug/format/program)", "/// ethdebug: enabled"}, + }, + { + {"solc", "--ethdebug", "--via-ir", "--ir-optimized", tempDir.path().string() + "/input.sol"}, + {"Error: --ethdebug / --ethdebug-runtime output can only be used with --ir. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n"}, + {}, + }, + { + {"solc", "--ethdebug-runtime", "--via-ir", "--ir-optimized", tempDir.path().string() + "/input.sol"}, + {"Error: --ethdebug / --ethdebug-runtime output can only be used with --ir. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n"}, + {}, + }, + { + {"solc", "--ethdebug", "--ethdebug-runtime", "--via-ir", "--ir-optimized", tempDir.path().string() + "/input.sol"}, + {"Error: --ethdebug / --ethdebug-runtime output can only be used with --ir. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n"}, + {}, + }, + { + {"solc", "--ethdebug", "--via-ir", "--ir-optimized", "--optimize", tempDir.path().string() + "/input.sol"}, + {"Error: --ethdebug / --ethdebug-runtime output can only be used with --ir. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n"}, + {}, + }, + { + {"solc", "--ethdebug-runtime", "--via-ir", "--ir-optimized", "--optimize", tempDir.path().string() + "/input.sol"}, + {"Error: --ethdebug / --ethdebug-runtime output can only be used with --ir. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n"}, + {}, + }, + { + {"solc", "--ethdebug", "--ethdebug-runtime", "--via-ir", "--ir-optimized", "--optimize", tempDir.path().string() + "/input.sol"}, + {"Error: --ethdebug / --ethdebug-runtime output can only be used with --ir. Optimization is not yet supported with ethdebug, e.g. no support for --optimize / --ir-optimized yet.\n"}, + {}, + }, + }; + for (auto const& test: tests) + { + OptionsReaderAndMessages result{runCLI(std::get<0>(test), "")}; + BOOST_REQUIRE(!std::get<1>(test).empty() ? !result.success : result.success); + for (auto const& error : std::get<1>(test)) + BOOST_REQUIRE(result.stderrContent == error); + for (auto const& output : std::get<2>(test)) + BOOST_REQUIRE(result.stdoutContent.find(output) != std::string::npos); + } +} + BOOST_AUTO_TEST_SUITE_END() } // namespace solidity::frontend::test diff --git a/test/solc/CommandLineParser.cpp b/test/solc/CommandLineParser.cpp index 227b1b9213d8..85eeaebe31a8 100644 --- a/test/solc/CommandLineParser.cpp +++ b/test/solc/CommandLineParser.cpp @@ -628,6 +628,43 @@ BOOST_AUTO_TEST_CASE(invalid_optimizer_sequence_without_optimize) } } +BOOST_AUTO_TEST_CASE(ethdebug) +{ + CommandLineOptions commandLineOptions = parseCommandLine({"solc", "contract.sol", "--debug-info", "ethdebug", "--ethdebug", "--via-ir"}); + BOOST_CHECK_EQUAL(commandLineOptions.compiler.outputs.ethdebug, true); + BOOST_CHECK_EQUAL(commandLineOptions.compiler.outputs.ethdebugRuntime, false); + BOOST_CHECK_EQUAL(commandLineOptions.output.debugInfoSelection.has_value(), true); + BOOST_CHECK_EQUAL(commandLineOptions.output.debugInfoSelection->ethdebug, true); + commandLineOptions = parseCommandLine({"solc", "contract.sol", "--debug-info", "ethdebug", "--ethdebug-runtime", "--via-ir"}); + BOOST_CHECK_EQUAL(commandLineOptions.compiler.outputs.ethdebug, false); + BOOST_CHECK_EQUAL(commandLineOptions.compiler.outputs.ethdebugRuntime, true); + BOOST_CHECK_EQUAL(commandLineOptions.output.debugInfoSelection.has_value(), true); + BOOST_CHECK_EQUAL(commandLineOptions.output.debugInfoSelection->ethdebug, true); + commandLineOptions = parseCommandLine({"solc", "contract.sol", "--ethdebug", "--via-ir"}); + BOOST_CHECK_EQUAL(commandLineOptions.compiler.outputs.ethdebug, true); + BOOST_CHECK_EQUAL(commandLineOptions.compiler.outputs.ethdebugRuntime, false); + // debug-info "ethdebug" selected implicitly, + // if compiled with --ethdebug or --ethdebug-runtime and no debug-info was selected. + BOOST_CHECK_EQUAL(commandLineOptions.output.debugInfoSelection.has_value(), true); + BOOST_CHECK_EQUAL(commandLineOptions.output.debugInfoSelection->ethdebug, true); + commandLineOptions = parseCommandLine({"solc", "contract.sol", "--ethdebug-runtime", "--via-ir"}); + BOOST_CHECK_EQUAL(commandLineOptions.compiler.outputs.ethdebug, false); + BOOST_CHECK_EQUAL(commandLineOptions.compiler.outputs.ethdebugRuntime, true); + BOOST_CHECK_EQUAL(commandLineOptions.output.debugInfoSelection.has_value(), true); + BOOST_CHECK_EQUAL(commandLineOptions.output.debugInfoSelection->ethdebug, true); + commandLineOptions = parseCommandLine({"solc", "contract.sol", "--ethdebug", "--ethdebug-runtime", "--via-ir"}); + BOOST_CHECK_EQUAL(commandLineOptions.compiler.outputs.ethdebug, true); + BOOST_CHECK_EQUAL(commandLineOptions.compiler.outputs.ethdebugRuntime, true); + BOOST_CHECK_EQUAL(commandLineOptions.output.debugInfoSelection.has_value(), true); + BOOST_CHECK_EQUAL(commandLineOptions.output.debugInfoSelection->ethdebug, true); + commandLineOptions = parseCommandLine({"solc", "contract.sol", "--debug-info", "ethdebug", "--ir"}); + BOOST_CHECK_EQUAL(commandLineOptions.compiler.outputs.ethdebug, false); + BOOST_CHECK_EQUAL(commandLineOptions.compiler.outputs.ethdebugRuntime, false); + BOOST_CHECK_EQUAL(commandLineOptions.compiler.outputs.ir, true); + BOOST_CHECK_EQUAL(commandLineOptions.output.debugInfoSelection.has_value(), true); + BOOST_CHECK_EQUAL(commandLineOptions.output.debugInfoSelection->ethdebug, true); +} + BOOST_AUTO_TEST_SUITE_END() } // namespace solidity::frontend::test diff --git a/test/tools/ossfuzz/strictasm_assembly_ossfuzz.cpp b/test/tools/ossfuzz/strictasm_assembly_ossfuzz.cpp index 595aecdca3f4..5a9192bc3a05 100644 --- a/test/tools/ossfuzz/strictasm_assembly_ossfuzz.cpp +++ b/test/tools/ossfuzz/strictasm_assembly_ossfuzz.cpp @@ -41,7 +41,7 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size) std::nullopt, YulStack::Language::StrictAssembly, solidity::frontend::OptimiserSettings::minimal(), - langutil::DebugInfoSelection::All() + langutil::DebugInfoSelection::AllExceptExperimental() ); if (!stack.parseAndAnalyze("source", input)) diff --git a/test/tools/ossfuzz/strictasm_diff_ossfuzz.cpp b/test/tools/ossfuzz/strictasm_diff_ossfuzz.cpp index ffeb14702183..a4515b30957a 100644 --- a/test/tools/ossfuzz/strictasm_diff_ossfuzz.cpp +++ b/test/tools/ossfuzz/strictasm_diff_ossfuzz.cpp @@ -65,7 +65,7 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size) std::nullopt, YulStack::Language::StrictAssembly, solidity::frontend::OptimiserSettings::full(), - DebugInfoSelection::All() + DebugInfoSelection::AllExceptExperimental() ); try { diff --git a/test/tools/ossfuzz/strictasm_opt_ossfuzz.cpp b/test/tools/ossfuzz/strictasm_opt_ossfuzz.cpp index 7553c81c0f44..4543804926ee 100644 --- a/test/tools/ossfuzz/strictasm_opt_ossfuzz.cpp +++ b/test/tools/ossfuzz/strictasm_opt_ossfuzz.cpp @@ -42,7 +42,7 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size) std::nullopt, YulStack::Language::StrictAssembly, solidity::frontend::OptimiserSettings::full(), - DebugInfoSelection::All() + DebugInfoSelection::AllExceptExperimental() ); if (!stack.parseAndAnalyze("source", input))