Windbg Crash转储堆栈跟踪保持每个功能

时间:2015-06-09 04:23:37

标签: windbg

所以我有一个崩溃转储,并使用WinDbg,我能够获得堆栈跟踪。但是,它似乎正在跳过其他所有功能。例如,如果实际代码是:

void a()
{
  b();
}
void b()
{
  c();
}
void c(){}

堆栈跟踪在堆栈框架中有a和c,而不是b。这是预期的行为吗?我能做些什么来查看整个堆栈跟踪?我使用命令“kn”来查看堆栈跟踪。

2 个答案:

答案 0 :(得分:1)

编译器可以优化代码。一种优化是内联方法,以便删除callret语句以及与之相关的所有内容(pushpop等。

出于演示目的,我在您的代码中添加了std::cout语句,我们可以识别这些语句,以便现在完整的代码可以读取

#include "stdafx.h"
#include <iostream>

void c()
{
    std::cout <<  "Hello world";
}

void b()
{
    c();
}

void a()
{
    b();
}

int _tmain(int argc, _TCHAR* argv[])
{
    a();
    return 0;
}

调试版本

中的演练

在典型的调试版本中,没有优化,您可以看到这些方法。要按照示例,首先启动WinDbg并通过文件/打开可执行文件... 运行可执行文件。

0:000> .symfix e:\debug\symbols

0:000> lm
start    end        module name
010d0000 010f3000   OptimizedInlined   (deferred)             
...

0:000> ld OptimizedInlined
Symbols loaded for OptimizedInlined

0:000> x OptimizedInlined!c
010e50c0          OptimizedInlined!c (void)

0:000> bp OptimizedInlined!c

0:000> bl
 0 e 010e50c0     0001 (0001)  0:**** OptimizedInlined!c

 0:000> g
Breakpoint 0 hit
eax=cccccccc ebx=7efde000 ecx=00000000 edx=00000001 esi=00000000 edi=003ffa00
eip=010e50c0 esp=003ff930 ebp=003ffa00 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
OptimizedInlined!c:
010e50c0 55              push    ebp

0:000> u eip L18
OptimizedInlined!c [e:\...\optimizedinlined.cpp @ 8]:
010e50c0 55              push    ebp
010e50c1 8bec            mov     ebp,esp
010e50c3 81ecc0000000    sub     esp,0C0h
010e50c9 53              push    ebx
010e50ca 56              push    esi
010e50cb 57              push    edi
010e50cc 8dbd40ffffff    lea     edi,[ebp-0C0h]
010e50d2 b930000000      mov     ecx,30h
010e50d7 b8cccccccc      mov     eax,0CCCCCCCCh
010e50dc f3ab            rep stos dword ptr es:[edi]
010e50de 6854ca0e01      push    offset OptimizedInlined!`string' (010eca54)
010e50e3 a1e4000f01      mov     eax,dword ptr [OptimizedInlined!_imp_?coutstd (010f00e4)]
010e50e8 50              push    eax
010e50e9 e8c9c1ffff      call    OptimizedInlined!ILT+690(??$?6U?$char_traitsDstdstdYAAAV?$basic_ostreamDU?$char_traitsDstd (010e12b7)
010e50ee 83c408          add     esp,8
010e50f1 5f              pop     edi
010e50f2 5e              pop     esi
010e50f3 5b              pop     ebx
010e50f4 81c4c0000000    add     esp,0C0h
010e50fa 3bec            cmp     ebp,esp
010e50fc e838c2ffff      call    OptimizedInlined!ILT+820(__RTC_CheckEsp) (010e1339)
010e5101 8be5            mov     esp,ebp
010e5103 5d              pop     ebp
010e5104 c3              ret

演练版本构建

在发布版本中,了解事情的变化。 WinDbg命令相同,但找不到方法c()b()a()std::cout方法调用已内联到wmain()

0:000> .symfix e:\debug\symbols

0:000> lm
start    end        module name
01360000 01367000   OptimizedInlined   (deferred)             
...

0:000> ld OptimizedInlined
Symbols loaded for OptimizedInlined

0:000> x OptimizedInlined!c

0:000> x OptimizedInlined!b

0:000> x OptimizedInlined!a

0:000> x OptimizedInlined!wmain
013612a0          OptimizedInlined!wmain (int, wchar_t **)

0:000> bp OptimizedInlined!wmain

0:000> bl
 0 e 013612a0     0001 (0001)  0:**** OptimizedInlined!wmain

 0:000> g
Breakpoint 0 hit
eax=6142f628 ebx=00000000 ecx=0087a6e8 edx=0019def8 esi=00000001 edi=00000000
eip=013612a0 esp=0042f8f8 ebp=0042f934 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
OptimizedInlined!wmain:
013612a0 8b0d44303601    mov     ecx,dword ptr [OptimizedInlined!_imp_?coutstd (01363044)] ds:002b:01363044={MSVCP120!std::cout (646c6198)}

0:000> u eip L4
OptimizedInlined!wmain [e:\...\optimizedinlined.cpp @ 23]:
013612a0 8b0d44303601    mov     ecx,dword ptr [OptimizedInlined!_imp_?coutstd (01363044)]
013612a6 e895040000      call    OptimizedInlined!std::operator<<<std::char_traits<char> > (01361740)
013612ab 33c0            xor     eax,eax
013612ad c3              ret

答案 1 :(得分:0)

正如Lieven已经提到的那样。这是编译器内联函数调用的情况。

我建议有两件事:

一个。如果您可以控制代码和构建环境。构建代码的非优化/调试版本。这将确保编译器不会单独内联函数。

湾在WinDBG中,您可以在View - &gt;下看到反汇编。拆卸。在这里,您可以看到函数b()的代码实际上位于a()下。 如果您对组装调试感到满意,您也可以获得本地的价值:)