如何在没有栈的情况下利用堆分析crash文件

我想大家平时拿到crash文件首先都会看看栈的调用情况,如果问题简单直接就能从栈上定位出问题。但是有的时候我们可能没有办法从栈上找到我们想要的信息,这个时候堆是一个很好的地方来找到我们需要的信息。下面的两个案例就是利用这个方法解决问题的。

 

1.        由于内存泄漏,程序终止。终止过程中,主线程栈已经析构,堆信息依然完整,这时出现crash

2.        对于打开优化编译选项的C++程序,当分析类的成员函数时,由于默认调用方式是__thiscallthis指针用ecx传递,所以当查看非顶端栈帧时,ecx值都不是正确的this指针值,所以对象状态很难找到。

 

 由于我的应用中都是ATL实现的COM对象,所以对象的首地址都是该对象的虚函数表,所以可以通过从遍历所有堆块,查找虚函数表的方式来找到对象的首地址或者对象的个数,从而找到相应的对象或者定位何种对象用光内存。下面就用一个例子来说明具体如何操作。

  

假设COM对象的声明如下:

 

class ATL_NO_VTABLE CFileStreamer : 

         public CComObjectRootEx<CComMultiThreadModel>,

         public CComCoClass<CFileStreamer, &CLSID_FileStreamer>,

         public IStream,

         public IFileStreamer,

         public ICompressionCtrl

{

...

};

 

那么函数对应的虚函数表如下:

 

 

 

使用如下的测试程序:

int _tmain(int argc, _TCHAR* argv[])

{

CComPtr<IFileStreamer> spIUnknown;

CoInitializeEx(NULL,COINIT_MULTITHREADED);

if( FAILED(CoCreateInstance(CLSID_FileStreamer,

NULL,

CLSCTX_ALL,

IID_IFileStreamer,

(void**)&spIUnknown))

)

{

printf("failed to create filestreamer object/n");

}

_getch();

spIUnknown.Release();

CoUninitialize();

return 0;

}

 

当程序执行起来之后使用windbg附到程序上,然后运行下面的命令:

0:001> !heap

Index   Address  Name      Debugging options enabled

  1:   00150000               

  2:   00010000               

  3:   00370000               

  4:   008e0000               

  5:   009f0000               

  6:   00be0000                

  7:   00b00000              

 

这里列出了系统中所有的堆,对于每个堆执行下面的命令:

!heap <heap handle>。例如:

0:001> !heap 00150000

Index   Address  Name      Debugging options enabled

  1:   00150000

Segment at 00150000 to 00250000 (00034000 bytes committed)

 

这里的输出就是堆00150000中包含的堆段,对于每个堆段执行下面的命令:

dds <segment start address> L<commited bytes>

 

这里的输出是对每个堆上的地址进行符号解析,如果找到一个虚函数表,那么就会显示如下的样子:

003c3de0  00000000

003c3de4  00000000

003c3de8  0013000c

003c3dec  0018075c

003c3df0  10008630 FileStreamerBox!ATL::CComObject<CFileStreamer>::`vftable'

003c3df4  100085f0 FileStreamerBox!ATL::CComObject<CFileStreamer>::`vftable'

003c3df8  100085c8 FileStreamerBox!ATL::CComObject<CFileStreamer>::`vftable'

003c3dfc  00000001

003c3e00  0015eff8

003c3e04  ffffffff

 

这里地址003c3df0就是对象CComObject<CFileStreamer>的首地址,即this指针的值。

 

如果把所有输出通过.logopen/.logclose命令收集起来,然后统计其中各种虚函数表的个数就能到各种对象的数量分布,从而定位问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值