在CSDN晃悠的時候無意發現MAP檔案使用,記錄下來供大家學習。K5z平坦軟體園
K5z平坦軟體園
僅通過崩潰地址找出原始碼的出錯行K5z平坦軟體園
相信很多人都曾經遇到自己的程式在執行代碼時會跳出“Access xxxxx”地址錯誤。在通常情況下,我們根據此錯誤資訊追蹤不到錯誤碼行,只能一個個去看代碼。特別是自己的軟體已經發布,剛開始運行OK,但是時不時會跳出錯誤---真的是一件很崩潰的事情。可是你知道嗎?我們已經擁有去追蹤錯誤的方法,只是你一直不知道而已。K5z平坦軟體園
K5z平坦軟體園
MAP檔案K5z平坦軟體園
什麼是 MAP檔案?簡單地講,MAP檔案是程式的全域符號、源檔案和程式碼號資訊的唯一的文本表示方法,它可以在任何地方、任何時候使用,不需要有額外的程式進行支援。K5z平坦軟體園
DELPHI下產生MAP檔案的方法:偶只知道下面兩種,如果誰知道其他的方法 敬請告知 多謝 K5z平坦軟體園
產生詳細的MAP資訊的方法 K5z平坦軟體園
1. project -> options -> Linker -> Map file 選擇detailed. K5z平坦軟體園
2. D:/Fred/Code/DELPHI/MyPas/ErrLineByAddr2>dcc32 -GD project1.dpr (哈,這個我沒看懂,先用第一種吧)K5z平坦軟體園
下面根據例子看看MAP檔案的功能。K5z平坦軟體園
我們的程式:K5z平坦軟體園
unit Unit1;K5z平坦軟體園
K5z平坦軟體園
interfaceK5z平坦軟體園
K5z平坦軟體園
usesK5z平坦軟體園
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,K5z平坦軟體園
Dialogs, StdCtrls;K5z平坦軟體園
K5z平坦軟體園
typeK5z平坦軟體園
TForm1 = class(TForm)K5z平坦軟體園
btn1: TButton;K5z平坦軟體園
btn2: TButton;K5z平坦軟體園
edt1: TEdit;K5z平坦軟體園
procedure btn1Click(Sender: TObject);K5z平坦軟體園
procedure btn2Click(Sender: TObject);K5z平坦軟體園
privateK5z平坦軟體園
{ Private declarations }K5z平坦軟體園
publicK5z平坦軟體園
{ Public declarations }K5z平坦軟體園
end;K5z平坦軟體園
K5z平坦軟體園
varK5z平坦軟體園
Form1: TForm1;K5z平坦軟體園
K5z平坦軟體園
implementationK5z平坦軟體園
K5z平坦軟體園
{$R *.dfm}K5z平坦軟體園
{本例子參照CSND相關文章給出的例子}K5z平坦軟體園
procedure TForm1.btn1Click(Sender: TObject);K5z平坦軟體園
varK5z平坦軟體園
p: PChar;K5z平坦軟體園
beginK5z平坦軟體園
p:= nil;K5z平坦軟體園
p^:= 'a';//此句將引發地址錯誤K5z平坦軟體園
end;K5z平坦軟體園
K5z平坦軟體園
//因為MAP檔案在尋找錯誤行時涉及到16進位計算問題,所以為了測試我特地加了一個Edit框用來計算最後得出的值K5z平坦軟體園
procedure TForm1.btn2Click(Sender: TObject);K5z平坦軟體園
beginK5z平坦軟體園
edt1.text:= IntToHex(StrToInt('$'+ edt1.text) - StrToInt('$00400000') - StrToInt('$00001000'), 8) ;K5z平坦軟體園
end;K5z平坦軟體園
K5z平坦軟體園
end.K5z平坦軟體園
運行你的程式,點擊Btn1時報地址類錯誤,在我的機器上描述如下:K5z平坦軟體園
Access violation at address 0044F8D1 in module 'Project1.exe'. Write of address 00000000.K5z平坦軟體園
K5z平坦軟體園
錯誤地址為 0044F8D1。K5z平坦軟體園
K5z平坦軟體園
下面我們將根據這個地址找到Delphi 源碼檔案中對應程式碼。K5z平坦軟體園
如果你設定的沒有問題,程式運行後在同目錄下會產生一個‘Project.MAP’檔案,開啟你的MAP檔案。K5z平坦軟體園
檔案格式分為幾個段落,你可以看到 :K5z平坦軟體園
K5z平坦軟體園
0002:00002970 _UninitializeFlatSBK5z平坦軟體園
0002:00002B64 _WINNLSEnableIMEK5z平坦軟體園
K5z平坦軟體園
K5z平坦軟體園
Address Publics by VALUE //在這個段落中,你可以根據地址找到出錯函數名K5z平坦軟體園
K5z平坦軟體園
0002:FFBB0010 TlsLastK5z平坦軟體園
0001:000001F4 GetStdHandleK5z平坦軟體園
0001:000001FC RaiseExceptionK5z平坦軟體園
0001:00000204 RtlUnwindK5z平坦軟體園
0001:0000020C UnhandledExceptionFilterK5z平坦軟體園
----省略----K5z平坦軟體園
K5z平坦軟體園
Line numbers for Unit1(Unit1.pas) segment .textK5z平坦軟體園
K5z平坦軟體園
32 0001:0004E8C8 33 0001:0004E8C9 34 0001:0004E8CE 35 0001:0004E8D4K5z平坦軟體園
38 0001:0004E8D8 39 0001:0004E8F4 40 0001:0004E978 42 0001:0004E9E4K5z平坦軟體園
42 0001:0004E9EBK5z平坦軟體園
.......K5z平坦軟體園
注釋: Line numbers行下格式K5z平坦軟體園
K5z平坦軟體園
32 0001:0004E8C8 K5z平坦軟體園
K5z平坦軟體園
第一個數字代表在原始碼中的程式碼號,第二個數是該程式碼在所屬的程式碼片段中的位移量。K5z平坦軟體園
如果要尋找程式碼號,需要使用下面的公式做一些十六進位的減法運算:K5z平坦軟體園
崩潰行位移 = 崩潰地址(Crash Address) - 基地址(ImageBase Address) - 0x1000 K5z平坦軟體園
K5z平坦軟體園
為什麼要這樣做呢?我們得到的崩潰地址都是由 位移地址+ 基地址 得來的,所以在計算行號的時候要把基地址減去,一般情況下,基地址的值是 0x00400000 。另外,由於一般的 可攜式執行檔的程式碼片段都是從 0x1000 位移開始的,所以也必須減去 0x1000 。K5z平坦軟體園
(基地址可以通過 Project->Options, 在頁面中有一個Image Base值,就是它了)K5z平坦軟體園
K5z平坦軟體園
如果你不知道十六進位如何計算,那麼就按照我上面Btn2下的代碼,將得到的 0044F8D1 崩潰行地址輸入=> K5z平坦軟體園
得到 0004E8D1K5z平坦軟體園
再看:K5z平坦軟體園
Line numbers for Unit1(Unit1.pas) segment .textK5z平坦軟體園
K5z平坦軟體園
32 0001:0004E8C8 33 0001:0004E8C9 34 0001:0004E8CE 35 0001:0004E8D4K5z平坦軟體園
38 0001:0004E8D8 39 0001:0004E8F4 40 0001:0004E978 42 0001:0004E9E4K5z平坦軟體園
42 0001:0004E9EBK5z平坦軟體園
找出 小於等於 0004E8D1 的數(最接近的數,且不能大於) -->34 0001:0004E8CE.K5z平坦軟體園
源碼中的錯誤行即為 34!