如何查看友好的 .NET 调用堆栈?

Posted

技术标签:

【中文标题】如何查看友好的 .NET 调用堆栈?【英文标题】:How to see friendly .NET call stacks? 【发布时间】:2017-08-05 04:16:21 【问题描述】:

我有一个内存转储。我可以获得正常的调用堆栈(带行号) 当我使用 Debug Diag 分析转储时,我在线程 62 上得到了这个调用堆栈。

.NET Call Stack

[[HelperMethodFrame_1OBJ] (System.Threading.WaitHandle.WaitOneNative)] System.Threading.WaitHandle.WaitOneNative(System.Runtime.InteropServices.SafeHandle, UInt32, Boolean, Boolean) 
mscorlib_ni!System.Threading.WaitHandle.InternalWaitOne(System.Runtime.InteropServices.SafeHandle, Int64, Boolean, Boolean)+21 
mscorlib_ni!System.Threading.WaitHandle.WaitOne(Int32, Boolean)+31 
CaptureServices.GenericInfrastructure.ExportLogic.ChannelsThread.ChannelsStateThread()+bb 
mscorlib_ni!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)+15e 
mscorlib_ni!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)+17 
mscorlib_ni!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)+52 
mscorlib_ni!System.Threading.ThreadHelper.ThreadStart()+52 
[[GCFrame]] 
[[DebuggerU2MCatchHandlerFrame]] 

据我了解,.NET 有一些机制可以显示人类可读的名称而不是地址。现在我想要 WinDbg 中的这一行:

CaptureUtilities.AudioProcessing.APProcessorThread.IterateAPStreamProcessorQueue()+49 

我打开 WinDbg 并加载转储。我执行~62 k 并得到

Child-SP          RetAddr           Call Site
00000016`4965e0c8 00007ffc`b59113ed ntdll!NtWaitForMultipleObjects+0xa
00000016`4965e0d0 00007ffc`abde77be KERNELBASE!WaitForMultipleObjectsEx+0xe1
00000016`4965e3b0 00007ffc`abde7658 clr!WaitForMultipleObjectsEx_SO_TOLERANT+0x62
00000016`4965e410 00007ffc`abde7451 clr!Thread::DoAppropriateWaitWorker+0x1e4
00000016`4965e510 00007ffc`abdebd15 clr!Thread::DoAppropriateWait+0x7d
00000016`4965e590 00007ffc`a94ecdf1 clr!WaitHandleNative::CorWaitOneNative+0x165
00000016`4965e7c0 00007ffc`a94ecdc1 mscorlib_ni+0x48cdf1
00000016`4965e7f0 00007ffc`4cf2e97b mscorlib_ni+0x48cdc1
00000016`4965e830 00007ffc`a94e674e 0x00007ffc`4cf2e97b
00000016`4965e890 00007ffc`a94e65e7 mscorlib_ni+0x48674e
00000016`4965e960 00007ffc`a94e65a2 mscorlib_ni+0x4865e7
00000016`4965e990 00007ffc`a94ed1f2 mscorlib_ni+0x4865a2
00000016`4965e9e0 00007ffc`abc36a53 mscorlib_ni+0x48d1f2
00000016`4965ea20 00007ffc`abc36913 clr!CallDescrWorkerInternal+0x83

好的,据我了解是一样的。现在我们有

0x00007ffc`4cf2e97b

而不是

CaptureServices.GenericInfrastructure.ExportLogic.ChannelsThread.ChannelsStateThread()+bb 

所以我有微软调试符号,现在我需要加载我自己的符号来查看调用堆栈。 问题是 - 我需要为我的项目加载所有调试符号,还是只需要为包含 CaptureServices.GenericInfrastructure.ExportLogic 的 dll 调试符号? 或者也许我只需要加载我的调试符号的一部分来处理这个线程?

【问题讨论】:

你从哪里得到IterateAPStreamProcessorQueue?它不在调用堆栈中 【参考方案1】:

试试!sosex.mk。它提供了一个用户友好的堆栈跟踪,其中包含交错的托管帧和本机帧。我不认为这是一个象征问题。此外,当您有托管地址时,可以将其传递给 !sosex.mln 以查看其中的内容,但我认为您已经知道此命令。

【讨论】:

【参考方案2】:

k 命令与~62k 一样,是用于本机调用堆栈的命令。它确实显示了任何 .NET 内容(clr.dll 中的本机方法除外)。

要查看 .NET 堆栈,您需要为 WinDbg 加载 .NET 扩展:

.loadby sos clr

然后使用该扩展的命令查看 .NET 调用堆栈。先切换到线程 62

~62s
!clrstack
!dumpstack

恕我直言,这些命令会在需要时从 PDB 加载符号。如果您收到符号警告,请参阅How to fix symbols in WinDbg

【讨论】:

【参考方案3】:

您需要该函数所属的任何库的调试符号。

【讨论】:

就像,我什至没有看到混淆,如果你想要一个可执行文件的符号数据,你需要它的符号数据库(通常是 Windows 中的 .pdb)。是什么让你陷入了困境? 也许简单的例子会显示我的困惑。让我的项目有 3 个 DLL(A、D、C)我知道在这个线程上我卡在 A 的代码中。从 B 和 C 的代码调用的 A 中的这段代码是独立的(不是这个调用堆栈的一部分,而是其他调用堆栈)我需要查看调用堆栈 A、A+B、A+B+C 哪些 DLL? 您是否意识到这是针对 .NET 而不是本地代码的?它不像加载 PDB 文件那么简单。 WinDbg 无法自行调试 .NET。 @Thomas,WinDbg 能做什么或不能做什么无关紧要,调试符号在 Windows 中是通用的。如果 WinDbg 不能处理 JIT 代码,只需使用更好的调试器。但无论如何,请否决正确的答案。编辑:你也大错特错了,WinDbg 肯定可以处理托管调用堆栈。 @StepanLoginov,如果我理解正确,您想查看 A.dll 中的调用堆栈吗?然后您需要 A.dll 的调试符号(A.pdb,您可以在 Debug/Release 文件夹中找到它们)。

以上是关于如何查看友好的 .NET 调用堆栈?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 dtrace 查看调用堆栈

将 Charles Proxy 与 .NET Core Azure 站点一起使用 - 如何查看 API 调用?

Azure 门户:如何查看调用堆栈

linux应用中,在一个进程内如何获取本进程内其它线程的堆栈信息、

Linux 如何查看一个进程的堆栈

谁知道如何查看Windows下正在运行的程序堆栈,Linux可以用gdb,windows下该用啥