如何通过offset地址确定引起崩溃的代码行

如何通过offset地址确定引起崩溃的代码行 (转)2009-04-21 09:19

简介

当release版本的程序交付给用户使用后,如果应用程序崩溃了,怎么样通过windows提示的offset地址来定位源程序中对应的出错代码呢?这篇文章就来讨论这个问题。

建立调试环境

1.(VC 6)依次选择FileàNewàProjects,在列表中选择“MFC AppWizard(EXE)”在“Project Name”中输入“Crash_Test”作为项目名,“OK”进入下一步。在“MFC Appwizard – Step 1”对话框中选择“Dialog Based”单选框。“Finish”完成工程的建立,F7编译无误。

2.(VC 6)双击确定按钮,提示加入(重写)“OnOK”函数,OK,进入“CCrash_TestDlg::OnOK()”函数。

3.我们将在OnOK函数中构造一些能够引起程序崩溃的错误代码:

void CCrash_TestDlg::OnOK()

{

AfxGetApp()->GetMainWnd()->SetWindowText(_T("Crash"));

int pTest = NULL;

pTest = 0; // 为空指针赋值,程序将崩溃

CDialog::OnOK();

}

加入“AfxGetApp()->GetMainWnd()->SetWindowText(_T("Crash"));”的目的是使崩溃地址和“OnOK”的地址有一定偏移,使演示更具一般性。

4.(VC 6)首先设置Release编译(在BuildàSet as configuration中选择Win32 Release)。依次选择ProjectàSettings,选择“C/C++”tab页,Category中选择“Listing Files”,然后在“Listing file type”中选择“Assembly, Machine Code, and Source”,OK。这个选项将为每个源文件(*.cpp)生成机器码、汇编码和源代码的对应表,可以在“Release”目录下找到和查看这些文件。

5.(VC 6)依次选择ProjectàSettings,选择“Link”tab页,Category中选择“Debug”,

钩选“Generate map file”,OK。这个选项将生成编译后的函数地址和函数名的对应表。

定位错误代码

1.现在运行“Release”目录下的测试程序,当点击“确定”按钮时,程序将崩溃。

Windows XP 会出现“Crash_Test.exe 遇到问题需要关闭。我们对此引起的不便表示抱歉。”…………

云云的对话框,在对话框的下方,单击“请单击此处”的超连接,在“错误签名”中,我们会得到如下信息:

AppName: crash_test.exeAppVer: 1.0.0.1ModName: crash_test.exe

ModVer: 1.0.0.1Offset: 000014a0

其中的Offset值就是崩溃的地址啦,现在我们根据这个地址来定位源程序中出错的代码行。

2.用记事本打开“Release”目录下的,“Crash_Test.map”文件,在文件中会看到类似下面的内容:

0001:00000470?OnQueryDragIcon@CCrash_TestDlg@@IAEPAUHICON__@@XZ 00401470 fCrash_TestDlg.obj

0001:00000480?OnOK@CCrash_TestDlg@@MAEXXZ 00401480 fCrash_TestDlg.obj

0001:000004c0?BeginModalState@CWnd@@UAEXXZ 004014c0 f i Crash_TestDlg.obj

0001:000004d0?EndModalState@CWnd@@UAEXXZ 004014d0 f i Crash_TestDlg.obj

画线的部分就是各个函数编译运行后在内存中的相对地址 (高位部分是基地址,就不参与计算啦,基地址可能因机器不同而异,但相对地址都是一样的。) ,因为“Offset”指示的崩溃地址为“14a0”,

1480(OnOK地址) < 14a0(出错地址) < 14c0(BeginModalState地址),很显然,14a0的地址是在OnOK函数的地址范围内的,也就是说OnOK就是引起崩溃的函数。接下来再来确定出错的具体代码行。

3.因为OnOK是在“Crash_TestDlg.cpp”中实现的,因此,我们打开对应的“Crash_TestDlg.cod”文件,其中有如下代码:

?OnOK@CCrash_TestDlg@@MAEXXZ PROC NEAR; CCrash_TestDlg::OnOK, COMDAT

; 173: {

0000056pushesi

000018b f1movesi, ecx

… …

; 175: int pTest = NULL;

; 176:
pTest = 0;

; 177: CDialog::OnOK();

0001e8b cemovecx, esi

00020c7 05 00 00 00

00 00 00 00 00movDWORD PTR ds:0, 0

0002ae8 00 00 00 00call?OnOK@CDialog@@MAEXXZ; CDialog::OnOK

0002f5epopesi

; 178: }

… …

很明显,这些就是OnOK函数的汇编表示和机器码表示,画线的地址就是函数中各个语句的相对(相对于函数首地址)地址。

在步骤1中,我们已经得到,Offset为14a0,OnOK的函数首地址为0480,现在,我们用14a0-1480就得到20(注意,这里都是16进制运算),可见,出错的代码行为:

00020c7 05 00 00 00 00 00 00 00 00movDWORD PTR ds:0, 0

对应上面注释的:

; 176: *pTest = 0;

原文链接: https://www.cnblogs.com/alex_itxz/archive/2010/09/20/1831782.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/15239

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月7日 下午3:09
下一篇 2023年2月7日 下午3:10

相关推荐