Debugging 调试.NET CLR应用程序时,如何查看计算堆栈上的局部变量?

Debugging 调试.NET CLR应用程序时,如何查看计算堆栈上的局部变量?,debugging,stack,windbg,il,sos,Debugging,Stack,Windbg,Il,Sos,我正在使用Windbg(带sos扩展)并尝试调试崩溃的应用程序。我能够转储引发异常的调用的IL,通过检查代码,似乎可以获得所需的信息,如果我可以转储计算堆栈的内容。是否有可能使用WinDbg和sos执行以下操作 以下是我所做的: 启动WinDbg 附加到崩溃的进程 按sos mscorwks加载(加载sos扩展) !令牌2ee模块名0600009a(其中模块名是应用程序(和程序集)的名称 我正在调试的hat和9a是Windows错误报告工具报告的崩溃方法的方法偏移量。我得到以下输出: 模块:00

我正在使用Windbg(带sos扩展)并尝试调试崩溃的应用程序。我能够转储引发异常的调用的IL,通过检查代码,似乎可以获得所需的信息,如果我可以转储计算堆栈的内容。是否有可能使用WinDbg和sos执行以下操作

以下是我所做的:

  • 启动WinDbg
  • 附加到崩溃的进程
  • 按sos mscorwks加载(加载sos扩展)
  • !令牌2ee模块名0600009a(其中模块名是应用程序(和程序集)的名称 我正在调试的hat和9a是Windows错误报告工具报告的崩溃方法的方法偏移量。我得到以下输出:

    模块:000e2c3c(theApplicationName.exe)
    令牌:0x0600009a
    MethodDesc:000e67c8
    名称:MyNamespace.MyClassName.TheCallPritfn(MyOtherClass)
    JITTED代码地址:0081b1d0

  • !dumpil 00e67c8(它为所讨论的方法转储了IL)。这是输出:

    
    // ..
    // .. the previous code omitted for brevity
    .catch
    {
     IL_0071: stloc.0
     IL_0072: nop
     IL_0073: ldstr "Can't set CurrentServer property for: "
     IL_0078: ldarg.0
     IL_0079: ldfld MyNamespace.MyClassName::_currentServer
     IL_007e: brtrue.s IL_0087
     IL_0080: ldstr ""
     IL_0085: br.s IL_0092
     IL_0087: ldarg.0
     IL_0088: ldfld MyNamespace.MyClassName::_currentServer
     IL_008d: callvirt MyNamespace.MyOtherClass::get_Name
     IL_0092: call System.String::Concat
     IL_0097: ldloc.0
     IL_0098: newobj MyNamespace.MySpecialExceptionType::ctor
     IL_009d: throw
    } 
    
    问题是:是否有一种方法可以让我查看抛出异常之前在堆栈上推送了什么。如果我没有弄错的话,传递到异常构造函数的参数应该是计算堆栈上索引0处的局部变量

    另外,当我试图打电话给!clrstack-a时,我收到一条消息说: 无法遍历托管堆栈。当前线程可能不是托管线程。您可以运行!threads来获取进程中托管线程的列表


  • 谢谢!

    您需要识别并选择正确的线程。当前线程的id将显示在WinDbg提示符中

    !threads
    将显示应用程序中的所有托管线程。识别后,您可以使用
    ~Xs
    切换线程,其中X是线程的WinDbg id

    !clrstack
    将显示堆栈跟踪。如果需要局部变量和/或参数,请使用
    -l
    /
    -p
    (或
    -a

    您可以遍历所有线程,并使用
    ~*e!clrstack
    列出它们的调用堆栈


    如果本地/参数不能满足您的需要,请使用
    !dso
    显示推到堆栈上的对象。

    哇,如果没有实际的转储,这很难做到。:-) 这里有几个问题。。然后,我将添加一个在前面的答案中没有列出的命令

    问题:

  • 您确定捕获的是第一个异常,而不仅仅是最后一个未处理并中断进程的异常吗

  • 您可以看看引发异常的线程的本机调用堆栈吗
    注意:应该有对RaiseException()的调用或访问冲突

  • 小心那些与您的代码完全无关的异步异常,它们可能进入并将您弹出到catch块中。。。或者更糟(Thread.AbortException/System.OutofMemoryException和…StackOverflowException:-)

  • 要进一步挖掘,请跑步!故障线程上的dumpstack。。输出并不精确,但是它在遍历线程调用堆栈方面做了一项惊人的工作,您可能会幸运地看到一个@符号,该符号在消息中引用了带有.cxr和.exr的异常。如果这样做,则可以运行.cxr-cxr address,查看异常链中的第一个异常是什么。 要点:虽然我可能回避了这个问题,但如果调用的异常是未处理的并停止了进程,您可能希望记录初始调用堆栈或将以前的异常添加为内部异常,以便确定根本原因

    谢谢, 亚伦