Skip to content

Commit c4cb445

Browse files
committed
Enable ethdebug debug info and output selection.
1 parent 55a5fd9 commit c4cb445

File tree

91 files changed

+1184
-21
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

91 files changed

+1184
-21
lines changed

libevmasm/Assembly.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ std::string Assembly::assemblyString(
426426
{
427427
std::ostringstream tmp;
428428
assemblyStream(tmp, _debugInfoSelection, "", _sourceCodes);
429-
return tmp.str();
429+
return (_debugInfoSelection.ethdebug ? "/// ethdebug: enabled\n" : "") + tmp.str();
430430
}
431431

432432
Json Assembly::assemblyJSON(std::map<std::string, unsigned> const& _sourceIndices, bool _includeSourceList) const

liblangutil/DebugInfoSelection.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,22 @@ DebugInfoSelection const DebugInfoSelection::Only(bool DebugInfoSelection::* _me
4949
return result;
5050
}
5151

52+
DebugInfoSelection const DebugInfoSelection::Except(std::vector<bool DebugInfoSelection::*> const& _members) noexcept
53+
{
54+
DebugInfoSelection result = All();
55+
for (bool DebugInfoSelection::* member: _members)
56+
result.*member = false;
57+
return result;
58+
}
59+
5260
std::optional<DebugInfoSelection> DebugInfoSelection::fromString(std::string_view _input)
5361
{
5462
// TODO: Make more stuff constexpr and make it a static_assert().
5563
solAssert(componentMap().count("all") == 0, "");
5664
solAssert(componentMap().count("none") == 0, "");
5765

5866
if (_input == "all")
59-
return All();
67+
return ExceptExperimental();
6068
if (_input == "none")
6169
return None();
6270

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

7987
if (!selection.enable(component))
8088
return std::nullopt;

liblangutil/DebugInfoSelection.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,9 @@ struct DebugInfoSelection
4242
static DebugInfoSelection const All(bool _value = true) noexcept;
4343
static DebugInfoSelection const None() noexcept { return All(false); }
4444
static DebugInfoSelection const Only(bool DebugInfoSelection::* _member) noexcept;
45-
static DebugInfoSelection const Default() noexcept { return All(); }
45+
static DebugInfoSelection const Default() noexcept { return ExceptExperimental(); }
46+
static DebugInfoSelection const Except(std::vector<bool DebugInfoSelection::*> const& _members) noexcept;
47+
static DebugInfoSelection const ExceptExperimental() noexcept { return Except({&DebugInfoSelection::ethdebug}); }
4648

4749
static std::optional<DebugInfoSelection> fromString(std::string_view _input);
4850
static std::optional<DebugInfoSelection> fromComponents(
@@ -72,13 +74,15 @@ struct DebugInfoSelection
7274
{"location", &DebugInfoSelection::location},
7375
{"snippet", &DebugInfoSelection::snippet},
7476
{"ast-id", &DebugInfoSelection::astID},
77+
{"ethdebug", &DebugInfoSelection::ethdebug},
7578
};
7679
return components;
7780
}
7881

7982
bool location = false; ///< Include source location. E.g. `@src 3:50:100`
8083
bool snippet = false; ///< Include source code snippet next to location. E.g. `@src 3:50:100 "contract C {..."`
8184
bool astID = false; ///< Include ID of the Solidity AST node. E.g. `@ast-id 15`
85+
bool ethdebug = false; ///< Include ethdebug related debug information.
8286
};
8387

8488
std::ostream& operator<<(std::ostream& _stream, DebugInfoSelection const& _selection);

libsolidity/codegen/ir/IRGenerator.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ std::string IRGenerator::generate(
130130
);
131131
};
132132

133-
Whiskers t(R"(
133+
Whiskers t(R"(<?isEthdebugEnabled>/// ethdebug: enabled</isEthdebugEnabled>
134134
/// @use-src <useSrcMapCreation>
135135
object "<CreationObject>" {
136136
code {
@@ -167,6 +167,7 @@ std::string IRGenerator::generate(
167167
for (VariableDeclaration const* var: ContractType(_contract).immutableVariables())
168168
m_context.registerImmutableVariable(*var);
169169

170+
t("isEthdebugEnabled", m_context.debugInfoSelection().ethdebug);
170171
t("CreationObject", IRNames::creationObject(_contract));
171172
t("sourceLocationCommentCreation", dispenseLocationComment(_contract));
172173
t("library", _contract.isLibrary());

libsolidity/interface/CompilerStack.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,6 +1091,14 @@ Json CompilerStack::interfaceSymbols(std::string const& _contractName) const
10911091
return interfaceSymbols;
10921092
}
10931093

1094+
Json CompilerStack::ethdebug(std::string const& _contractName) const
1095+
{
1096+
(void)_contractName;
1097+
1098+
Json ethdebug = {{"not yet implemented", true}};
1099+
return ethdebug;
1100+
}
1101+
10941102
bytes CompilerStack::cborMetadata(std::string const& _contractName, bool _forIR) const
10951103
{
10961104
solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful.");

libsolidity/interface/CompilerStack.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,10 @@ class CompilerStack: public langutil::CharStreamProvider, public evmasm::Abstrac
353353
/// @returns a JSON object with the three members ``methods``, ``events``, ``errors``. Each is a map, mapping identifiers (hashes) to function names.
354354
Json interfaceSymbols(std::string const& _contractName) const;
355355

356+
/// @returns a JSON representing the ethdebug data of the specified contract.
357+
/// Prerequisite: Successful call to parse or compile.
358+
Json ethdebug(std::string const& _contractName) const;
359+
356360
/// @returns the Contract Metadata matching the pipeline selected using the viaIR setting.
357361
std::string const& metadata(std::string const& _contractName) const { return metadata(contract(_contractName)); }
358362

libsolidity/interface/StandardCompiler.cpp

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ bool hashMatchesContent(std::string const& _hash, std::string const& _content)
180180

181181
bool isArtifactRequested(Json const& _outputSelection, std::string const& _artifact, bool _wildcardMatchesExperimental)
182182
{
183-
static std::set<std::string> experimental{"ir", "irAst", "irOptimized", "irOptimizedAst"};
183+
static std::set<std::string> experimental{"ir", "irAst", "irOptimized", "irOptimizedAst", "ethdebug"};
184184
for (auto const& selectedArtifactJson: _outputSelection)
185185
{
186186
std::string const& selectedArtifact = selectedArtifactJson.get<std::string>();
@@ -265,7 +265,7 @@ bool isBinaryRequested(Json const& _outputSelection)
265265
static std::vector<std::string> const outputsThatRequireBinaries = std::vector<std::string>{
266266
"*",
267267
"ir", "irAst", "irOptimized", "irOptimizedAst",
268-
"evm.gasEstimates", "evm.legacyAssembly", "evm.assembly"
268+
"evm.gasEstimates", "evm.legacyAssembly", "evm.assembly", "ethdebug"
269269
} + evmObjectComponents("bytecode") + evmObjectComponents("deployedBytecode");
270270

271271
for (auto const& fileRequests: _outputSelection)
@@ -295,6 +295,21 @@ bool isEvmBytecodeRequested(Json const& _outputSelection)
295295
return false;
296296
}
297297

298+
/// @returns true if ethdebug was requested.
299+
bool isEthdebugRequested(Json const& _outputSelection)
300+
{
301+
if (!_outputSelection.is_object())
302+
return false;
303+
304+
for (auto const& fileRequests: _outputSelection)
305+
for (auto const& requests: fileRequests)
306+
for (auto const& request: requests)
307+
if (request == "ethdebug")
308+
return true;
309+
310+
return false;
311+
}
312+
298313
/// @returns The IR output selection for CompilerStack, based on outputs requested in the JSON.
299314
/// Note that as an exception, '*' does not yet match "ir", "irAst", "irOptimized" or "irOptimizedAst".
300315
CompilerStack::IROutputSelection irOutputSelection(Json const& _outputSelection)
@@ -1172,6 +1187,30 @@ std::variant<StandardCompiler::InputsAndSettings, Json> StandardCompiler::parseI
11721187
ret.modelCheckerSettings.timeout = modelCheckerSettings["timeout"].get<Json::number_unsigned_t>();
11731188
}
11741189

1190+
if (isEthdebugRequested(ret.outputSelection))
1191+
{
1192+
if (ret.language == "Solidity" && !ret.viaIR)
1193+
return formatError(Error::Type::FatalError, "general", "''ethdebug' can only be selected as output, if 'viaIR' was set.");
1194+
1195+
if (!ret.debugInfoSelection.has_value())
1196+
{
1197+
ret.debugInfoSelection = DebugInfoSelection::Default();
1198+
ret.debugInfoSelection->enable("ethdebug");
1199+
}
1200+
else
1201+
{
1202+
if (!ret.debugInfoSelection->ethdebug)
1203+
return formatError(Error::Type::FatalError, "general", "'ethdebug' need to be enabled in 'settings.debug.debugInfo', if 'ethdebug' was selected as output.");
1204+
}
1205+
}
1206+
1207+
if (
1208+
ret.debugInfoSelection.has_value() && ret.debugInfoSelection->ethdebug &&
1209+
irOutputSelection(ret.outputSelection) == CompilerStack::IROutputSelection::None &&
1210+
!isEthdebugRequested(ret.outputSelection)
1211+
)
1212+
return formatFatalError(Error::Type::FatalError, "'settings.debug.debugInfo' can only include 'ethdebug', if output 'ir', 'irOptimized' and/or 'ethdebug' was selected.");
1213+
11751214
return {std::move(ret)};
11761215
}
11771216

@@ -1429,8 +1468,8 @@ Json StandardCompiler::compileSolidity(StandardCompiler::InputsAndSettings _inpu
14291468

14301469
Json output;
14311470

1432-
if (errors.size() > 0)
1433-
output["errors"] = std::move(errors);
1471+
if (!errors.empty())
1472+
output["errors"] = std::move(errors);
14341473

14351474
if (!compilerStack.unhandledSMTLib2Queries().empty())
14361475
for (std::string const& query: compilerStack.unhandledSMTLib2Queries())
@@ -1475,6 +1514,10 @@ Json StandardCompiler::compileSolidity(StandardCompiler::InputsAndSettings _inpu
14751514
if (isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "devdoc", wildcardMatchesExperimental))
14761515
contractData["devdoc"] = compilerStack.natspecDev(contractName);
14771516

1517+
// ethdebug
1518+
if (compilationSuccess && _inputsAndSettings.viaIR && isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "ethdebug", wildcardMatchesExperimental))
1519+
contractData["ethdebug"] = compilerStack.ethdebug(contractName);
1520+
14781521
// IR
14791522
if (compilationSuccess && isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "ir", wildcardMatchesExperimental))
14801523
contractData["ir"] = compilerStack.yulIR(contractName);
@@ -1698,6 +1741,9 @@ Json StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings)
16981741
if (isArtifactRequested(_inputsAndSettings.outputSelection, sourceName, contractName, "evm.assembly", wildcardMatchesExperimental))
16991742
output["contracts"][sourceName][contractName]["evm"]["assembly"] = object.assembly->assemblyString(stack.debugInfoSelection());
17001743

1744+
if (isEthdebugRequested(_inputsAndSettings.outputSelection))
1745+
output["ethdebug"] = object.ethdebug;
1746+
17011747
return output;
17021748
}
17031749

libyul/YulStack.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ YulStack::assembleWithDeployed(std::optional<std::string_view> _deployName)
276276
{{m_charStream->name(), 0}}
277277
)
278278
);
279+
creationObject.ethdebug["not yet implemented"] = true;
279280

280281
if (deployedAssembly)
281282
{
@@ -287,6 +288,7 @@ YulStack::assembleWithDeployed(std::optional<std::string_view> _deployName)
287288
{{m_charStream->name(), 0}}
288289
)
289290
);
291+
deployedObject.ethdebug["not yet implemented"] = true;
290292
}
291293
}
292294
catch (UnimplementedFeatureError const& _error)
@@ -360,7 +362,8 @@ std::string YulStack::print(
360362
yulAssert(m_stackState >= Parsed);
361363
yulAssert(m_parserResult, "");
362364
yulAssert(m_parserResult->hasCode(), "");
363-
return m_parserResult->toString(
365+
return (m_debugInfoSelection.ethdebug ? "/// ethdebug: enabled\n" : "") +
366+
m_parserResult->toString(
364367
languageToDialect(m_language, m_evmVersion),
365368
AsmPrinter::TypePrinting::OmitDefault,
366369
m_debugInfoSelection,

libyul/YulStack.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ struct MachineAssemblyObject
5757
std::shared_ptr<evmasm::LinkerObject> bytecode;
5858
std::shared_ptr<evmasm::Assembly> assembly;
5959
std::unique_ptr<std::string> sourceMappings;
60+
Json ethdebug = Json::object();
6061
};
6162

6263
/*

solc/CommandLineInterface.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,8 @@ static bool needsHumanTargetedStdout(CommandLineOptions const& _options)
156156
_options.compiler.outputs.opcodes ||
157157
_options.compiler.outputs.signatureHashes ||
158158
_options.compiler.outputs.storageLayout ||
159-
_options.compiler.outputs.transientStorageLayout;
159+
_options.compiler.outputs.transientStorageLayout ||
160+
_options.compiler.outputs.ethdebug;
160161
}
161162

162163
static bool coloredOutput(CommandLineOptions const& _options)
@@ -520,6 +521,20 @@ void CommandLineInterface::handleGasEstimation(std::string const& _contract)
520521
}
521522
}
522523

524+
void CommandLineInterface::handleEthdebug(std::string const& _contract)
525+
{
526+
solAssert(CompilerInputModes.count(m_options.input.mode) == 1);
527+
528+
if (!m_options.compiler.outputs.ethdebug)
529+
return;
530+
531+
std::string data = jsonPrint(removeNullMembers(m_compiler->ethdebug(_contract)), m_options.formatting.json);
532+
if (!m_options.output.dir.empty())
533+
createFile(m_compiler->filesystemFriendlyName(_contract) + "_ethdebug.json", data);
534+
else
535+
sout() << "Debug Data (ethdebug):" << std::endl << data << std::endl;
536+
}
537+
523538
void CommandLineInterface::readInputFiles()
524539
{
525540
solAssert(!m_standardJsonInput.has_value());
@@ -1300,6 +1315,14 @@ void CommandLineInterface::assembleYul(yul::YulStack::Language _language, yul::Y
13001315
m_options.formatting.json
13011316
) << std::endl;
13021317
}
1318+
if (m_options.compiler.outputs.ethdebug)
1319+
{
1320+
sout() << std::endl << "Debug Data (ethdebug):" << std::endl;
1321+
sout() << util::jsonPrint(
1322+
object.ethdebug,
1323+
m_options.formatting.json
1324+
) << std::endl;
1325+
}
13031326
}
13041327
}
13051328

@@ -1342,6 +1365,7 @@ void CommandLineInterface::outputCompilationResults()
13421365
handleTransientStorageLayout(contract);
13431366
handleNatspec(true, contract);
13441367
handleNatspec(false, contract);
1368+
handleEthdebug(contract);
13451369
} // end of contracts iteration
13461370
}
13471371

0 commit comments

Comments
 (0)