Handle DebugInfoSelection in the code printing Yul and EVM assembly

This commit is contained in:
Kamil Śliwak 2021-09-03 19:38:59 +02:00
parent 25eedfafe2
commit f7c4ed849d
8 changed files with 96 additions and 35 deletions

View File

@ -96,13 +96,13 @@ public:
m_out(_out), m_prefix(_prefix), m_sourceCodes(_sourceCodes), m_assembly(_assembly) m_out(_out), m_prefix(_prefix), m_sourceCodes(_sourceCodes), m_assembly(_assembly)
{} {}
void feed(AssemblyItem const& _item) void feed(AssemblyItem const& _item, DebugInfoSelection const& _debugInfoSelection)
{ {
if (_item.location().isValid() && _item.location() != m_location) if (_item.location().isValid() && _item.location() != m_location)
{ {
flush(); flush();
m_location = _item.location(); m_location = _item.location();
printLocation(); printLocation(_debugInfoSelection);
} }
string expression = _item.toAssemblyText(m_assembly); string expression = _item.toAssemblyText(m_assembly);
@ -142,16 +142,29 @@ public:
m_pending.clear(); m_pending.clear();
} }
void printLocation() void printLocation(DebugInfoSelection const& _debugInfoSelection)
{ {
if (!m_location.isValid()) if (!m_location.isValid() || (!_debugInfoSelection.location && !_debugInfoSelection.snippet))
return; return;
m_out << m_prefix << " /*"; m_out << m_prefix << " /*";
if (_debugInfoSelection.location)
{
if (m_location.sourceName) if (m_location.sourceName)
m_out << " " + escapeAndQuoteString(*m_location.sourceName); m_out << " " + escapeAndQuoteString(*m_location.sourceName);
if (m_location.hasText()) if (m_location.hasText())
m_out << ":" << to_string(m_location.start) + ":" + to_string(m_location.end); m_out << ":" << to_string(m_location.start) + ":" + to_string(m_location.end);
m_out << " " << locationFromSources(m_sourceCodes, m_location); }
if (_debugInfoSelection.snippet)
{
if (_debugInfoSelection.location)
m_out << " ";
m_out << locationFromSources(m_sourceCodes, m_location);
}
m_out << " */" << endl; m_out << " */" << endl;
} }
@ -167,12 +180,17 @@ private:
} }
void Assembly::assemblyStream(ostream& _out, string const& _prefix, StringMap const& _sourceCodes) const void Assembly::assemblyStream(
ostream& _out,
DebugInfoSelection const& _debugInfoSelection,
string const& _prefix,
StringMap const& _sourceCodes
) const
{ {
Functionalizer f(_out, _prefix, _sourceCodes, *this); Functionalizer f(_out, _prefix, _sourceCodes, *this);
for (auto const& i: m_items) for (auto const& i: m_items)
f.feed(i); f.feed(i, _debugInfoSelection);
f.flush(); f.flush();
if (!m_data.empty() || !m_subs.empty()) if (!m_data.empty() || !m_subs.empty())
@ -185,7 +203,7 @@ void Assembly::assemblyStream(ostream& _out, string const& _prefix, StringMap co
for (size_t i = 0; i < m_subs.size(); ++i) for (size_t i = 0; i < m_subs.size(); ++i)
{ {
_out << endl << _prefix << "sub_" << i << ": assembly {\n"; _out << endl << _prefix << "sub_" << i << ": assembly {\n";
m_subs[i]->assemblyStream(_out, _prefix + " ", _sourceCodes); m_subs[i]->assemblyStream(_out, _debugInfoSelection, _prefix + " ", _sourceCodes);
_out << _prefix << "}" << endl; _out << _prefix << "}" << endl;
} }
} }
@ -194,10 +212,13 @@ void Assembly::assemblyStream(ostream& _out, string const& _prefix, StringMap co
_out << endl << _prefix << "auxdata: 0x" << util::toHex(m_auxiliaryData) << endl; _out << endl << _prefix << "auxdata: 0x" << util::toHex(m_auxiliaryData) << endl;
} }
string Assembly::assemblyString(StringMap const& _sourceCodes) const string Assembly::assemblyString(
DebugInfoSelection const& _debugInfoSelection,
StringMap const& _sourceCodes
) const
{ {
ostringstream tmp; ostringstream tmp;
assemblyStream(tmp, "", _sourceCodes); assemblyStream(tmp, _debugInfoSelection, "", _sourceCodes);
return tmp.str(); return tmp.str();
} }

View File

@ -24,6 +24,7 @@
#include <libevmasm/LinkerObject.h> #include <libevmasm/LinkerObject.h>
#include <libevmasm/Exceptions.h> #include <libevmasm/Exceptions.h>
#include <liblangutil/DebugInfoSelection.h>
#include <liblangutil/EVMVersion.h> #include <liblangutil/EVMVersion.h>
#include <libsolutil/Common.h> #include <libsolutil/Common.h>
@ -142,10 +143,12 @@ public:
/// Create a text representation of the assembly. /// Create a text representation of the assembly.
std::string assemblyString( std::string assemblyString(
langutil::DebugInfoSelection const& _debugInfoSelection = langutil::DebugInfoSelection::Default(),
StringMap const& _sourceCodes = StringMap() StringMap const& _sourceCodes = StringMap()
) const; ) const;
void assemblyStream( void assemblyStream(
std::ostream& _out, std::ostream& _out,
langutil::DebugInfoSelection const& _debugInfoSelection = langutil::DebugInfoSelection::Default(),
std::string const& _prefix = "", std::string const& _prefix = "",
StringMap const& _sourceCodes = StringMap() StringMap const& _sourceCodes = StringMap()
) const; ) const;

View File

@ -135,11 +135,15 @@ string dispenseLocationComment(langutil::SourceLocation const& _location, IRGene
{ {
solAssert(_location.sourceName, ""); solAssert(_location.sourceName, "");
_context.markSourceUsed(*_location.sourceName); _context.markSourceUsed(*_location.sourceName);
return "/// " + AsmPrinter::formatSourceLocation(
string debugInfo = AsmPrinter::formatSourceLocation(
_location, _location,
_context.sourceIndices(), _context.sourceIndices(),
_context.debugInfoSelection(),
_context.soliditySourceProvider() _context.soliditySourceProvider()
); );
return debugInfo.empty() ? "" : "/// " + debugInfo;
} }
string dispenseLocationComment(ASTNode const& _node, IRGenerationContext& _context) string dispenseLocationComment(ASTNode const& _node, IRGenerationContext& _context)

View File

@ -30,6 +30,7 @@
#include <libsolidity/codegen/ir/Common.h> #include <libsolidity/codegen/ir/Common.h>
#include <liblangutil/CharStreamProvider.h> #include <liblangutil/CharStreamProvider.h>
#include <liblangutil/DebugInfoSelection.h>
#include <liblangutil/EVMVersion.h> #include <liblangutil/EVMVersion.h>
#include <libsolutil/Common.h> #include <libsolutil/Common.h>
@ -174,6 +175,7 @@ public:
bool immutableRegistered(VariableDeclaration const& _varDecl) const { return m_immutableVariables.count(&_varDecl); } bool immutableRegistered(VariableDeclaration const& _varDecl) const { return m_immutableVariables.count(&_varDecl); }
langutil::DebugInfoSelection debugInfoSelection() const { return m_debugInfoSelection; }
langutil::CharStreamProvider const* soliditySourceProvider() const { return m_soliditySourceProvider; } langutil::CharStreamProvider const* soliditySourceProvider() const { return m_soliditySourceProvider; }
private: private:
@ -220,6 +222,7 @@ private:
std::set<ContractDefinition const*, ASTNode::CompareByID> m_subObjects; std::set<ContractDefinition const*, ASTNode::CompareByID> m_subObjects;
langutil::DebugInfoSelection m_debugInfoSelection = langutil::DebugInfoSelection::Default();
langutil::CharStreamProvider const* m_soliditySourceProvider = nullptr; langutil::CharStreamProvider const* m_soliditySourceProvider = nullptr;
}; };

View File

@ -340,8 +340,7 @@ string IRGenerator::generateFunction(FunctionDefinition const& _function)
return m_context.functionCollector().createFunction(functionName, [&]() { return m_context.functionCollector().createFunction(functionName, [&]() {
m_context.resetLocalVariables(); m_context.resetLocalVariables();
Whiskers t(R"( Whiskers t(R"(
/// @ast-id <astID> <astIDComment><sourceLocationComment>
<sourceLocationComment>
function <functionName>(<params>)<?+retParams> -> <retParams></+retParams> { function <functionName>(<params>)<?+retParams> -> <retParams></+retParams> {
<retInit> <retInit>
<body> <body>
@ -349,7 +348,10 @@ string IRGenerator::generateFunction(FunctionDefinition const& _function)
<contractSourceLocationComment> <contractSourceLocationComment>
)"); )");
t("astID", to_string(_function.id())); if (m_context.debugInfoSelection().astID)
t("astIDComment", "/// @ast-id " + to_string(_function.id()) + "\n");
else
t("astIDComment", "");
t("sourceLocationComment", dispenseLocationComment(_function)); t("sourceLocationComment", dispenseLocationComment(_function));
t( t(
"contractSourceLocationComment", "contractSourceLocationComment",
@ -409,8 +411,7 @@ string IRGenerator::generateModifier(
return m_context.functionCollector().createFunction(functionName, [&]() { return m_context.functionCollector().createFunction(functionName, [&]() {
m_context.resetLocalVariables(); m_context.resetLocalVariables();
Whiskers t(R"( Whiskers t(R"(
/// @ast-id <astID> <astIDComment><sourceLocationComment>
<sourceLocationComment>
function <functionName>(<params>)<?+retParams> -> <retParams></+retParams> { function <functionName>(<params>)<?+retParams> -> <retParams></+retParams> {
<assignRetParams> <assignRetParams>
<evalArgs> <evalArgs>
@ -418,6 +419,7 @@ string IRGenerator::generateModifier(
} }
<contractSourceLocationComment> <contractSourceLocationComment>
)"); )");
t("functionName", functionName); t("functionName", functionName);
vector<string> retParamsIn; vector<string> retParamsIn;
for (auto const& varDecl: _function.returnParameters()) for (auto const& varDecl: _function.returnParameters())
@ -440,7 +442,11 @@ string IRGenerator::generateModifier(
_modifierInvocation.name().annotation().referencedDeclaration _modifierInvocation.name().annotation().referencedDeclaration
); );
solAssert(modifier, ""); solAssert(modifier, "");
t("astID", to_string(modifier->id()));
if (m_context.debugInfoSelection().astID)
t("astIDComment", "/// @ast-id " + to_string(modifier->id()) + "\n");
else
t("astIDComment", "");
t("sourceLocationComment", dispenseLocationComment(*modifier)); t("sourceLocationComment", dispenseLocationComment(*modifier));
t( t(
"contractSourceLocationComment", "contractSourceLocationComment",
@ -546,14 +552,18 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl)
solAssert(paramTypes.empty(), ""); solAssert(paramTypes.empty(), "");
solUnimplementedAssert(type->sizeOnStack() == 1); solUnimplementedAssert(type->sizeOnStack() == 1);
return Whiskers(R"( return Whiskers(R"(
/// @ast-id <astID> <astIDComment><sourceLocationComment>
<sourceLocationComment>
function <functionName>() -> rval { function <functionName>() -> rval {
rval := loadimmutable("<id>") rval := loadimmutable("<id>")
} }
<contractSourceLocationComment> <contractSourceLocationComment>
)") )")
("astID", to_string(_varDecl.id())) (
"astIDComment",
m_context.debugInfoSelection().astID ?
"/// @ast-id " + to_string(_varDecl.id()) + "\n" :
""
)
("sourceLocationComment", dispenseLocationComment(_varDecl)) ("sourceLocationComment", dispenseLocationComment(_varDecl))
( (
"contractSourceLocationComment", "contractSourceLocationComment",
@ -567,14 +577,18 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl)
{ {
solAssert(paramTypes.empty(), ""); solAssert(paramTypes.empty(), "");
return Whiskers(R"( return Whiskers(R"(
/// @ast-id <astID> <astIDComment><sourceLocationComment>
<sourceLocationComment>
function <functionName>() -> <ret> { function <functionName>() -> <ret> {
<ret> := <constantValueFunction>() <ret> := <constantValueFunction>()
} }
<contractSourceLocationComment> <contractSourceLocationComment>
)") )")
("astID", to_string(_varDecl.id())) (
"astIDComment",
m_context.debugInfoSelection().astID ?
"/// @ast-id " + to_string(_varDecl.id()) + "\n" :
""
)
("sourceLocationComment", dispenseLocationComment(_varDecl)) ("sourceLocationComment", dispenseLocationComment(_varDecl))
( (
"contractSourceLocationComment", "contractSourceLocationComment",
@ -691,8 +705,7 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl)
} }
return Whiskers(R"( return Whiskers(R"(
/// @ast-id <astID> <astIDComment><sourceLocationComment>
<sourceLocationComment>
function <functionName>(<params>) -> <retVariables> { function <functionName>(<params>) -> <retVariables> {
<code> <code>
} }
@ -702,7 +715,12 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl)
("params", joinHumanReadable(parameters)) ("params", joinHumanReadable(parameters))
("retVariables", joinHumanReadable(returnVariables)) ("retVariables", joinHumanReadable(returnVariables))
("code", std::move(code)) ("code", std::move(code))
("astID", to_string(_varDecl.id())) (
"astIDComment",
m_context.debugInfoSelection().astID ?
"/// @ast-id " + to_string(_varDecl.id()) + "\n" :
""
)
("sourceLocationComment", dispenseLocationComment(_varDecl)) ("sourceLocationComment", dispenseLocationComment(_varDecl))
( (
"contractSourceLocationComment", "contractSourceLocationComment",
@ -829,7 +847,7 @@ void IRGenerator::generateConstructors(ContractDefinition const& _contract)
for (ASTPointer<VariableDeclaration> const& varDecl: contract->constructor()->parameters()) for (ASTPointer<VariableDeclaration> const& varDecl: contract->constructor()->parameters())
params += m_context.addLocalVariable(*varDecl).stackSlots(); params += m_context.addLocalVariable(*varDecl).stackSlots();
if (contract->constructor()) if (m_context.debugInfoSelection().astID && contract->constructor())
t("astIDComment", "/// @ast-id " + to_string(contract->constructor()->id()) + "\n"); t("astIDComment", "/// @ast-id " + to_string(contract->constructor()->id()) + "\n");
else else
t("astIDComment", ""); t("astIDComment", "");

View File

@ -882,7 +882,7 @@ string CompilerStack::assemblyString(string const& _contractName, StringMap cons
Contract const& currentContract = contract(_contractName); Contract const& currentContract = contract(_contractName);
if (currentContract.evmAssembly) if (currentContract.evmAssembly)
return currentContract.evmAssembly->assemblyString(_sourceCodes); return currentContract.evmAssembly->assemblyString(DebugInfoSelection::Default(), _sourceCodes);
else else
return string(); return string();
} }

View File

@ -261,10 +261,16 @@ string AsmPrinter::appendTypeName(YulString _type, bool _isBoolLiteral) const
string AsmPrinter::formatSourceLocation( string AsmPrinter::formatSourceLocation(
SourceLocation const& _location, SourceLocation const& _location,
map<string, unsigned> const& _nameToSourceIndex, map<string, unsigned> const& _nameToSourceIndex,
DebugInfoSelection const& _debugInfoSelection,
CharStreamProvider const* _soliditySourceProvider CharStreamProvider const* _soliditySourceProvider
) )
{ {
yulAssert(!_nameToSourceIndex.empty(), ""); yulAssert(!_nameToSourceIndex.empty(), "");
if (_debugInfoSelection.snippet)
yulAssert(_debugInfoSelection.location, "@src tag must always contain the source location");
if (_debugInfoSelection.none())
return "";
string sourceIndex = "-1"; string sourceIndex = "-1";
string solidityCodeSnippet = ""; string solidityCodeSnippet = "";
@ -272,7 +278,7 @@ string AsmPrinter::formatSourceLocation(
{ {
sourceIndex = to_string(_nameToSourceIndex.at(*_location.sourceName)); sourceIndex = to_string(_nameToSourceIndex.at(*_location.sourceName));
if (_soliditySourceProvider) if (_debugInfoSelection.snippet && _soliditySourceProvider)
{ {
solidityCodeSnippet = escapeAndQuoteString( solidityCodeSnippet = escapeAndQuoteString(
_soliditySourceProvider->charStream(*_location.sourceName).singleLineSnippet(_location) _soliditySourceProvider->charStream(*_location.sourceName).singleLineSnippet(_location)
@ -298,11 +304,14 @@ string AsmPrinter::formatSourceLocation(
string AsmPrinter::formatDebugData(shared_ptr<DebugData const> const& _debugData, bool _statement) string AsmPrinter::formatDebugData(shared_ptr<DebugData const> const& _debugData, bool _statement)
{ {
if (!_debugData) DebugInfoSelection debugInfoSelection = DebugInfoSelection::Default();
if (!_debugData || debugInfoSelection.none())
return ""; return "";
vector<string> items; vector<string> items;
if (auto id = _debugData->astID) if (auto id = _debugData->astID)
if (debugInfoSelection.astID)
items.emplace_back("@ast-id " + to_string(*id)); items.emplace_back("@ast-id " + to_string(*id));
if ( if (
@ -315,6 +324,7 @@ string AsmPrinter::formatDebugData(shared_ptr<DebugData const> const& _debugData
items.emplace_back(formatSourceLocation( items.emplace_back(formatSourceLocation(
_debugData->originLocation, _debugData->originLocation,
m_nameToSourceIndex, m_nameToSourceIndex,
debugInfoSelection,
m_soliditySourceProvider m_soliditySourceProvider
)); ));
} }

View File

@ -29,6 +29,7 @@
#include <libsolutil/CommonData.h> #include <libsolutil/CommonData.h>
#include <liblangutil/CharStreamProvider.h> #include <liblangutil/CharStreamProvider.h>
#include <liblangutil/DebugInfoSelection.h>
#include <liblangutil/SourceLocation.h> #include <liblangutil/SourceLocation.h>
#include <map> #include <map>
@ -83,6 +84,7 @@ public:
static std::string formatSourceLocation( static std::string formatSourceLocation(
langutil::SourceLocation const& _location, langutil::SourceLocation const& _location,
std::map<std::string, unsigned> const& _nameToSourceIndex, std::map<std::string, unsigned> const& _nameToSourceIndex,
langutil::DebugInfoSelection const& _debugInfoSelection = langutil::DebugInfoSelection::Default(),
langutil::CharStreamProvider const* m_soliditySourceProvider = nullptr langutil::CharStreamProvider const* m_soliditySourceProvider = nullptr
); );