【问题标题】:Determine line number of InnerException from minidump using WinDbg使用 WinDbg 从 minidump 确定 InnerException 的行号
【发布时间】:2012-10-02 14:53:46
【问题描述】:

我正在尝试从转储中追踪 NullReferenceException。 NullReferenceException 不是崩溃异常,而是崩溃异常是带有 InnerException 的 TargetInvocationException,即 NullReferenceException。

我正在使用带有 SOS 的 Windbg,我使用命令 analyze -v,这给了我 NullReferenceException 的调用堆栈:

EXCEPTION_OBJECT: !pe f6cb150
Exception object: 000000000f6cb150
Exception type:   System.NullReferenceException
Message:          Object reference not set to an instance of an object.
InnerException:   <none>
StackTrace (generated):
SP               IP               Function
000000002CD9D8C0 000007FF01E7C639 MyDll!DoSomething2()+0xe99
000000002CD9DBE0 000007FF01E7B11D MyDll!DoSomething1()+0x43d
000000002CD9DD20 000007FF01E7AB11 MyDll!WorkerDoWork(System.Object, System.ComponentModel.DoWorkEventArgs)+0x51
000000002CD9DD80 000007FEEA68A0F2 System_ni!System.ComponentModel.BackgroundWorker.WorkerThreadStart(System.Object)+0x62

注意,我得到的方法名称带有字节偏移,但没有行号。 DoSomething2 是一个很大的函数,所以 NullReferenceException 发生在哪里并不明显。

我尝试按照 Tess Ferrandez 博客中的说明进行操作:

.Net exceptions - Tracking down where in the code the exceptions occurred

但我在尝试使用带有 DoSomething2 的 IP 的 !ip2md 确定方法 DoSomething2 的方法描述符时遇到了困难:7FF01E7C639:

> !ip2md 7FF01E7C639
Failed to request MethodData, not in JIT code range

请注意,!ip2md 命令在发生 TargetInvocationException 的方法的 IP 上成功。

问题

我可以从哪里开始缩小 DoSomething2 中崩溃的行? 请注意,我无法重现崩溃,所以我只有这个(和几个重复的)转储。

补充说明

  • .NET 4.0
  • Windbg 版本:6.12.0002.633 AMD64
  • 我是 Windbg 的新手:所以信息越多越好

编辑 1

当我没有正确设置符号时,我会得到以下信息:

STACK_TEXT:  
00000000`2cd9d8c0 00000000`ffffffff MyDll!Unknown_0xe99+0xe99
00000000`2cd9dbe0 00000000`ffffffff MyDll!Unknown_0x43d+0x43d
00000000`2cd9dd20 00000000`ffffffff MyDll!Unknown_0x51+0x51
00000000`2cd9dd80 00000000`ffffffff system_ni!    System.ComponentModel.BackgroundWorker.WorkerThreadStart+0x62

当我将它设置为指向我的符号服务器并打开 !sym 噪声时,它似乎可以正确加载符号:

0:000> ld MyDll
DBGHELP: C:\Program Files\Debugging Tools for Windows (x64)\MyDll.dll - file not found
SYMSRV:  c:\symbols\MyDll.dll\4F3D6F4B154000\MyDll.dll not found
SYMSRV:  http://msdl.microsoft.com/download/symbols/MyDll.dll/4F3D6F4B154000/MyDll.dll not found
SYMSRV:  \\mysymbolserver\store\Mydll.dll\4F3D6F4B154000\file.ptr
SYMSRV:  MyDll.dl_ from \\mysymbolserver\store: uncompressed
DBGHELP: c:\symbols\MyDll.dll\4F3D6F4B154000\MyDll.dll - OK
DBGENG:  c:\symbols\MyDll.dll\4F3D6F4B154000\MyDll.dll - Mapped image memory
SYMSRV:  c:\symbols\MyDll.pdb\8AFC2BE7529A41289FA9FBCEDB6836161\Mydll.pdb not found
SYMSRV:  http://msdl.microsoft.com/download/symbols/Mydll.pdb/8AFC2BE7529A41289FA9FBCEDB6836161/MyDll.pdb not found
SYMSRV:  \\mysymbolserver\store\MyDll.pdb\8AFC2BE7529A41289FA9FBCEDB6836161\file.ptr
SYMSRV:  MyDll.pd_ from \\mysymbolserver\store: uncompressed
DBGHELP: MyDll - private symbols & lines 
     c:\symbols\MyDll.pdb\8AFC2BE7529A41289FA9FBCEDB6836161\MyDll.pdb
Symbols loaded for MyDll

编辑 2

我尝试使用 !name2ee 如下:

0:000> !name2ee MyDll!MyType.DoSomething2
Module:      000007ff004995b8
Assembly:    Autodesk.DataManagement.Client.Framework.Vault.dll
<invalid module token>

所以,没有运气。但后来我几乎似乎得到了这个:

0:000> !name2ee MyDll.dll!MyNamespace.MyType
Module:      000007ff004995b8
Assembly:    MyDll.dll
Token:       000000000200008c
MethodTable: 000007ff01b2e258
EEClass:     000007ff01b415e0
Name:        MyNamespace.MyType

0:000> !dumpmt -md 7ff01b2e258
EEClass:      000007ff01b415e0
Module:       000007ff004995b8
Name:         MyNamspace.MyType
mdToken:      000000000200008c
File:         C:\Program Files\MyCompany\MyProduct\Bin\MyDll.dll
BaseSize:        0x30
ComponentSize:   0x0
Slots in VTable: 31
Number of IFaces in IFaceMap: 2
--------------------------------------
MethodDesc Table
           Entry       MethodDesc      JIT Name
000007feeb31a2c0 0000000000000000     NONE 0000000000000000 is not a MethodDesc
000007feeb3689f0 0000000000000000     NONE 0000000000000000 is not a MethodDesc
000007feeb3688c0 0000000000000000     NONE 0000000000000000 is not a MethodDesc
000007feeb353440 0000000000000000     NONE 0000000000000000 is not a MethodDesc
000007ff01b01300 0000000000000000     NONE 0000000000000000 is not a MethodDesc
000007ff01e89140 0000000000000000     NONE 0000000000000000 is not a MethodDesc
000007ff01b9c080 0000000000000000     NONE 0000000000000000 is not a MethodDesc
000007ff01f45f40 0000000000000000     NONE 0000000000000000 is not a MethodDesc
000007ff01a9b358 000007ff01b2e128     NONE MyType.DoSomething3()
000007ff01a9b360 000007ff01b2e130     NONE MyType.DoSomething4()
000007ff01a9b368 000007ff01b2e138     NONE MyType.DoSomething5()
000007ff01e79800 0000000000000000     NONE 0000000000000000 is not a MethodDesc
000007ff020fea80 0000000000000000     NONE 0000000000000000 is not a MethodDesc
000007ff01a9b3b0 000007ff01b2e1b0     NONE MyType.DoSomething6()
000007ff01a9b3b8 000007ff01b2e1b8     NONE MyType.DoSomething7()
000007ff01a9b328 000007ff01b2e0f0     NONE MyType..ctor()
000007ff01b01280 0000000000000000     NONE 0000000000000000 is not a MethodDesc
000007ff01e7a810 0000000000000000     NONE 0000000000000000 is not a MethodDesc
000007ff01e7aac0 0000000000000000     NONE 0000000000000000 is not a MethodDesc
000007ff01e83240 0000000000000000     NONE 0000000000000000 is not a MethodDesc
000007ff01f19520 000007ff01b2e178      JIT MyType.RunWorkerCompleted(System.Object, System.ComponentModel.RunWorkerCompletedEventArgs)
000007ff01e7ace0 0000000000000000      JIT 0000000000000000 is not a MethodDesc
000007ff01e7b7a0 0000000000000000      JIT 0000000000000000 is not a MethodDesc
000007ff01e7b710 0000000000000000      JIT 0000000000000000 is not a MethodDesc
000007ff01e7d2b0 0000000000000000      JIT 0000000000000000 is not a MethodDesc
000007ff01b015f0 0000000000000000      JIT 0000000000000000 is not a MethodDesc
000007ff01b88ce0 0000000000000000      JIT 0000000000000000 is not a MethodDesc
000007ff01a9b3e0 000007ff01b2e200     NONE MyType.DoSomething8()
000007ff01b921e0 0000000000000000     NONE 0000000000000000 is not a MethodDesc
000007ff01b933b0 0000000000000000     NONE 0000000000000000 is not a MethodDesc
000007ff01b93870 0000000000000000     NONE 0000000000000000 is not a MethodDesc

我猜所有丢失的条目(那些用“不是 MethodDesc”列出的)都是因为这不是一个完整的小型转储。对吗?

【问题讨论】:

  • 您不需要符号来获取托管堆栈跟踪。但是,您通常需要一个完整的转储。这是进程的完整转储还是小型转储?
  • 是的,缺少条目很可能是由于转储未满造成的。

标签: c# exception windbg sos


【解决方案1】:

WinDbg 似乎没有为您的 DLL 提取符号。您可以通过设置符号路径并根据需要使用!sym noisy 进行故障排除来查看该问题。

我不能说为什么!ip2md 在这种情况下不起作用,但是还有其他方法可以获取DoSomething2 的代码。在方法名称上尝试!name2ee,例如!name2ee *!TypeName.DoSomething2 或者您可以通过像 !name2ee *!Namespace.TypeName 这样的类型本身获取它,然后在您从 !name2ee 获得的方法表上使用 !dumpmt -md &lt;method table&gt;

获得代码后,!u 命令可以向您显示带有 .NET 注释的汇编代码转储。通过使用异常的偏移量,您可以确定 NullReferenceException 的性质。

【讨论】:

  • 谢谢!我以为我确实加载了符号。没有符号,我会得到不同的输出(请参阅我在问题中的编辑)。我会尽快尝试其他方法并报告。
  • 如果转储不是完整转储,大多数 .NET 调试命令将不起作用。我想知道这里是不是这样?
  • @SteveJohnson,有没有办法让我判断这是否是一个完整的转储? !ip2md 命令确实可以获取最终崩溃发生的函数的方法描述符。
  • 运行 ||命令。我得到:0:000> || . 0 完整内存用户迷你转储:D:\xyz.DMP
  • 好的,我明白了:。 0 用户迷你转储:C:\mydump.dmp
【解决方案2】:

您可能正在使用剥离的 PDB 文件,这是为发布版本中的项目生成的默认文件。从此类文件中删除所有文件和行号信息。

切换到 Release 配置,Project + Properties,Build 选项卡,Advanced,Debug Info = "full"。

这是故意的,行号信息对于发布版本不是很准确。抖动优化器会移动代码,因此您需要记住显示的行号是一个近似值。

【讨论】:

    【解决方案3】:

    在上面的评论中,您提到 ||命令产生“用户迷你转储”。为了正确调试 .NET 代码,您需要一个完整转储,这将指示 || 中的“完整内存用户小型转储”。命令。我认为这是你的问题。如果无法访问完整的加载程序堆,就无法将代码地址映射回 .NET 方法,因此您无法获得堆栈跟踪。如果您可以重现此问题,请捕获完整转储。您可以使用 ADPlus、ProcDump 或 DebugDiag 在崩溃时捕获转储。

    【讨论】:

      猜你喜欢
      • 2014-10-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-24
      • 1970-01-01
      • 2017-09-03
      • 2013-10-10
      • 1970-01-01
      相关资源
      最近更新 更多