调试器 StepInto 自动生成的代码和 JMC 问题
Debugger StepInto auto-generated code and JMC issue
我正在使用 MDBG 示例制作托管 .NET 调试器。
目前我正在为 StepInto 行为苦苦挣扎,而 StepOut 和 StepOver 似乎可以工作。
为了实现 Just-My-Code
步进,我在模块加载时调用 SetJMCStatus
。这很好用,让我只调试我的代码。
但是由于我将整个模块设置为 JMC,一些自动生成的代码开始发挥作用并破坏了单步执行。此类代码的示例可以是 auto-属性.
由于调试器正在执行 Il 指令,通过 step-into 我进入了自动生成的 get_propertyName
和 set_propertyName
方法,它们被标记为我的代码,因为它们是我的一部分模块。
为了将此类自动生成的代码与我的代码区分开来,我可以使用存在的调试符号,这些符号在自动生成的代码中是缺失的。然后我可以简单地将方法标记为不是我的代码以在单步执行期间跳过它。
问题是我在单步执行之前不知道哪些方法是自动生成的。当我单步执行一个没有调试符号的方法时可以将它标记为不是我的代码,但为时已晚 - 调试器在它不应该停止的地方停止了。
理论上我可以使用 IMetadataImport 遍历我的模块方法并在调试器启动时设置它们的 JMCStatus,但它似乎相当昂贵:
foreach (var methodToken in mdbgModule.Importer.EnumerateAllMethodTokens()) {
var func = mdbgModule.GetFunction(methodToken);
if (func.SymMethod == null)
func.CorFunction.JMCStatus = false;
}
如果我知道接下来要执行什么函数,那么我就可以设置它的状态并防止第一次进入自动生成的代码。
我坚持使用 MDBG 步进方法,不改变任何东西,只是在需要的地方调用 SetJMCStatus,所以我不确定提供任何代码是否有意义...如果是这样,我将编辑问题,只需添加评论!
非常感谢任何关于主题的建议!
此致,
Mike Stall hinted 在一个选项中,您可以为整个模块设置 JMC,然后当调试器步进器中断时,检查该方法是否可调试,如果不是,则禁用它的 JMC 状态并重新运行步进器。 (如果恢复步进器需要在再次进入之前退出,我不确定这是否会导致行为发生变化。)
您可以通过仅为具有可用 pdb 的模块设置 JMC 并通过为 classes/methods 禁用 JMC 并应用 [DebuggerNonUserCode]
来改进事情(也许 [DebuggerHidden] too). But rather than enumerating all the classes/methods and checking if they have the attribute, enumerate the custom attributes and work back (IMetaDataImport::EnumCustomAttributes with tkType set but not tk, then use IMetaDataImport::GetCustomAttributeProps 得到东西它适用于)。
如果在方法级别应用 [CompilerGenerated]
属性,您可能可以做类似的事情,但在 class 级别应用时会出现误报(编译器将其应用于迭代器和异步方法的状态机,但两者也可能有非生成代码)。
我正在使用 MDBG 示例制作托管 .NET 调试器。
目前我正在为 StepInto 行为苦苦挣扎,而 StepOut 和 StepOver 似乎可以工作。
为了实现 Just-My-Code
步进,我在模块加载时调用 SetJMCStatus
。这很好用,让我只调试我的代码。
但是由于我将整个模块设置为 JMC,一些自动生成的代码开始发挥作用并破坏了单步执行。此类代码的示例可以是 auto-属性.
由于调试器正在执行 Il 指令,通过 step-into 我进入了自动生成的 get_propertyName
和 set_propertyName
方法,它们被标记为我的代码,因为它们是我的一部分模块。
为了将此类自动生成的代码与我的代码区分开来,我可以使用存在的调试符号,这些符号在自动生成的代码中是缺失的。然后我可以简单地将方法标记为不是我的代码以在单步执行期间跳过它。
问题是我在单步执行之前不知道哪些方法是自动生成的。当我单步执行一个没有调试符号的方法时可以将它标记为不是我的代码,但为时已晚 - 调试器在它不应该停止的地方停止了。
理论上我可以使用 IMetadataImport 遍历我的模块方法并在调试器启动时设置它们的 JMCStatus,但它似乎相当昂贵:
foreach (var methodToken in mdbgModule.Importer.EnumerateAllMethodTokens()) {
var func = mdbgModule.GetFunction(methodToken);
if (func.SymMethod == null)
func.CorFunction.JMCStatus = false;
}
如果我知道接下来要执行什么函数,那么我就可以设置它的状态并防止第一次进入自动生成的代码。
我坚持使用 MDBG 步进方法,不改变任何东西,只是在需要的地方调用 SetJMCStatus,所以我不确定提供任何代码是否有意义...如果是这样,我将编辑问题,只需添加评论!
非常感谢任何关于主题的建议!
此致,
Mike Stall hinted 在一个选项中,您可以为整个模块设置 JMC,然后当调试器步进器中断时,检查该方法是否可调试,如果不是,则禁用它的 JMC 状态并重新运行步进器。 (如果恢复步进器需要在再次进入之前退出,我不确定这是否会导致行为发生变化。)
您可以通过仅为具有可用 pdb 的模块设置 JMC 并通过为 classes/methods 禁用 JMC 并应用 [DebuggerNonUserCode]
来改进事情(也许 [DebuggerHidden] too). But rather than enumerating all the classes/methods and checking if they have the attribute, enumerate the custom attributes and work back (IMetaDataImport::EnumCustomAttributes with tkType set but not tk, then use IMetaDataImport::GetCustomAttributeProps 得到东西它适用于)。
如果在方法级别应用 [CompilerGenerated]
属性,您可能可以做类似的事情,但在 class 级别应用时会出现误报(编译器将其应用于迭代器和异步方法的状态机,但两者也可能有非生成代码)。