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

Support for ethdebug types #15327

Draft
wants to merge 2 commits into
base: enable_debug_info_ethdebug
Choose a base branch
from
Draft
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 @@ -437,7 +437,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 @@ -103,6 +103,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 @@ -59,6 +59,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 @@ -87,6 +90,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
79 changes: 78 additions & 1 deletion libsolidity/ast/AST.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,6 @@ std::multimap<std::string, FunctionDefinition const*> const& ContractDefinition:
});
}


TypeNameAnnotation& TypeName::annotation() const
{
return initAnnotation<TypeNameAnnotation>();
Expand Down Expand Up @@ -399,6 +398,13 @@ StructDeclarationAnnotation& StructDefinition::annotation() const
return initAnnotation<StructDeclarationAnnotation>();
}

std::optional<Json> StructDefinition::ethdebug() const
{
Json result = Json::object();
result["kind"] = "struct";
return result;
}

Type const* EnumValue::type() const
{
auto parentDef = dynamic_cast<EnumDefinition const*>(scope());
Expand All @@ -416,6 +422,17 @@ TypeDeclarationAnnotation& EnumDefinition::annotation() const
return initAnnotation<TypeDeclarationAnnotation>();
}

std::optional<Json> EnumDefinition::ethdebug() const
{
Json result = Json::object();
result["kind"] = "enum";
Json values = Json::array();
for (auto const& value: members())
values.push_back(value->name());
result["values"] = values;
return result;
}

bool FunctionDefinition::libraryFunction() const
{
if (auto const* contractDef = dynamic_cast<ContractDefinition const*>(scope()))
Expand Down Expand Up @@ -543,6 +560,57 @@ FunctionDefinition const& FunctionDefinition::resolveVirtual(
return *this; // not reached
}

std::optional<Json> FunctionDefinition::ethdebug() const
{
Json result = Json::object();
if (isOrdinary())
result["kind"] = "function";
else if (isConstructor())
result["kind"] = "constructor";
else if (isFallback())
result["kind"] = "fallback";
else
solAssert(false);

if (!noVisibilitySpecified())
{
switch (visibility())
{
case solidity::frontend::Visibility::Default:
case solidity::frontend::Visibility::Private:
case solidity::frontend::Visibility::Internal:
result["internal"] = true;
break;
case solidity::frontend::Visibility::Public:
case solidity::frontend::Visibility::External:
result["external"] = true;
break;
}
}

Json definition = Json::object();
definition["name"] = name();
result["definition"] = definition;

Json parameters = Json::array();
for (auto const& param: this->parameters())
{
solAssert(param->ethdebug().has_value());
parameters.emplace_back(*param->ethdebug());
}
result["parameters"] = parameters;

Json returns = Json::array();
for (auto const& param: returnParameters())
{
solAssert(param->ethdebug().has_value());
returns.emplace_back(*param->ethdebug());
}
result["returns"] = returns;

return result;
}

Type const* ModifierDefinition::type() const
{
return TypeProvider::modifier(*this);
Expand Down Expand Up @@ -878,6 +946,15 @@ VariableDeclarationAnnotation& VariableDeclaration::annotation() const
return initAnnotation<VariableDeclarationAnnotation>();
}

std::optional<Json> VariableDeclaration::ethdebug() const
{
solAssert(type()->ethdebug().has_value());
Json result = Json::object();
result["name"] = name();
result["type"] = *type()->ethdebug();
return result;
}

StatementAnnotation& Statement::annotation() const
{
return initAnnotation<StatementAnnotation>();
Expand Down
10 changes: 10 additions & 0 deletions libsolidity/ast/AST.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ class ASTNode

virtual bool experimentalSolidityOnly() const { return false; }

virtual std::optional<Json> ethdebug() const { return std::nullopt; }

protected:
size_t const m_id = 0;

Expand Down Expand Up @@ -753,6 +755,8 @@ class StructDefinition: public Declaration, public StructurallyDocumented, publi

StructDeclarationAnnotation& annotation() const override;

std::optional<Json> ethdebug() const override;

private:
std::vector<ASTPointer<VariableDeclaration>> m_members;
};
Expand Down Expand Up @@ -785,6 +789,8 @@ class EnumDefinition: public Declaration, public StructurallyDocumented, public

TypeDeclarationAnnotation& annotation() const override;

std::optional<Json> ethdebug() const override;

private:
std::vector<ASTPointer<EnumValue>> m_members;
};
Expand Down Expand Up @@ -1036,6 +1042,8 @@ class FunctionDefinition: public CallableDeclaration, public StructurallyDocumen

Expression const* experimentalReturnExpression() const { return m_experimentalReturnExpression.get(); }

std::optional<Json> ethdebug() const override;

private:
StateMutability m_stateMutability;
bool m_free;
Expand Down Expand Up @@ -1156,6 +1164,8 @@ class VariableDeclaration: public Declaration, public StructurallyDocumented
ASTPointer<Expression> const& typeExpression() const { return m_typeExpression; }
VariableDeclarationAnnotation& annotation() const override;

std::optional<Json> ethdebug() const override;

protected:
Visibility defaultVisibility() const override { return Visibility::Internal; }

Expand Down
79 changes: 79 additions & 0 deletions libsolidity/ast/Types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,85 @@ std::set<FunctionDefinition const*, ASTNode::CompareByID> Type::operatorDefiniti
return matchingDefinitions;
}

std::optional<Json> Type::ethdebug() const
{
Json result = Json::object();
switch (category())
{
case Category::Address:
result["kind"] = "address";
break;
case Category::Integer:
{
auto integer = dynamic_cast<IntegerType const*>(this);
if (integer->isSigned())
result["kind"] = "int";
else
result["kind"] = "uint";
result["bits"] = integer->numBits();
break;
}
case Category::RationalNumber:
result["kind"] = "rational";
break;
case Category::StringLiteral:
result["kind"] = "string";
break;
case Category::Bool:
result["kind"] = "bool";
break;
case Category::FixedPoint:
result["kind"] = "fixed";
break;
case Category::Array:
result["kind"] = "array";
break;
case Category::ArraySlice:
result["kind"] = "slice";
break;
case Category::FixedBytes:
result["kind"] = "bytes";
break;
case Category::Contract:
result["kind"] = "contract";
break;
case Category::Struct:
result["kind"] = "struct";
break;
case Category::Function:
result["kind"] = "function";
break;
case Category::Enum:
result["kind"] = "enum";
break;
case Category::UserDefinedValueType:
result["kind"] = "udvt";
break;
case Category::Tuple:
result["kind"] = "tuple";
break;
case Category::Mapping:
result["kind"] = "mapping";
break;
case Category::TypeType:
result["kind"] = "type-type";
break;
case Category::Modifier:
result["kind"] = "modifier";
break;
case Category::Magic:
result["kind"] = "magic";
break;
case Category::Module:
result["kind"] = "module";
break;
case Category::InaccessibleDynamic:
result["kind"] = "inaccessible-dynamic";
break;
}
return result;
}

MemberList::MemberMap Type::attachedFunctions(Type const& _type, ASTNode const& _scope)
{
MemberList::MemberMap members;
Expand Down
4 changes: 3 additions & 1 deletion libsolidity/ast/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,15 @@

#pragma once

#include <liblangutil/Exceptions.h>
#include <libsolidity/ast/ASTEnums.h>
#include <libsolidity/ast/ASTForward.h>
#include <libsolidity/parsing/Token.h>
#include <liblangutil/Exceptions.h>

#include <libsolutil/Common.h>
#include <libsolutil/Numeric.h>
#include <libsolutil/CommonIO.h>
#include <libsolutil/JSON.h>
#include <libsolutil/LazyInit.h>
#include <libsolutil/Result.h>

Expand Down Expand Up @@ -409,6 +410,7 @@ class Type
bool _unary
) const;

virtual std::optional<Json> ethdebug() const;
private:
/// @returns a member list containing all members added to this type by `using for` directives.
static MemberList::MemberMap attachedFunctions(Type const& _type, ASTNode const& _scope);
Expand Down
Loading