程序Crash调试方式--MAP文件

什么时候用MAP文件调试

1.调试程序时,我们发现Debug版的exe可以完全正常运行,而Release版却经常莫名其妙Crash。

2.程序运行时直接崩溃,只显示一个出错地址,让联系开发人员。这样根本找不到程序Crash的位置。

3.但在大量进行压力测试时,尤其是多线程测试时,有可能同时出现十几个错误,这时VC本身的调试跳转可能跟不到核心出错的现场。


什么是MAP文件

MAP文件是程序的全局符号、源文件和代码行号信息的问一问本表示方法,是整个程序工程信息的静态文本。它可以直接打开,不需要其他支持。


在程序编译时加入MAP文件

vc6编译生成的MAP文件是带行号的,找到出错的内存地址后,直接通过行号就可以对应到代码,但是vs2005编译生成的MAP文件不带行号...那么就需要通过cod文件来定位行号。cod文件(机器码文件).

在vs2005中使编译时生成MAP文件和cod文件的方法:

(1).map文件:property->Configuration Properties->Linker->Debugging 中的Generate Map File选择Yes(/MAP);

(2).cod文件:property->Configuration Properties->C/C++->output Files中Assembler OutPut中选择Assembly,Maching Code and Source(/FAcs),生成机器,源代码

OK...


如何使用MAP和cod

先举个例子:

void Crash(void) 
{ 
	 int i = 1; 
	 int j = 0; 
	 i /= j; 
 } 

 void Func1()
 {
	 int b = 1000;
	 Crash();
 }

 void Func2()
 {
	 int c = 1;
	 return ;
 }

 void main(void) 
{ 
	int a = 0;
	a = 300; 
	Func1();
	Func2();
 } 

运行后出现下图:0x004113d0的位置crash


打开MAP文件(后缀名.map,默认和.exe在同一级目录)。


从Address这里开始看,通过Rva+Base这里查找Crash的地址0x004113d0.Rva+Base是递增的,很好定位,当然一般也不可能直接找到Crash的地址,而是找比他大的那个地址,或者比他小的那个地址。


找到后发现0x004113d0就在上面这两个地址中间,根据函数调用规则(栈的方式):找到Crash地址大的那个地址,则该地址前一个的入口就是产生崩溃的函数,即?Crash@@YAXXZ,也就是说是函数Crash出现了问题,记录下Crash函数的入口地址0x004113a0.

下面的问题是找到Crash中那一步出问题了,这就需要用到cod文件(.cod)


在cod文件中会有很多类似上图的结构,

以?Crash@@YAXXZ PROC; Crash, COMDAT开头,

以?Crash@@YAXXZ ENDP; Crash

来标识一个函数。中间的19、20、21、22、23就是源代码的行号。

如果要查找代码行号,需要使用下面的公式做一些十六进制的减法运算: 
崩溃行偏移 = 崩溃地址(Crash Address) - 基地址(ImageBase Address) - 0x1000 
崩溃地址都是由 偏移地址(Rva)+ 基地址(Base) 得来的,所以在计算行号的时候要把基地址减去,一般情况下,基地址的值是 0x00400000 ,另外,由于一般的 PE 文件的代码段都是从 0x1000 偏移开始的,所以也必须减去 0x1000 。 

而这里及地址就是Crash函数的入口地址0x004113a0,所以就减去函数入口地址就可以了

那么就是0x004113d0- 0x004113a0=0x00030

在cod文件的Crash函数中找到00030,则它对应的行号就是出错地方在源代码中的行号。就是22行。

发布了56 篇原创文章 · 获赞 21 · 访问量 26万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章