如何读取线程或调用堆栈的父线程或父函数

时间:2018-08-06 14:24:54

标签: .net visual-studio stack-overflow windbg dump

我正在尝试解密一个StackOverflowException crashdump。

调用堆栈,如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窗口中,没有看到该线程,指的是该线程。

有人有主意吗?
预先感谢

1 个答案:

答案 0 :(得分:2)

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

这可能是出于以下几个原因:

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

涉及.NET时,通常是第一个原因-这是JIT代码。 使用SOS debugger extension可以很容易地进行检查。

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

如果它是JIT的.NET代码,则您可能需要熟悉SOS扩展程序提供的other commands来调试问题。

Lieven Keersmaekers所述,您可以使用lm命令并查找已卸载的模块来检查已卸载的模块(原因2)。

您可以使用以下方法获得有关内存地址的一些常规信息: !address 0x00007ff`c2ea802cd。 如果页面没有PAGE_EXECUTE保护或类似保护措施,我希望调用堆栈是虚假的(原因3)。

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