什麼時候用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行。