WINCE-如何通过map文件定位异常地址

来源:互联网 发布:k11和js防水哪个好 编辑:程序博客网 时间:2024/05/03 03:15

在程序异常时,通常通过debug调试的方法找原因。在非调试的模式下或者实际应用中,程序出现崩溃,当程序比较复杂,通过查看代码不容易查出问题。

在evc和vs2005的工具中,可以通过生成map(映射文件)和cod(程序集、机器码、源代码)文件查找异常地址。map可定位在发生崩溃的函数,code文件可定位在具体函数中的某一行。

 

在evc中配置设置如下

生成Cod文件:在Project/Setting/C/C++/Listing file type中,选择Assembli,Machine Code,and Source。如何1.1.

生成Map文件:在Project/Setting/Link中,在Generate mapfile选项中打勾。如图1.2

 

图1.1

 

图1.2

 

在vs2005中配置设置如下

生成Cod文件:在属性à配置属性àC/C++à输出文件中,选择程序集、机器码和原代码(/FAcs)。如图1.3

生成Map文件:在属性à配置属性à链接器à调试à生成映射文件选择是(/NAP).如图1.4

 

图1.3

图1.4

 

 

设置该2项后,编译工程,会生成.cod和.map文件。这些文件就是用来查找异常地址。

 

下面举个例子:

 

void CHelloDlg::Fun(char *pbuf)

{

     *pbuf = 1;

}

 

// CHelloDlg 消息处理程序

 

BOOL CHelloDlg::OnInitDialog()

{

     CDialog::OnInitDialog();

 

     // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动

     //  执行此操作

     SetIcon(m_hIcon, TRUE);          // 设置大图标

     SetIcon(m_hIcon, FALSE);         // 设置小图标

 

     // TODO: 在此添加额外的初始化代码

     char *p = 0;

     Fun(p);

    

     return TRUE;  // 除非将焦点设置到控件,否则返回TRUE

}

 

很容易看出来,在函数Fun中pbuf是参数p没有申请空间,所以*pbuf = 1会异常。

所以在运行时出现如下异常:

PC=0001119c(Hello.exe+0x0000119c) RA=00011194(Hello.exe +0x00001194) SP=0004f620, BVA=00000000

 

在这里我们要注意在Hello.map文件中,0x0000119c需要加上Preferred load address后来查找接近的地址,最接近的小的那个值为函数的开始地址,

这里面最关键的信息是PC和RA给出的地址信息。PC就是上面提到的崩溃地址,根据这个地址可以定位到导致崩溃的源代码行;RA是PC的返回地址(Return Address),根据这个地址可以找到导致崩溃的上一级函数。除了PC和RA,其他信息也可以提供一些参考作用:BVA是ARM中的Fault Address Register(FAR),是引起Data Abort的虚拟地址,比如说你的程序试图访问一个非法地址里的内容,那么Data Abort时BVA就是这个非法地址;FSR是Fault Status Register,指明导致异常的原因。

 

1、查找异常的函数:

打开Hello.map文件,内容如下(截取部分)

  Address         Publics by Value              Rva+Base       Lib:Object

0001:0000015c       ?DoDataExchange@CHelloDlg@@MAAXPAVCDataExchange@@@Z 0001115c f   HelloDlg.obj

 0001:0000015c       ?Serialize@CObject@@UAAXAAVCArchive@@@Z 0001115c f   Hello.obj

 0001:0000015c       ?OnBnClickedButton1@CHelloDlg@@QAAXXZ 0001115c f   HelloDlg.obj

 0001:0000015c       ?DoDataExchange@CWnd@@MAAXPAVCDataExchange@@@Z 0001115c f   HelloDlg.obj

 0001:00000160       ?OnInitDialog@CHelloDlg@@MAAHXZ 00011160 f   HelloDlg.obj

 0001:000001a8       ?GetMessageMap@CHelloDlg@@MBAPBUAFX_MSGMAP@@XZ 000111a8 f   HelloDlg.obj

 0001:000001b4       ?GetMessageMap@CWinApp@@MBAPBUAFX_MSGMAP@@XZ 000111b4 f   uafxcw:appcore.obj

 0001:000001b4       ?GetThisMessageMap@CWinApp@@KAPBUAFX_MSGMAP@@XZ 000111b4 f   uafxcw:appcore.obj

 0001:000001c0       ?_LoadSysPolicies@CWinApp@@IAAHXZ 000111c0 f   uafxcw:appcore.obj

 0001:000002e4       ?InitApplication@CWinApp@@UAAHXZ 000112e4 f   uafxcw:appcore.obj

 0001:00000370       ??1CWinApp@@UAA@XZ         00011370 f   uafxcw:appcore.obj

 0001:000004bc       ?ExitInstance@CWinApp@@UAAHXZ 000114bc f   uafxcw:appcore.obj

 

通过异常地址0001119c,找到最相近的2个地址

OnInitDialog@CHelloDlg@@MAAHXZ 00011160 f   HelloDlg.obj

GetMessageMap@CHelloDlg@@MBAPBUAFX_MSGMAP@@XZ 000111a8 f   HelloDlg.obj

以上2个地址表示函数的起始地址,所以直接看HelloDlg,异常的地址在HelloDlg .obj的CHelloDlg的OnInitDialog。相应的代码在HelloDlg.cod

 

2、查找异常的行号

异常地址为0001119c,减去起始地址00011160,得0x3c。

异常地址的上一层函数地址为00011194,减去起始地址00011160,得0x34。

打开HelloDlg.cod,部分内容如下

 

; 48   :

; 49   : // TODO: 在此添加额外的初始化代码

; 50   : char *p = 0;

 

  00034  e3a02000         mov         r2, #0

 

; 51   : FunOSAD(p);

 

  00038  e3a03001         mov         r3, #1

  0003c   e5c23000          strb        r3, [r2]

 

; 52   :

; 53   : return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE

 

(说明:48是行号,00034是十六进制地址)

根据0x3c,可找到0003c      e5c23000          strb        r3, [r2],往上看,可以知道在FunOSAD中异常了。第51行。即*pbuf = 1;这一行代码异常。

 

上一层地址0x34,可找到上一级函数00034     e3a02000         mov         r2, #0,往上看可知道上一级地址为char *p = 0;,第50行。

原创粉丝点击