程序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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章