Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for parsing debug data attributes #14857

Open
wants to merge 3 commits into
base: enable_debug_info_ethdebug
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
16 changes: 12 additions & 4 deletions liblangutil/DebugData.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#pragma once

#include <liblangutil/SourceLocation.h>
#include <libsolutil/JSON.h>
#include <optional>
#include <memory>

Expand All @@ -28,27 +29,32 @@ namespace solidity::langutil
struct DebugData
{
typedef typename std::shared_ptr<DebugData const> ConstPtr;
typedef std::optional<std::vector<std::shared_ptr<Json>>> Attributes;

explicit DebugData(
langutil::SourceLocation _nativeLocation = {},
langutil::SourceLocation _originLocation = {},
std::optional<int64_t> _astID = {}
std::optional<int64_t> _astID = {},
Attributes _attributes = {}
):
nativeLocation(std::move(_nativeLocation)),
originLocation(std::move(_originLocation)),
astID(_astID)
astID(_astID),
attributes(std::move(_attributes))
{}

static DebugData::ConstPtr create(
langutil::SourceLocation _nativeLocation,
langutil::SourceLocation _originLocation = {},
std::optional<int64_t> _astID = {}
std::optional<int64_t> _astID = {},
Attributes _attributes = {}
)
{
return std::make_shared<DebugData>(
std::move(_nativeLocation),
std::move(_originLocation),
_astID
_astID,
std::move(_attributes)
);
}

Expand All @@ -65,6 +71,8 @@ struct DebugData
langutil::SourceLocation originLocation;
/// ID in the (Solidity) source AST.
std::optional<int64_t> astID;
/// Additional debug data attributes.
Attributes attributes;
};

} // namespace solidity::langutil
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