Skip to content

Commit

Permalink
Enable ethdebug debug info and output selection.
Browse files Browse the repository at this point in the history
  • Loading branch information
aarlt committed Aug 30, 2024
1 parent 664ee23 commit 0dd51e5
Show file tree
Hide file tree
Showing 26 changed files with 699 additions and 23 deletions.
4 changes: 4 additions & 0 deletions libevmasm/AbstractAssemblyStack.h
Original file line number Diff line number Diff line change
Expand Up @@ -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, bool _runtime) 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;

Expand Down
2 changes: 1 addition & 1 deletion libevmasm/Assembly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,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<std::string, unsigned> const& _sourceIndices, bool _includeSourceList) const
Expand Down
11 changes: 11 additions & 0 deletions libevmasm/EVMAssemblyStack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,17 @@ std::string const* EVMAssemblyStack::runtimeSourceMapping(std::string const& _co
return &m_runtimeSourceMapping;
}

Json EVMAssemblyStack::ethdebug(std::string const& _contractName, bool _runtime) const
{
solAssert(_contractName == m_name);
return _runtime ? m_runtimeEthdebug : m_ethdebug;
}

Json EVMAssemblyStack::ethdebug() const
{
return {};
}

Json EVMAssemblyStack::assemblyJSON(std::string const& _contractName) const
{
solAssert(_contractName == m_name);
Expand Down
5 changes: 5 additions & 0 deletions libevmasm/EVMAssemblyStack.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ class EVMAssemblyStack: public AbstractAssemblyStack
virtual std::string const* sourceMapping(std::string const& _contractName) const override;
virtual std::string const* runtimeSourceMapping(std::string const& _contractName) const override;

virtual Json ethdebug(std::string const& _contractName, bool _runtime) const override;
virtual Json ethdebug() const override;

virtual Json assemblyJSON(std::string const& _contractName) const override;
virtual std::string assemblyString(std::string const& _contractName, StringMap const& _sourceCodes) const override;

Expand Down Expand Up @@ -85,6 +88,8 @@ class EVMAssemblyStack: public AbstractAssemblyStack
langutil::DebugInfoSelection m_debugInfoSelection = langutil::DebugInfoSelection::Default();
std::string m_sourceMapping;
std::string m_runtimeSourceMapping;
Json m_ethdebug;
Json m_runtimeEthdebug;
};

} // namespace solidity::evmasm
12 changes: 10 additions & 2 deletions liblangutil/DebugInfoSelection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,22 @@ DebugInfoSelection const DebugInfoSelection::Only(bool DebugInfoSelection::* _me
return result;
}

DebugInfoSelection const DebugInfoSelection::Except(std::vector<bool DebugInfoSelection::*> const& _members) noexcept
{
DebugInfoSelection result = All();
for (bool DebugInfoSelection::* member: _members)
result.*member = false;
return result;
}

std::optional<DebugInfoSelection> DebugInfoSelection::fromString(std::string_view _input)
{
// TODO: Make more stuff constexpr and make it a static_assert().
solAssert(componentMap().count("all") == 0, "");
solAssert(componentMap().count("none") == 0, "");

if (_input == "all")
return All();
return ExceptExperimental();
if (_input == "none")
return None();

Expand All @@ -74,7 +82,7 @@ std::optional<DebugInfoSelection> DebugInfoSelection::fromComponents(
for (auto const& component: _componentNames)
{
if (component == "*")
return (_acceptWildcards ? std::make_optional(DebugInfoSelection::All()) : std::nullopt);
return (_acceptWildcards ? std::make_optional(ExceptExperimental()) : std::nullopt);

if (!selection.enable(component))
return std::nullopt;
Expand Down
6 changes: 5 additions & 1 deletion liblangutil/DebugInfoSelection.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 ExceptExperimental(); }
static DebugInfoSelection const Except(std::vector<bool DebugInfoSelection::*> const& _members) noexcept;
static DebugInfoSelection const ExceptExperimental() noexcept { return Except({&DebugInfoSelection::ethdebug}); }

static std::optional<DebugInfoSelection> fromString(std::string_view _input);
static std::optional<DebugInfoSelection> fromComponents(
Expand Down Expand Up @@ -72,13 +74,15 @@ struct DebugInfoSelection
{"location", &DebugInfoSelection::location},
{"snippet", &DebugInfoSelection::snippet},
{"ast-id", &DebugInfoSelection::astID},
{"ethdebug", &DebugInfoSelection::ethdebug},
};
return components;
}

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);
Expand Down
3 changes: 2 additions & 1 deletion libsolidity/codegen/ir/IRGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ std::string IRGenerator::generate(
);
};

Whiskers t(R"(
Whiskers t(R"(<?isEthdebugEnabled>/// ethdebug: enabled</isEthdebugEnabled>
/// @use-src <useSrcMapCreation>
object "<CreationObject>" {
code {
Expand Down Expand Up @@ -167,6 +167,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());
Expand Down
39 changes: 39 additions & 0 deletions libsolidity/interface/CompilerStack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1092,6 +1092,45 @@ Json CompilerStack::interfaceSymbols(std::string const& _contractName) const
return interfaceSymbols;
}

Json CompilerStack::ethdebug() const
{
return m_ethdebug.init(
[&]
{
Json result = Json::object();
result["sources"] = sourceNames();
return result;
});
}

Json CompilerStack::ethdebug(std::string const& _contractName, bool _runtime) const
{
solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful.");
return ethdebug(contract(_contractName), _runtime);
}

Json CompilerStack::ethdebug(Contract const& _contract, bool _runtime) const
{
solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful.");
solAssert(_contract.contract);
solUnimplementedAssert(!isExperimentalSolidity());
if (_runtime)
return _contract.ethdebugRuntime.init(
[&]
{
Json result = Json::object();
result["ethdebug-runtime-data"] = true;
return result;
});
return _contract.ethdebug.init(
[&]
{
Json result = Json::object();
result["ethdebug-data"] = true;
return result;
});
}

bytes CompilerStack::cborMetadata(std::string const& _contractName, bool _forIR) const
{
solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful.");
Expand Down
16 changes: 16 additions & 0 deletions libsolidity/interface/CompilerStack.h
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,14 @@ 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, bool _runtime) 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)); }

Expand Down Expand Up @@ -419,6 +427,8 @@ class CompilerStack: public langutil::CharStreamProvider, public evmasm::Abstrac
util::LazyInit<Json const> devDocumentation;
util::LazyInit<Json const> generatedSources;
util::LazyInit<Json const> runtimeGeneratedSources;
util::LazyInit<Json const> ethdebug;
util::LazyInit<Json const> ethdebugRuntime;
mutable std::optional<std::string const> sourceMapping;
mutable std::optional<std::string const> runtimeSourceMapping;
};
Expand Down Expand Up @@ -527,6 +537,10 @@ 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.
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(
Expand Down Expand Up @@ -567,6 +581,8 @@ class CompilerStack: public langutil::CharStreamProvider, public evmasm::Abstrac
State m_stackState = Empty;
CompilationSourceType m_compilationSourceType = CompilationSourceType::Solidity;
MetadataFormat m_metadataFormat = defaultMetadataFormat();
// top-level ethdebug object containing top-level information (types, sources, etc.)
util::LazyInit<Json const> m_ethdebug;
};

}
Loading

0 comments on commit 0dd51e5

Please sign in to comment.