【问题标题】:How to add a BreakPoint in C# code in WinDbg to view the value of local variable?如何在WinDbg的C#代码中添加BreakPoint来查看局部变量的值?
【发布时间】:2021-04-22 11:30:30
【问题描述】:

首先,是否可以在WinDbg.exe中通过添加SOS.dll来查看C#代码中的局部变量?

我使用.cordll -ve -u -l 将 SOS.dll 扩展加载到 WinDbg.exe 命令。机器是x​​86的。命令的结果是:

CLRDLL: Loaded DLL C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscordacwks.dll
Automatically loaded SOS Extension
CLR DLL status: Loaded DLL C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscordacwks.dll

我以为 SOS.dll 已成功加载。然后我想在代码中插入一个断点。通过测试F9似乎不行。所以我使用!bpmd命令插入断点,像这样:

0:004> !bpmd MyCode.exe Program.Main
PDB symbol for clr.dll not loaded
Found 1 methods in module 00714044...
MethodDesc = 00714d50
Setting breakpoint: bp 00760869 [Demo.Program.Main(System.String[])]
Adding pending breakpoints...
0:004> bl
     1 e Disable Clear  00760869     0001 (0001)  0:**** 

但结果是:

0:004> g
eax=00000024 ebx=00000001 ecx=00eff73c edx=77592740 esi=00000000 edi=77621a20
eip=77592740 esp=00eff73c ebp=00eff750 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
ntdll!KiFastSystemCallRet:
77592740 c3   

为什么没有命中断点?

希望有人能给我一些帮助!

【问题讨论】:

    标签: c# windbg breakpoints sos


    【解决方案1】:

    您没有发布完整的调试会话,但让我得出几个结论:

    1. 您在线程 4 上,这意味着您已经超出了初始断点。 (否则只有线程 0)
    2. !bpmd 立即生效,这意味着 Main 方法已经被 jitted 了。
    3. 由于 Main 方法已经被 jitted,所以它已经运行了。
    4. 由于 Main 方法已经运行,没有理由再次中断(除非您递归调用它的可能性很小)

    MRE

    在下面的例子中,我使用的是这个程序:

    class Program
    {
        static void Main()
        {
            int x = 5;
            var p = new Program();
            var i = x;
            Console.WriteLine("Debug now.");
            Console.ReadLine();
            // Ensure variables are needed
            Console.WriteLine(x+i+p.ToString()); 
        }
    }
    

    下次请自己提供这样的例子,这样我们就不需要自己拿出例子了。

    我在Release模式下编译,首选32位AnyCPU。

    我正在使用 WinDbg Preview 1.2103.01004.0 进行调试

    如何中断 Program.Main()?

    在 WinDbg 中启动应用程序,使其在初始断点处停止,如下所示:

    ntdll!LdrpDoDebuggerBreak+0x2b:
    77ee1a62 cc              int     3
    0:000> 
    

    我们需要 .NET SOS,所以

    0:000> sxe ld clrjit
    0:000> *** Wait until .NET is loaded
    0:000> g
    

    一段时间后,.NET 可用

    ModLoad: 72180000 7220a000   C:\Windows\Microsoft.NET\Framework\v4.0.30319\clrjit.dll
    [...]
    ntdll!NtMapViewOfSection+0xc:
    77ea2c0c c22800          ret     28h
    0:000>
    

    获取SOSEX extension 的副本并加载它。它简化了事情。

    0:000> .load D:\debug\ext\sosex\x86\sosex.dll
    0:000> 
    

    在 Program.Main 处设置断点:

    0:000> !mbm *!*Program.Main
    0:000> !mbl
    2 e : disable *!*PROGRAM.MAIN ILOffset=0: pass=1 oneshot=false thread=ANY
        SO67212401!SO67212401.Program.Main(string[]) (PENDING JIT)
    

    注意“待处理的 JIT”,这意味着 Main() 尚未运行。让我们拭目以待:

    0:000> g
    ModLoad: 77b10000 77ba6000   C:\WINDOWS\SysWOW64\OLEAUT32.dll
    Breakpoint: JIT notification received for method SO67212401.Program.Main(System.String[]) in AppDomain 01090fe8.
    Breakpoint set at SO67212401.Program.Main(System.String[]) in AppDomain 01090fe8.
    Breakpoint 2 hit
    

    我们在Main()!

    0:000> !clrstack
    OS Thread Id: 0x5614 (0)
    Child SP       IP Call Site
    00efed3c 01560853 SO67212401.Program.Main(System.String[]) [C:\...\SO67212401\Program.cs @ 9]
    00efeebc 7529f036 [GCFrame: 00efeebc] 
    

    如何查看局部变量?

    如果您使用!mt 和!mgu 单步执行代码,您将到达第二个Console.WriteLine() 调用:

    0:000> !clrstack
    OS Thread Id: 0x5614 (0)
    Child SP       IP Call Site
    00efed38 736d4f64 System.Console.WriteLine(System.String)
    00efed3c 015608a3 SO67212401.Program.Main(System.String[]) [C:\...\Program.cs @ 16]
    00efeebc 7529f036 [GCFrame: 00efeebc] 
    

    使用!clrstack -l -p查看局部变量和参数:

    0:000> !clrstack -l -p
    OS Thread Id: 0x5614 (0)
    Child SP       IP Call Site
    00efed38 736d4f64 System.Console.WriteLine(System.String)
        PARAMETERS:
            value (<CLR reg>) = 0x0309522c
    
    00efed3c 015608a3 SO67212401.Program.Main(System.String[]) [C:\...\Program.cs @ 16]
        PARAMETERS:
            args = <no data>
        LOCALS:
            <no data>
            <no data>
            0x00efed3c = 0x0000000a
    
    00efeebc 7529f036 [GCFrame: 00efeebc] 
    

    所以:只有1个局部变量,值为10。参数是

    0:000> !do 0309522c
    Name:        System.String
    [...]
    String:      10SO67212401.Program              <-- string value
    Fields:
    [...]
    

    由“10”和对象名称组成的串联字符串。

    在调试模式下试试这个,你会看到非优化版本的变量。

    【讨论】:

    • 您好 Thomas Weller,感谢您的帮助。下次我会提供代码。我使用 File 中的 Open Executable 选项打开了我的应用程序,并按照上述步骤操作。但是我没有打断点。
    • 当我使用命令0:000&gt; !mbm *!*Program.Main添加断点后输入“g”,结果如下:0:000&gt; g ModLoad: 76400000 76496000 C:\Windows\System32\OLEAUT32.dll eax=000000c0 ebx=01243ea8 ecx=013bfbc8 edx=775a2740 esi=01243ea8 edi=011cbe20 eip=775a2740 esp=013bfbc8 ebp=013bfd88 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ntdll!KiFastSystemCallRet: 775a2740 c3 ret
    • 我尝试输入 !clrstack 命令:0:003&gt; !clrstack PDB symbol for clr.dll not loaded OS Thread Id: 0x1a8 (3) Unable to walk the managed stack. The current thread is likely not a managed thread. You can run !threads to get a list of managed threads in the process Failed to start stack walk: 80070057
    • Release模式和Debug模式下的代码都显示上述结果。如果您对此有一些想法,非常高兴!
    • 对于最后一个(关于!clrstack),您在线程 3 上,而不是线程 0。在我看来,您已附加到进程而不是在调试器中运行它。
    猜你喜欢
    • 1970-01-01
    • 2013-07-17
    • 2011-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 2012-02-12
    相关资源
    最近更新 更多