Skip to content
Merged
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) 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;

Expand Down
2 changes: 1 addition & 1 deletion libevmasm/Assembly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::string, unsigned> const& _sourceIndices, bool _includeSourceList) const
Expand Down
19 changes: 19 additions & 0 deletions libevmasm/EVMAssemblyStack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
6 changes: 6 additions & 0 deletions libevmasm/EVMAssemblyStack.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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<Json> m_ethdebug;
std::unique_ptr<Json> m_ethdebugRuntime;
};

} // 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::AllExcept(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 AllExceptExperimental();
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(AllExceptExperimental()) : std::nullopt);

if (!selection.enable(component))
return std::nullopt;
Expand Down
15 changes: 14 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 AllExceptExperimental(); }
static DebugInfoSelection const AllExcept(std::vector<bool DebugInfoSelection::*> const& _members) noexcept;
static DebugInfoSelection const AllExceptExperimental() noexcept { return AllExcept({&DebugInfoSelection::ethdebug}); }

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

std::vector<std::string> selectedNames() const
{
std::vector<std::string> 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);
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 @@ -120,7 +120,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 @@ -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());
Expand Down
33 changes: 33 additions & 0 deletions libsolidity/interface/CompilerStack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.");
Expand Down
17 changes: 17 additions & 0 deletions libsolidity/interface/CompilerStack.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)); }

Expand Down Expand Up @@ -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(
Expand Down
Loading