现在的位置: 首页 > 自动控制 > 工业·编程 > 正文

简单的定位到程序崩溃地点的方法

2013-07-26 06:49 工业·编程 ⁄ 共 1411字 ⁄ 字号 暂无评论

2k以上的操作系统,微软提供了一种新的功能Online Crash Analysis,简称OCA,就是当程序崩溃的时候我们看到的的那个对话框,问你是否把崩溃的一些信息发送到微软,各个软件厂商可以从微软那里根据收集到的程序版本和出错的地址等信息来完善自己的程序。

如果你手头什么小工具都没有的情况下,下面这个方法可以很快的手工定位到出错地点。

点击“请单击此处”,可以看到详细的信息。

其中AppName是出错程序的exe文件名,AppVer是exe文件版本,ModName是此exe文件调用的崩溃模块的名称,ModVer是版本,最重要的就是Offset了,是崩溃的地址。

找到与出错版本程序对应的代码版本,在工程选项设置里Link->General勾上Generate mapfile,创建出一个与编译结果同名的map文件;并且在C/C++->Listing Files->Listing file type中选择Assembly,Machine Code,and Source一项,这样会为每个cpp文件创建出一个同名的cod文件。

编译出来以后我们就可以根据程序崩溃的地址开始一步步的寻找源头了。

事例程序是我用VC创建的一个对话框工程,然后改写了下面函数,下载后把后缀名改为rar

void CAboutDlg::OnOK() 
{
void* p = NULL;
    memcpy(p, this, 1024);
    CDialog::OnOK();
}

这样点击关于对话框上ok键就会崩溃了。

在示例程序中崩溃的地址是0x000012ad,先用一个文本编辑器打开map文件,在最上面可以看到一行Preferred load address is 00400000,代表程序的运行空间的起始地址为0x00400000,那么实际崩溃的地址就应该是0x00400000 + 0x000012ad = 0x004012ad,往下看map文件,有这么两行:

0001:000002a0       ?OnOK@CAboutDlg@@MAEXXZ    004012a0 f   1.obj
0001:000002c0       ??3CObject@@SGXPAX@Z       004012c0 f i 1.obj

第一个模块后面的地址是0x004012a0,第二个模块后面的地址是0x004012c0,而0x004012ad落在了这两个模块中间,那就说明崩溃的地址在第一行的代码范围内。

最后面的1.obj揭示了崩溃的具体文件,找到对应的1.cod文件,用文本编辑器打开,查找?OnOK@CAboutDlg@@MAEXXZ,能查找到多处,其中有一处?OnOK@CAboutDlg@@MAEXXZ PROC NEAR字样的就是此函数的起始处,下面用机器码、汇编和源代码描述了代码的细节。

这个函数的起始地址是0x004012a0,而崩溃的地址是0x004012ad,这两个相减,得到了崩溃的地址相对于函数起始的偏移地址0xd,看每一行汇编代码最前面的数字,就是偏移地址,找到0000d,后面的汇编就是出错的指令行,而上面的源代码就是出错的代码行。

这种方法一般用来处理OCA的bug,或者对付一些debug班没问题但是release板有问题的疑难杂症,但是如果ModName定位不在自己的程序里就没有办法了,那就有可能是因为自己程序里出了一些问题,但是没有崩溃,而代码走到了windows自身的模块中才受到影响崩溃了。

给我留言

留言无头像?