首页 > 解决方案 > 如何读取父线程或线程或调用堆栈的父函数

问题描述

我正在尝试解密 StackOverflowException 故障转储。

调用堆栈,如 Visual Studio 中所示,如下所示:

ntdll.dll!RtlAllocateHeap()
[Inline Frame] combase.dll!CRetailMalloc_Alloc(IMalloc *) Line 640
combase.dll!CoTaskMemAlloc(unsigned __int64 stcb) Line 459
shell32.dll!CFSFolder::_InitFolder()
shell32.dll!CFSFolder::_Bind()
shell32.dll!CFSFolder::BindToObject()
shell32.dll!CRegFolder::BindToObject()
shell32.dll!CRegFolder::BindToObject()
shell32.dll!SHBindToObject()
shell32.dll!SHGetAttributesWithBindCtx()
shell32.dll!CShellLink::_IsTargetAnotherLink()
shell32.dll!CShellLink::_LoadIDList()
shell32.dll!CShellLink::_LoadFromStream()
shell32.dll!CShellLink::_LoadFromFile()
shell32.dll!CShellLink::Load(unsigned short const *,unsigned long)

这似乎不是很有趣。然而,在 Windbg 中,该命令~kb提供了更多信息:

0:040> ~kb
 # RetAddr           : Args to Child                                                           : Call Site
00 00007ffc`9d5f184a : 00000000`000001b0 00000000`00000002 00000000`00000002 00000000`1e492250 : ntdll!RtlAllocateHeap+0xd2
01 (Inline Function) : --------`-------- --------`-------- --------`-------- --------`-------- : combase!CRetailMalloc_Alloc+0x12 [d:\blue\com\combase\class\memapi.cxx @ 640] 
02 00007ffc`9e3dd4fe : 00000000`000001ad 00000000`00000000 00000000`000001ad 00007ffc`9fa30d67 : combase!CoTaskMemAlloc+0x3a [d:\blue\com\combase\class\memapi.cxx @ 459] 
03 00007ffc`9e3dcf2d : 00007ffc`9e561188 00000000`00000000 00000000`1a6053e0 00007ffc`9e561188 : shell32!CFSFolder::_InitFolder+0xd2
04 00007ffc`9e3dc685 : 00000000`1b803198 00007ffc`9e34203d 00000000`1a1a8580 00007ffc`9e3420c0 : shell32!CFSFolder::_Bind+0x9d1
05 00007ffc`9e3de676 : 00000000`1e7c4af4 00007ffc`9e561188 00000000`00000000 00007ffc`9fa30d67 : shell32!CFSFolder::BindToObject+0x664
06 00007ffc`9e3db94c : 00007ffc`9d5f1860 00430072`006f0046 00000000`00000003 ffffffff`fffffffe : shell32!CRegFolder::BindToObject+0x8bd
07 00007ffc`9e3dafda : 00000000`1e638820 00000000`00000000 00000000`1e7c4ae0 00007ffc`9e3dff07 : shell32!CRegFolder::BindToObject+0x687
08 00007ffc`9e40c041 : 00000000`00000000 00000000`1e80c2a0 00000000`00000000 00006567`8ccde5e5 : shell32!SHBindToObject+0x11d
09 00007ffc`9e408a7b : 00000000`1e638820 00000000`1e7c4ae0 00000000`00000001 00000000`00410000 : shell32!SHGetAttributesWithBindCtx+0x1a0
0a 00007ffc`9e40958f : 00000000`00000000 00000000`00000000 00000000`1a1a9630 00000000`00000000 : shell32!CShellLink::_IsTargetAnotherLink+0x7b
0b 00007ffc`9e40886b : 00000000`00000048 00000000`1e6389e0 00000000`00000000 00000000`1a1a96a0 : shell32!CShellLink::_LoadIDList+0x4b
0c 00007ffc`9e40b3f9 : 00000000`00000000 00000000`1e638820 00000000`00000000 00000000`80000000 : shell32!CShellLink::_LoadFromStream+0x2da
0d 00007ffc`9e40b359 : 00007ffc`8d49c3d9 00000000`1a1a99f8 00000000`00003201 00000000`1f95b1e4 : shell32!CShellLink::_LoadFromFile+0x8f
0e 00007ffc`2ea805f9 : 00000000`00000000 00000000`1a1a9d20 00000000`00000000 00000000`1f95b280 : shell32!CShellLink::Load+0x25
0f 00007ffc`2ea80479 : 00000000`1f95b280 00000000`00000000 00000000`1f95b1d8 00000000`00000000 : 0x00007ffc`2ea805f9
10 00007ffc`2ea8036c : 00000000`00000000 00000000`00000000 00000000`1f95b1b8 00000000`022c55e8 : 0x00007ffc`2ea80479
11 00007ffc`2ea802cd : 00000000`1f95b1d8 00007ffc`2e5d4a3c 00000000`00000000 00000000`022c55e8 : 0x00007ffc`2ea8036c
12 00007ffc`2ea7eae2 : 00000000`04233f90 00009ebd`de3821dd 00000000`00000003 00000000`00000003 : 0x00007ffc`2ea802cd
13 00007ffc`2ea7ee80 : 00000000`02619df0 00009ebd`de3821dd 00000000`1f9571c0 00000000`00000003 : 0x00007ffc`2ea7eae2
14 00007ffc`2ea7ee80 : 00000000`02619df0 00009ebd`de3821dd 00000000`1f94ec10 00000000`00000003 : 0x00007ffc`2ea7ee80
15 00007ffc`2ea7ee80 : 00000000`02619df0 00009ebd`de3821dd 00000000`1f946660 00000000`00000003 : 0x00007ffc`2ea7ee80
16 00007ffc`2ea7ee80 : 00000000`02619df0 00009ebd`de3821dd 00000000`1f93e0b0 00000000`00000003 : 0x00007ffc`2ea7ee80
17 00007ffc`2ea7ee80 : 00000000`02619df0 00009ebd`de3821dd 00000000`1f935b00 00000000`00000003 : 0x00007ffc`2ea7ee80
...
ff 00007ffc`2ea7ee80 : 00000000`02619df0 00009ebd`de3821dd 00000000`1f744808 00000000`00000003 : 0x00007ffc`2ea7ee80

这似乎与 StackOverflowException (调用堆栈中的调用过多)一致:确实,内存地址处的函数0x00007ffc'2ea7ee80——出于格式化原因,我用单引号替换了反引号——不断地调用自己。

现在的问题是:我怎么知道这是哪个函数或哪个是父线程?

至于 Windbg:当我单击最后一个条目(ff启用 DMS)时,我看到以下内容:

0:040> dx Debugger.Sessions[0].Processes[10912].Threads[5268].Stack.Frames[255].SwitchTo();dv /t /v
Debugger.Sessions[0].Processes[10912].Threads[5268].Stack.Frames[255].SwitchTo()
Unable to enumerate locals, Win32 error 0n318
Private symbols (symbols.pri) are required for locals.
Type ".hh dbgerr005" for details

供您参考:在 Visual Studio 的Parallel Stacks窗口中,我没有看到线程,指的是这个。

有人有想法吗?
提前致谢

标签: .netvisual-studiostack-overflowwindbgdump

解决方案


调用堆栈中的裸地址意味着代码不在任何加载的模块中。

这可能有几个原因:

  1. 代码可能是在运行时生成的,就像JIT一样。
  2. 代码可能驻留在已卸载的模块中。
  3. 调用堆栈可能已损坏。

当涉及到 .NET 时,通常是第一个原因——它是 JIT 代码。这很容易使用SOS 调试器扩展进行检查。

首先使用 加载扩展,.loadby sos clr然后使用 . 检查相关指令指针或返回地址!ip2md 0x00007ff`c2ea802cd

如果它是 JIT 的 .NET 代码,那么您可能需要熟悉SOS 扩展提供的其他命令来调试问题。

正如Lieven Keersmaekers所提到的,您可以使用命令检查未加载的模块(原因 #2)lm并查找未加载的模块。

您可以使用以下命令获取有关内存地址的一些一般信息 !address 0x00007ff`c2ea802cd:如果页面没有PAGE_EXECUTE保护或类似的东西,我希望调用堆栈是伪造的(原因#3)。

注意:周围还有其他 JIT 运行时。它们在虚拟机、脚本语言甚至一些库(如正则表达式引擎)中很常见。这些运行时往往不提供调试器扩展,因此,如果您怀疑正在使用一个,您可能必须为该特定运行时寻找工具。


推荐阅读