6

我正在使用 Windbg(带有 sos 扩展名)并尝试调试崩溃的应用程序。我能够转储引发异常的调用的 IL,并且通过检查代码,如果我可以转储评估堆栈的内容,我似乎可以获得所需的信息。可以用 WinDbg & sos 做什么吗?

这是我所做的:

  1. 启动 WinDbg
  2. 附加到崩溃的进程
  3. loadby sos mscorwks (加载 sos 扩展)
  4. !token2ee theModuleName 0600009a (其中theModuleName是我正在调试的应用程序(和程序集)的名称,9a是 Windows 错误报告工具报告的崩溃方法的方法偏移量。我得到了这个输出:

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

  5. !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 处的局部变量。

    PS 当我尝试调用!clrstack -a时,我收到一条消息:无法遍历托管堆栈。当前线程可能不是托管线程。您可以运行 !threads 以获取进程中的托管线程列表。

谢谢!

4

2 回答 2

6

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

!threads将显示应用程序中的所有托管线程。~Xs一旦确定,您可以使用其中 X 是线程的 WinDbg id来切换线程。

!clrstack将向您显示堆栈跟踪。如果您想要本地人和/或参数,请使用-l/ -p(或-a两者都使用)。

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

如果 local/parameters 不能满足您的需求,请使用!dso来显示推送到堆栈上的对象。

于 2009-02-06T23:38:40.290 回答
2

哇,这很难,没有真正的转储可以戳穿。:-)

这里有几个问题..然后我将添加一个之前未在上面的答案中列出的命令..

问题:

  1. 您确定您正在捕获第一个异常,而不仅仅是最后一个未处理并破坏流程的异常吗?

  2. 你能看一下引发异常的线程的本机调用堆栈吗?
    注意:应该调用 RaiseException() 或访问冲突。

  3. 当心与您的代码完全无关的异步异常,并且可以进入并将您弹出到一个 catch 块中......或更糟(Thread.AbortException/System.OutofMemoryException 和...... StackOverflowException :-)

为了进一步挖掘,您在故障线程上运行!dumpstack。输出并不准确,但是它确实在遍历线程调用堆栈方面做得非常出色,您可能会幸运地看到一个引用 .cxr 异常的@符号和.exr 在消息中。如果你这样做了,那么你可以运行.cxr -cxr-address并查看异常链中的第一个异常是什么。

要点:虽然我可能会绕开这个问题,但如果调用 WER 的异常未处理并取消进程,您可能希望记录初始调用堆栈或将先前的异常添加为内部异常,以便确定根本原因.

谢谢,亚伦

于 2009-02-22T00:44:46.017 回答