• 通过崩溃地址找错误行数之Delphi版


    通过崩溃地址找错误行数之Delphi版
    2009-5-11 17:42:35 来源: 转载 作者:网络 访问:360 次 被顶:2 次 字号:【大 中 小】
    核心提示:什么是 MAP 文件?简单地讲, MAP 文件是程序的全局符号、源文件和代码行号信息的唯一的文本表示方法,它可以在任何地方、任何时候使用,不需要有额外的程序进行支持。而且,这是唯一能找出程序崩溃的地方的救星。 ...DELPHI下生成MAP文件的方法:偶只知道下面两种,如果谁知道其他的方法 敬请告知 多谢 
    生成详细的MAP信息的方法 
    1. project -> options -> Linker -> Map file 选择detailed. 
    2. D:FredCodeDELPHIMyPasErrLineByAddr2>dcc32 -GD project1.dpr

    我们的代码为: 
    unit Unit1;

    //{$D+,L+}

    interface

    uses 
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
      Dialogs, StdCtrls;

    type 
      TForm1 = class(TForm) 
        Button1: TButton; 
        procedure Button1Click(Sender: TObject); 
      private 
        { Private declarations } 
      public 
        { Public declarations } 
      end;

    var 
      Form1: TForm1;

    implementation

    {$R *.dfm}

    procedure TForm1.Button1Click(Sender: TObject); 
    var 
      I, J: Integer; 
      p: PChar; 
    begin 
      I := 10; 
      J := 0; 
      //I := I div J;  // 32 
      //ShowMessage(IntToStr(I)); 
      p := nil; 
      p^ := 'A';  // 38 
    end;

    end. 
    // 想必大家看到了 会有返回0地址错误....我们这里就是要让它崩溃,让我让你崩溃 ^_^ 
    然后执行 点击 然后出错 我的机器上 崩溃地址为0044d946 

    如果要查找代码行号,需要使用下面的公式做一些十六进制的减法运算: 
    崩溃行偏移 = 崩溃地址(Crash Address) - 基地址(ImageBase Address) - 0x1000  
    减去后得到 0004c946 然后查找 0004c946  
    0044d946 - 00400000 = 0004d946 - 00001000 = 0004c946 <= 后面列出的  
    0004C946 就是它了 我们用ultraedit32之类的工具打开 .map文件 搜索 0004C94,找到了,然后就找 
    <= 0004c946的那个地址 然后看到了 
    Line numbers for Unit1(Unit1.pas) segment .text

        37 0001:0004C944    38 0001:0004C946    39 0001:0004C949    41 0001:0004C97C 
        41 0001:0004C983

    38 0001:0004C946    就是它了。。。unit1.pas的第38行!!去代码里看一下 果然就是38行

    http://blog.csdn.net/diligentcatrich/article/details/6838285

    在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!

    http://blog.csdn.net/youthon/article/details/6067003

  • 相关阅读:
    bzoj1297: [SCOI2009]迷路
    bzoj1875: [SDOI2009]HH去散步
    bzoj2466: [中山市选2009]树
    bzoj1770: [Usaco2009 Nov]lights 燈
    BZOJ 1965: [Ahoi2005]SHUFFLE 洗牌( 数论 )
    BZOJ 1004: [HNOI2008]Cards( 置换群 + burnside引理 + 背包dp + 乘法逆元 )
    BZOJ 1006: [HNOI2008]神奇的国度( MCS )
    BZOJ 1925: [Sdoi2010]地精部落( dp )
    BestCoder Round #57 (div.2)
    BZOJ 1216: [HNOI2003]操作系统( 优先队列 )
  • 原文地址:https://www.cnblogs.com/findumars/p/5218045.html
Copyright © 2020-2023  润新知