@@ -165,21 +165,28 @@ bool hashMatchesContent(std::string const& _hash, std::string const& _content)
165
165
166
166
bool isArtifactRequested (Json const & _outputSelection, std::string const & _artifact, bool _wildcardMatchesExperimental)
167
167
{
168
- static std::set<std::string> experimental{" ir" , " irAst" , " irOptimized" , " irOptimizedAst" , " yulCFGJson" };
168
+ static std::set<std::string> experimental{" ir" , " irAst" , " irOptimized" , " irOptimizedAst" , " yulCFGJson" , " ethdebug " };
169
169
for (auto const & selectedArtifactJson: _outputSelection)
170
170
{
171
171
std::string const & selectedArtifact = selectedArtifactJson.get <std::string>();
172
172
if (
173
173
_artifact == selectedArtifact ||
174
174
boost::algorithm::starts_with (_artifact, selectedArtifact + " ." )
175
175
)
176
+ {
177
+ if (_artifact.find (" ethdebug" ) != std::string::npos)
178
+ // only accept exact matches for ethdebug, e.g. evm.bytecode.ethdebug
179
+ return selectedArtifact == _artifact;
176
180
return true ;
181
+ }
177
182
else if (selectedArtifact == " *" )
178
183
{
179
184
// TODO: yulCFGJson is only experimental now, so it should not be matched by "*".
180
185
if (_artifact == " yulCFGJson" )
181
186
return false ;
182
187
// "ir", "irOptimized" can only be matched by "*" if activated.
188
+ if (_artifact.find (" ethdebug" ) != std::string::npos)
189
+ return false ;
183
190
if (experimental.count (_artifact) == 0 || _wildcardMatchesExperimental)
184
191
return true ;
185
192
}
@@ -237,7 +244,7 @@ bool isArtifactRequested(Json const& _outputSelection, std::string const& _file,
237
244
std::vector<std::string> evmObjectComponents (std::string const & _objectKind)
238
245
{
239
246
solAssert (_objectKind == " bytecode" || _objectKind == " deployedBytecode" , " " );
240
- std::vector<std::string> components{" " , " .object" , " .opcodes" , " .sourceMap" , " .functionDebugData" , " .generatedSources" , " .linkReferences" };
247
+ std::vector<std::string> components{" " , " .object" , " .opcodes" , " .sourceMap" , " .functionDebugData" , " .generatedSources" , " .linkReferences" , " .ethdebug " };
241
248
if (_objectKind == " deployedBytecode" )
242
249
components.push_back (" .immutableReferences" );
243
250
return util::applyMap (components, [&](auto const & _s) { return " evm." + _objectKind + _s; });
@@ -253,7 +260,7 @@ bool isBinaryRequested(Json const& _outputSelection)
253
260
static std::vector<std::string> const outputsThatRequireBinaries = std::vector<std::string>{
254
261
" *" ,
255
262
" ir" , " irAst" , " irOptimized" , " irOptimizedAst" , " yulCFGJson" ,
256
- " evm.gasEstimates" , " evm.legacyAssembly" , " evm.assembly"
263
+ " evm.gasEstimates" , " evm.legacyAssembly" , " evm.assembly" , " ethdebug "
257
264
} + evmObjectComponents (" bytecode" ) + evmObjectComponents (" deployedBytecode" );
258
265
259
266
for (auto const & fileRequests: _outputSelection)
@@ -283,6 +290,21 @@ bool isEvmBytecodeRequested(Json const& _outputSelection)
283
290
return false ;
284
291
}
285
292
293
+ // / @returns true if ethdebug was requested.
294
+ bool isEthdebugRequested (Json const & _outputSelection)
295
+ {
296
+ if (!_outputSelection.is_object ())
297
+ return false ;
298
+
299
+ for (auto const & fileRequests: _outputSelection)
300
+ for (auto const & requests: fileRequests)
301
+ for (auto const & request: requests)
302
+ if (request == " evm.bytecode.ethdebug" || request == " evm.deployedBytecode.ethdebug" )
303
+ return true ;
304
+
305
+ return false ;
306
+ }
307
+
286
308
// / @returns The set of selected contracts, along with their compiler pipeline configuration, based
287
309
// / on outputs requested in the JSON. Translates wildcards to the ones understood by CompilerStack.
288
310
// / Note that as an exception, '*' does not yet match "ir", "irAst", "irOptimized" or "irOptimizedAst".
@@ -378,6 +400,7 @@ Json collectEVMObject(
378
400
langutil::EVMVersion _evmVersion,
379
401
evmasm::LinkerObject const & _object,
380
402
std::string const * _sourceMap,
403
+ Json _ethdebug,
381
404
Json _generatedSources,
382
405
bool _runtimeObject,
383
406
std::function<bool (std::string)> const & _artifactRequested
@@ -398,6 +421,9 @@ Json collectEVMObject(
398
421
output[" immutableReferences" ] = formatImmutableReferences (_object.immutableReferences );
399
422
if (_artifactRequested (" generatedSources" ))
400
423
output[" generatedSources" ] = std::move (_generatedSources);
424
+ if (_artifactRequested (" ethdebug" ))
425
+ output[" ethdebug" ] = std::move (_ethdebug);
426
+
401
427
return output;
402
428
}
403
429
@@ -1179,6 +1205,35 @@ std::variant<StandardCompiler::InputsAndSettings, Json> StandardCompiler::parseI
1179
1205
ret.modelCheckerSettings .timeout = modelCheckerSettings[" timeout" ].get <Json::number_unsigned_t >();
1180
1206
}
1181
1207
1208
+ if ((ret.debugInfoSelection .has_value () && ret.debugInfoSelection ->ethdebug ) || isEthdebugRequested (ret.outputSelection ))
1209
+ {
1210
+ if (ret.language != " Solidity" && ret.language != " Yul" )
1211
+ return formatFatalError (Error::Type::FatalError, " 'settings.debug.debugInfo' 'ethdebug' is only supported for languages 'Solidity' and 'Yul'." );
1212
+ }
1213
+
1214
+ if (isEthdebugRequested (ret.outputSelection ))
1215
+ {
1216
+ if (ret.language == " Solidity" && !ret.viaIR )
1217
+ return formatFatalError (Error::Type::FatalError, " 'evm.bytecode.ethdebug' or 'evm.deployedBytecode.ethdebug' can only be selected as output, if 'viaIR' was set." );
1218
+
1219
+ if (!ret.debugInfoSelection .has_value ())
1220
+ {
1221
+ ret.debugInfoSelection = DebugInfoSelection::Default ();
1222
+ ret.debugInfoSelection ->enable (" ethdebug" );
1223
+ }
1224
+ else
1225
+ {
1226
+ if (!ret.debugInfoSelection ->ethdebug && ret.language == " Solidity" )
1227
+ return formatFatalError (Error::Type::FatalError, " 'ethdebug' needs to be enabled in 'settings.debug.debugInfo', if 'evm.bytecode.ethdebug' or 'evm.deployedBytecode.ethdebug' was selected as output." );
1228
+ }
1229
+ }
1230
+
1231
+ if (
1232
+ ret.debugInfoSelection .has_value () && ret.debugInfoSelection ->ethdebug && ret.language == " Solidity" &&
1233
+ !pipelineConfig (ret.outputSelection )[" " ][" " ].irCodegen && !isEthdebugRequested (ret.outputSelection )
1234
+ )
1235
+ return formatFatalError (Error::Type::FatalError, " 'settings.debug.debugInfo' can only include 'ethdebug', if output 'ir', 'irOptimized', 'evm.bytecode.ethdebug' or 'evm.deployedBytecode.ethdebug' was selected." );
1236
+
1182
1237
return {std::move (ret)};
1183
1238
}
1184
1239
@@ -1254,6 +1309,7 @@ Json StandardCompiler::importEVMAssembly(StandardCompiler::InputsAndSettings _in
1254
1309
_inputsAndSettings.evmVersion ,
1255
1310
stack.object (sourceName),
1256
1311
stack.sourceMapping (sourceName),
1312
+ stack.ethdebug (sourceName, false ),
1257
1313
{},
1258
1314
false , // _runtimeObject
1259
1315
[&](std::string const & _element) {
@@ -1278,6 +1334,7 @@ Json StandardCompiler::importEVMAssembly(StandardCompiler::InputsAndSettings _in
1278
1334
_inputsAndSettings.evmVersion ,
1279
1335
stack.runtimeObject (sourceName),
1280
1336
stack.runtimeSourceMapping (sourceName),
1337
+ stack.ethdebug (sourceName, true ),
1281
1338
{},
1282
1339
true , // _runtimeObject
1283
1340
[&](std::string const & _element) {
@@ -1299,6 +1356,7 @@ Json StandardCompiler::importEVMAssembly(StandardCompiler::InputsAndSettings _in
1299
1356
contractsOutput[sourceName][" " ] = contractData;
1300
1357
Json output;
1301
1358
output[" contracts" ] = contractsOutput;
1359
+
1302
1360
return util::removeNullMembers (output);
1303
1361
}
1304
1362
@@ -1514,6 +1572,7 @@ Json StandardCompiler::compileSolidity(StandardCompiler::InputsAndSettings _inpu
1514
1572
_inputsAndSettings.evmVersion ,
1515
1573
compilerStack.object (contractName),
1516
1574
compilerStack.sourceMapping (contractName),
1575
+ compilerStack.ethdebug (contractName, false ),
1517
1576
compilerStack.generatedSources (contractName),
1518
1577
false ,
1519
1578
[&](std::string const & _element) { return isArtifactRequested (
@@ -1536,6 +1595,7 @@ Json StandardCompiler::compileSolidity(StandardCompiler::InputsAndSettings _inpu
1536
1595
_inputsAndSettings.evmVersion ,
1537
1596
compilerStack.runtimeObject (contractName),
1538
1597
compilerStack.runtimeSourceMapping (contractName),
1598
+ compilerStack.ethdebug (contractName, true ),
1539
1599
compilerStack.generatedSources (contractName, true ),
1540
1600
true ,
1541
1601
[&](std::string const & _element) { return isArtifactRequested (
@@ -1560,6 +1620,9 @@ Json StandardCompiler::compileSolidity(StandardCompiler::InputsAndSettings _inpu
1560
1620
if (!contractsOutput.empty ())
1561
1621
output[" contracts" ] = contractsOutput;
1562
1622
1623
+ if (isEthdebugRequested (_inputsAndSettings.outputSelection ))
1624
+ output[" ethdebug" ] = compilerStack.ethdebug ();
1625
+
1563
1626
return output;
1564
1627
}
1565
1628
@@ -1608,6 +1671,19 @@ Json StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings)
1608
1671
return output;
1609
1672
}
1610
1673
1674
+ for (auto const & fileRequests: _inputsAndSettings.outputSelection )
1675
+ for (auto const & requests: fileRequests)
1676
+ for (auto const & request: requests)
1677
+ if (request == " evm.deployedBytecode.ethdebug" )
1678
+ {
1679
+ output[" errors" ].emplace_back (formatError (
1680
+ Error::Type::JSONError,
1681
+ " general" ,
1682
+ " \" evm.deployedBytecode.ethdebug\" cannot be used for Yul."
1683
+ ));
1684
+ return output;
1685
+ }
1686
+
1611
1687
YulStack stack (
1612
1688
_inputsAndSettings.evmVersion ,
1613
1689
_inputsAndSettings.eofVersion ,
@@ -1679,6 +1755,7 @@ Json StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings)
1679
1755
_inputsAndSettings.evmVersion ,
1680
1756
*o.bytecode ,
1681
1757
o.sourceMappings .get (),
1758
+ o.ethdebug ,
1682
1759
Json::array (),
1683
1760
isDeployed,
1684
1761
[&, kind = kind](std::string const & _element) { return isArtifactRequested (
0 commit comments