如何通过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
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!