[Delphi]使用MAP文件查找程序地址类错误行

在CSDN晃悠的时候无意发现MAP文件使用,记录下来供大家学习。
     
   仅通过崩溃地址找出源代码的出错行
   相信很多人都曾经遇到自己的程序在执行代码时会跳出“Access xxxxx”地址错误。在通常情况下,我们根据此错误信息追踪不到错误代码行,只能一个个去看代码。特别是自己的软件已经发布,刚开始运行OK,但是时不时会跳出错误---真的是一件很崩溃的事情。可是你知道吗?我们已经拥有去追踪错误的方法,只是你一直不知道而已。
  
   MAP文件

   什么是 MAP文件?简单地讲,MAP文件是程序的全局符号、源文件和代码行号信息的唯一的文本表示方法,它可以在任何地方、任何时候使用,不需要有额外的程序进行支持。
   DELPHI下生成MAP文件的方法:偶只知道下面两种,如果谁知道其他的方法   敬请告知   多谢  
   生成详细的MAP信息的方法  
   1.   project   ->   options   ->   Linker   ->   Map   file   选择detailed.  
   2.   D:/Fred/Code/DELPHI/MyPas/ErrLineByAddr2>dcc32   -GD   project1.dpr (哈,这个我没看懂,先用第一种吧)

   下面根据例子看看MAP文件的功能。
   我们的程序:
   unit Unit1;
   
    interface
   
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls;
   
    type
      TForm1 = class(TForm)
        btn1: TButton;
        btn2: TButton;
        edt1: TEdit;
        procedure btn1Click(Sender: TObject);
        procedure btn2Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
   
    var
      Form1: TForm1;
   
    implementation
   
    {$R *.dfm}
    {本例子参照CSND相关文章给出的例子}
    procedure TForm1.btn1Click(Sender: TObject);
    var
      p: PChar;
    begin
      p:= nil;
      p^:= 'a';//此句将引发地址错误
    end;
   
    //因为MAP文件在查找错误行时涉及到16进制计算问题,所以为了测试我特地加了一个Edit框用来计算最后得出的值
    procedure TForm1.btn2Click(Sender: TObject);
    begin
      edt1.text:= IntToHex(StrToInt('$'+ edt1.text) - StrToInt('$00400000') - StrToInt('$00001000'), 8) ;
    end;
   
    end.
    运行你的程序,点击Btn1时报地址类错误,在我的机器上描述如下:
    Access violation at address 0044F8D1 in module 'Project1.exe'. Write of address 00000000.
   
    错误地址为 0044F8D1。
   
    下面我们将根据这个地址找到Delphi 源码文件中对应代码行。
    如果你设置的没有问题,程序运行后在同目录下会产生一个‘Project.MAP’文件,打开你的MAP文件。
    文件格式分为几个段落,你可以看到 :
   
     0002:00002970       _UninitializeFlatSB
     0002:00002B64       _WINNLSEnableIME
   
   
      Address         Publics by VALUE //在这个段落中,你可以根据地址找到出错函数名
   
     0002:FFBB0010       TlsLast
     0001:000001F4       GetStdHandle
     0001:000001FC       RaiseException
     0001:00000204       RtlUnwind
     0001:0000020C       UnhandledExceptionFilter

     ----省略----
    
     Line numbers for Unit1(Unit1.pas) segment .text
    
         32 0001:0004E8C8    33 0001:0004E8C9    34 0001:0004E8CE    35 0001:0004E8D4
         38 0001:0004E8D8    39 0001:0004E8F4    40 0001:0004E978    42 0001:0004E9E4
         42 0001:0004E9EB

      .......
     注释: Line numbers行下格式
    
       32 0001:0004E8C8
      
     第一个数字代表在源代码中的代码行号,第二个数是该代码行在所属的代码段中的偏移量。
     如果要查找代码行号,需要使用下面的公式做一些十六进制的减法运算:

     崩溃行偏移 = 崩溃地址(Crash Address) - 基地址(ImageBase Address) - 0x1000
    
     为什么要这样做呢?我们得到的崩溃地址都是由 偏移地址+ 基地址 得来的,所以在计算行号的时候要把基地址减去,一般情况下,基地址的值是 0x00400000 。另外,由于一般的 PE 文件的代码段都是从 0x1000 偏移开始的,所以也必须减去 0x1000 。
     (基地址可以通过 Project->Options, 在页面中有一个Image Base值,就是它了)
    
     如果你不知道十六进制如何计算,那么就按照我上面Btn2下的代码,将得到的 0044F8D1 崩溃行地址输入=>
     得到 0004E8D1
     再看:
         Line numbers for Unit1(Unit1.pas) segment .text
    
         32 0001:0004E8C8    33 0001:0004E8C9    34 0001:0004E8CE    35 0001:0004E8D4
         38 0001:0004E8D8    39 0001:0004E8F4    40 0001:0004E978    42 0001:0004E9E4
         42 0001:0004E9EB
     找出 小于等于 0004E8D1 的数(最接近的数,且不能大于) -->34 0001:0004E8CE.
     源码中的错误行即为 34!

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页