如何在匿名方法中打破WinDbg?

Ric*_*erg 8 c# debugging windbg anonymous-methods sos

标题有点说明了一切.通常的SOS命令!没有名字,bpmd没有很多好处.

我有一些想法:

  • 转储每个方法,然后在找到相应的MethodDesc时 使用!bpmd -md
    • 从我所知道的,在现实世界的使用中不实用.即使我写了一个宏来限制转储到匿名类型/方法,也没有明显的方法来区分它们.
  • 使用Reflector转储MSIL名称
    • 在处理动态程序集和/或Reflection.Emit时没有帮助.Visual Studio无法在这种情况下阅读本地变量,这是我首先转向Windbg的全部原因......
  • 在VS中设置断点,等待它击中,然后使用非侵入性技巧更改为Windbg
    • 试图从VS分离导致它挂起(与应用程序一起).我认为这是因为托管调试器是通过线程注入而不是标准"硬"调试器的"软"调试器.或者它可能只是Silverlight特有的VS错误(几乎不是我遇到过的第一个).
  • 在已知调用匿名方法的其他位置设置断点,然后单步进入
    • 我的备份计划,但如果这个Q&A揭示了一个更好的方法,我宁愿不诉诸它

Bri*_*sen 9

匿名方法并不是真正的匿名方法.它隐藏在编译器生成的名称后面.

考虑这个小例子:

Func<int, int> a = (x) => x + 1;

Console.WriteLine(a.Invoke(1));
Run Code Online (Sandbox Code Playgroud)

要查找返回值,我们需要找到方法实现的名称.为此,我们需要找到周围方法的MethodDesc.在这个例子中,它是Main(),所以:

0:000> !name2ee * TestBench.Program.Main
Module: 6db11000 (mscorlib.dll)
--------------------------------------
Module: 00162c5c (TestBench.exe)
Token: 0x06000001
MethodDesc: 00163010
Name: TestBench.Program.Main()
JITTED Code Address: 001e0070
Run Code Online (Sandbox Code Playgroud)

通过MethodDesc,我们可以转储IL Main()

0:000> !dumpil 00163010
ilAddr = 003f2068
IL_0000: nop 
IL_0001: ldstr "press enter"
IL_0006: call System.Console::WriteLine     
IL_000b: nop 
IL_000c: call System.Console::ReadLine 
IL_0011: pop 
IL_0012: ldsfld TestBench.Program::CS$<>9__CachedAnonymousMethodDelegate1
IL_0017: brtrue.s IL_002c
IL_0019: ldnull 
IL_001a: ldftn TestBench.Program::<Main>b__0
IL_0020: newobj class [System.Core]System.Func`2<int32,int32>::.ctor 
IL_0025: stsfld TestBench.Program::CS$<>9__CachedAnonymousMethodDelegate1
IL_002a: br.s IL_002c
IL_002c: ldsfld TestBench.Program::CS$<>9__CachedAnonymousMethodDelegate1
IL_0031: stloc.0 
IL_0032: ldloc.0 
IL_0033: ldc.i4.1 
IL_0034: callvirt class [System.Core]System.Func`2<int32,int32>::Invoke 
IL_0039: call System.Console::WriteLine 
IL_003e: nop 
IL_003f: ret 
Run Code Online (Sandbox Code Playgroud)

请注意有趣的名字.它们是生成委托类型和实际方法的名称.该方法被调用<Main>b__0.我们来看看方法:

0:000> !name2ee * TestBench.Program.<Main>b__0
Module: 6db11000 (mscorlib.dll)
--------------------------------------
Module: 00152c5c (TestBench.exe)
Token: 0x06000003
MethodDesc: 00153024
Name: TestBench.Program.<Main>b__0(Int32)
Not JITTED yet. Use !bpmd -md 00153024 to break on run. 
Run Code Online (Sandbox Code Playgroud)

你有它.MethodDesc是00153024,正如评论所说,您可以使用!bpmd使用MethodDesc设置断点.