利用MSJExceptionHandler类查找Crash问题

来源:互联网 发布:java从服务器下载文件 编辑:程序博客网 时间:2024/05/05 17:06

   最近有个用户遇到程序Crash问题,但我们的机器都不能重现,于是在网上搜了一把,发现有个MSJExceptionHandler类还比较好用,故整理了一下供大家参考。

这个类的使用方法很简单,只要把这个类加入到你的工程(不管是MFC,com,dll都可以)中一起编译就可以了,由于在这个类的实现文件中把定义了一个全局的类对象,所以不用加入任何代码,连#include都不需要。

一、VS2005创建一个基于对话框的工程testCrash

1.将msjexhnd.h和msjexhnd.cpp加入到这个工程

   此时编译程序会提示错误fatal error C1010: unexpected end of file while looking for precompiled header. Did you forget to add '#include "stdafx.h"' to your source?

2.工程中选中msjexhnd.cpp右键>属性,在c/c++>Precompiled Headers>Create/Use Precompiled Headers选择Not Using Precompiled Headers,Ok

   编译程序,成功。

3.首先设置工程为Release编译,然后选中工程右键>属性,在c/c++>Output Files>Assembler Output选择Assembly, Machine Code and Source (/FAcs).

   这个选项将为每个源文件(*.cpp)生成机器码、汇编码和源代码的对应表,可以在“Release”目录下找到和查看这些文件。
   然后在Linker>Debugging>Generate Map File选择Yes (/MAP),这个选项将生成编译后的函数地址和函数名的对应表。

   点击ok后rebuild此工程,可以在Release目录找到testCrash.map,testCrashDlg.cod

4.在工程中加入测试代码,并重新编译程序

void CtestCrashDlg::OnBnClickedOk()
{
 // TODO: Add your control notification handler code here
 int *p=NULL;
 *p = 0; //给空指针赋值
 OnOK();
}

 

二、查找Crash

1.运行testCrash.exe,点击ok按钮,程序crash

   此时会在exe同一目录下生成文件 testCrash.RPT,你可以自己定义此文件位置及名字,具体看MSJExceptionHandler的构造函数。

2.用文本方式打开testCrash.RPT,可以看到这一行

  Fault address:  00401452 01:00000452 d:\myown\test\testcrash\release\testCrash.exe

  注意01:00000452就是程序崩溃的地址

3.打开testCrash.map,可以找到

  0001:00000450       ?OnBnClickedOk@CtestCrashDlg@@QAEXXZ 00401450 f   testCrashDlg.obj
  0001:00000460       ?Create@CDialog@@UAEHIPAVCWnd@@@Z 00401460 f i testCrashDlg.obj
  由于崩溃地址是01:00000452,大于0001:00000450,小于0001:00000460,所以可以肯定是CtestCrashDlg::OnBnClickedOk里崩溃。

  并且相对地址是 00000452-00000450=2(16进制),代码对应在testCrashDlg.cod因为最后面显示的是testCrashDlg.obj

4.打开testCrashDlg.cod,找到

; COMDAT ?OnBnClickedOk@CtestCrashDlg@@QAEXXZ
_TEXT SEGMENT
?OnBnClickedOk@CtestCrashDlg@@QAEXXZ PROC  ; CtestCrashDlg::OnBnClickedOk, COMDAT
; _this$ = ecx

; 155  :  // TODO: Add your control notification handler code here
; 156  :  int *p=NULL;

  00000 33 c0   xor  eax, eax

; 157  :  *p = 0;

  00002 89 00   mov  DWORD PTR [eax], eax

; 158  :  OnOK();

前面带分号的是注释,不带的是汇编代码,汇编代码前面5位数是代码在此函数的相对地址,00002就是偏移2,正是我们要找的崩溃的地方。

它上面的一行是注释实际的源代码; 157  :  *p = 0;

好,终于找到元凶!