(转)利用WinDbg找出程序崩溃的代码行号

在程序运行过程中,遇到错误时不时崩溃,说程序不时的崩溃,什么xxoo不能read的! 
如果光要是这个内存地址,估计你会疯掉~~
所以分享一下基本的调试技巧,需要准备的工具有WinDbg + VC6.0,
下面是自己整理的一份自动生成DUMP文件的源代码,只需要添加到工程即可,源代码如下:
MiniDump.h
MiniDump.cpp

原文链接地址:           http://blog.csdn.net/wangningyu/article/details/6748138

原作者上传的测试代码:http://download.csdn.net/download/wangningyu/3575167

                               http://www.cctry.com/thread-41078-1-1.html

 

pdb文件的说明和微软符号下载:http://blog.csdn.net/xl_lbj/article/details/11604035

                              http://blog.csdn.net/bytxl/article/details/46722881

VC++6.0编译release版本程序生成pdb调试信息:http://blog.csdn.net/beanjoy/article/details/7294679

用VC6.0建立一个基于对话框程序

1、在CXXDlg::OnInitDialog()中添加这样一段:

BOOL CTestDlg::OnInitDialog()
{
        CDialog::OnInitDialog();
    
        // ......
        SetUnhandledExceptionFilter(CrashReportEx);
        HMODULE        hKernel32;

        // Try to get MiniDumpWriteDump() address.
        hDbgHelp = LoadLibrary("DBGHELP.DLL");
        MiniDumpWriteDump_ = (MINIDUMP_WRITE_DUMP)GetProcAddress(hDbgHelp, "MiniDumpWriteDump");
        //        d("hDbgHelp=%X, MiniDumpWriteDump_=%X", hDbgHelp, MiniDumpWriteDump_);
        
        // Try to get Tool Help library functions.
        hKernel32 = GetModuleHandle("KERNEL32");
        CreateToolhelp32Snapshot_ = (CREATE_TOOL_HELP32_SNAPSHOT)GetProcAddress(hKernel32, "CreateToolhelp32Snapshot");
        Module32First_ = (MODULE32_FIRST)GetProcAddress(hKernel32, "Module32First");
        Module32Next_ = (MODULE32_NEST)GetProcAddress(hKernel32, "Module32Next");
}

下面是工程中的测试代码:

class CTestDlg : public CDialog
{
// Construction
public:
        CTestDlg(CWnd* pParent = NULL);        // standard constructor

        void Fun1(char *pszBuffer);
        void Fun2(char *pszBuffer);
        void Fun3(char *pszBuffer);
};
void CTestDlg::Fun1(char *pszBuffer)
{
        Fun2(pszBuffer);
}

void CTestDlg::Fun2(char *pszBuffer)
{
        Fun3(pszBuffer);
}

void CTestDlg::Fun3(char *pszBuffer)
{
        pszBuffer[1] = 0x00;
}

我们在双击确定按钮时的响应代码如下:

void CTestDlg::OnOK() 
{
        // TODO: Add extra validation here
        Fun1(NULL);
}

其中Generate mapfile可以勾选,也可以不勾选

3、将编译生成的Release目录中的pdb、map文件(如果上面的步骤没有勾选,就不生成map文件)保存起来,以后调试会用到:

,这里就没有勾选生成map文件,有生成pdb文件。(release版也是这样的,在对应文件夹下)

4、运行程序,单击确定按钮出现异常后自动重启,并创建一个Log文件夹,里面生成dump文件:

5、我们打开WinDbg,设置一下相关路径
    A、设置pdb路径(File \ Symbol File Path)

 B、设置源代码路径( File \ Source File Path )

 

C、设置Exe路径( File \ Image File Path )

6、用WinDbg打开dump文件(File \ Open Crash Dump)

 

7、输入命令!analyze -v,等待几秒后会打印出错误信息,函数调用栈如下图:

0:000> !analyze -v
*******************************************************************************
*                                                                             *
*                        Exception Analysis                                   *
*                                                                             *
*******************************************************************************

*** ERROR: Symbol file could not be found.  Defaulted to export symbols for MFC42D.DLL - 
GetPageUrlData failed, server returned HTTP status 404
URL requested: http://watson.microsoft.com/StageOne/Test_exe/1_0_0_1/58c6045e/Test_exe/1_0_0_1/58c6045e/c0000005/00002d60.htm?Retriage=1

FAULTING_IP: 
Test!CTestDlg::Fun3+20 [E:\vcDemo\Test\TestDlg.cpp @ 141]
00402d60 c6400100        mov     byte ptr [eax+1],0

EXCEPTION_RECORD:  ffffffff -- (.exr 0xffffffffffffffff)
ExceptionAddress: 00402d60 (Test!CTestDlg::Fun3+0x00000020)
   ExceptionCode: c0000005 (Access violation)
  ExceptionFlags: 00000000
NumberParameters: 2
   Parameter[0]: 00000001
   Parameter[1]: 00000001
Attempt to write to address 00000001

PROCESS_NAME:  Test.exe

ERROR_CODE: (NTSTATUS) 0xc0000005 - 0x%08lx

EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - 0x%08lx

EXCEPTION_PARAMETER1:  00000001

EXCEPTION_PARAMETER2:  00000001

WRITE_ADDRESS:  00000001 

FOLLOWUP_IP: 
Test!CTestDlg::Fun3+20 [E:\vcDemo\Test\TestDlg.cpp @ 141]
00402d60 c6400100        mov     byte ptr [eax+1],0

MOD_LIST: <ANALYSIS/>

FAULTING_THREAD:  00008884

BUGCHECK_STR:  APPLICATION_FAULT_NULL_CLASS_PTR_DEREFERENCE_INVALID_POINTER_WRITE

PRIMARY_PROBLEM_CLASS:  NULL_CLASS_PTR_DEREFERENCE

DEFAULT_BUCKET_ID:  NULL_CLASS_PTR_DEREFERENCE

LAST_CONTROL_TRANSFER:  from 00402d19 to 00402d60

STACK_TEXT:  
0012f530 00402d19 00000000 0012f5e8 001986e0 Test!CTestDlg::Fun3+0x20 [E:\vcDemo\Test\TestDlg.cpp @ 141]
0012f58c 00402cc9 00000000 0012f644 001986e0 Test!CTestDlg::Fun2+0x29 [E:\vcDemo\Test\TestDlg.cpp @ 137]
0012f5e8 00403267 00000000 0012f8e4 001986e0 Test!CTestDlg::Fun1+0x29 [E:\vcDemo\Test\TestDlg.cpp @ 132]
0012f644 5f4398cc 0012f8e4 001986e0 00000000 Test!CTestDlg::OnOK+0x27 [E:\vcDemo\Test\TestDlg.cpp @ 242]
WARNING: Stack unwind information not available. Following frames may be wrong.
0012f67c 5f439ffb 0012fe3c 00000001 00000000 MFC42D!Ordinal563+0x133
0012f6d4 5f435c1b 00000001 00000000 00000000 MFC42D!Ordinal3657+0x274
0012f704 5f431f33 00000001 00000000 00000000 MFC42D!Ordinal3658+0x24
0012f764 5f431135 00000001 006005fc 0012f8e4 MFC42D!Ordinal3670+0x138
0012f864 5f4310b8 00000111 00000001 006005fc MFC42D!Ordinal4118+0x53
0012f884 5f42ec09 00000111 00000001 006005fc MFC42D!Ordinal5076+0x2e
0012f8f8 5f42f0f5 0012fe3c 005a0588 00000111 MFC42D!Ordinal1045+0xed
0012f924 5f49265d 005a0588 00000111 00000001 MFC42D!Ordinal1192+0xad
0012f954 7600c4b7 005a0588 00000111 00000001 MFC42D!Ordinal1193+0x4a
0012f980 7600c5b7 5f492613 005a0588 00000111 user32!InternalCallWinProc+0x23
0012f9f8 7600526c 00000000 5f492613 005a0588 user32!UserCallWinProcCheckWow+0x14b
0012fa38 7600555a 007c9b40 007ca9e0 00000001 user32!SendMessageWorker+0x4d0
0012fa58 760396b5 005a0588 00000111 00000001 user32!SendMessageW+0x7c
0012fa70 760397b5 007c9e28 00000000 007c9e28 user32!xxxButtonNotifyParent+0x41
0012fa8c 76027ed1 0019e124 00000001 00000000 user32!xxxBNReleaseCapture+0xf7
0012fb10 76018285 007c9e28 00000202 00000000 user32!ButtonWndProcWorker+0x911
0012fb30 7600c4b7 006005fc 00000202 00000000 user32!ButtonWndProcA+0x4c
0012fb5c 7600c5b7 7601db9d 006005fc 00000202 user32!InternalCallWinProc+0x23
0012fbd4 7600cbe9 00000000 7601db9d 006005fc user32!UserCallWinProcCheckWow+0x14b
0012fc34 7600cc40 7601db9d 00000000 0012fc68 user32!DispatchMessageWorker+0x357
0012fc44 760041c3 004177e0 004177e0 004177e8 user32!DispatchMessageW+0xf
0012fc68 76012043 005a0588 007c9e28 0012fea4 user32!IsDialogMessageW+0x588
0012fc88 5f438bf5 005a0588 004177e0 0012fea4 user32!IsDialogMessageA+0x10c
0012fcac 5f434464 004177e0 0012fea4 00000000 MFC42D!Ordinal3337+0x7b
0012fcc8 5f435bee 004177e0 0012fea4 00000000 MFC42D!Ordinal4206+0x75
0012fcec 5f433018 004177e0 0012fea4 00000000 MFC42D!Ordinal4208+0xf8
0012fd0c 5f43b776 005a0588 004177e0 004177a8 MFC42D!Ordinal5070+0x98
0012fd28 5f43bbdd 004177e0 0012fea4 00000000 MFC42D!Ordinal4215+0x55
0012fd44 5f43466f 0012fea4 00000000 7ffd9000 MFC42D!Ordinal4239+0xe2
0012fd80 5f436a6f 00000004 0012fea4 00000000 MFC42D!Ordinal4410+0x202
0012fde0 004025ec 00000000 00000000 7ffd9000 MFC42D!Ordinal1862+0x191
0012feb0 5f4359f3 00000000 00000000 7ffd9000 Test!CTestApp::InitInstance+0x6c [E:\vcDemo\Test\Test.cpp @ 59]
0012fed0 004038e8 00400000 00000000 00172d0d MFC42D!Ordinal1190+0x83
0012fee8 00403763 00400000 00000000 00172d0d Test!WinMain+0x18 [appmodul.cpp @ 30]
0012ff88 7622ef1c 7ffd9000 0012ffd4 77d83648 Test!WinMainCRTStartup+0x1b3 [crtexe.c @ 330]
0012ff94 77d83648 7ffd9000 77ae81ff 00000000 kernel32!BaseThreadInitThunk+0xe
0012ffd4 77d8361b 004035b0 7ffd9000 00000000 ntdll!__RtlUserThreadStart+0x70
0012ffec 00000000 004035b0 7ffd9000 00000000 ntdll!_RtlUserThreadStart+0x1b


STACK_COMMAND:  ~0s; .ecxr ; kb

FAULTING_SOURCE_CODE:  
   137: }
   138: 
   139: void CTestDlg::Fun3(char *pszBuffer)
   140: {
>  141:     pszBuffer[1] = 0x00;
   142: }
   143: 
   144: BOOL CTestDlg::OnInitDialog()
   145: {
   146:     CDialog::OnInitDialog();


SYMBOL_STACK_INDEX:  0

SYMBOL_NAME:  test!CTestDlg::Fun3+20

FOLLOWUP_NAME:  MachineOwner

MODULE_NAME: Test

IMAGE_NAME:  Test.exe

DEBUG_FLR_IMAGE_TIMESTAMP:  58c6045e

FAILURE_BUCKET_ID:  NULL_CLASS_PTR_DEREFERENCE_c0000005_Test.exe!CTestDlg::Fun3

BUCKET_ID:  APPLICATION_FAULT_NULL_CLASS_PTR_DEREFERENCE_INVALID_POINTER_WRITE_test!CTestDlg::Fun3+20

WATSON_STAGEONE_URL:  http://watson.microsoft.com/StageOne/Test_exe/1_0_0_1/58c6045e/Test_exe/1_0_0_1/58c6045e/c0000005/00002d60.htm?Retriage=1

Followup: MachineOwner
---------

这样我们就能在发布版本的程序中,准确的定位到哪个函数出了问题,所以发布程序时,一定要记得生成pdb文件,不然客户运行出错的话,你不死也残!

使用windbg调试时,需要注意的是pdb的版本与产生dump的exe或dll版本必须一致(保证是同一时间编译后生成的)。
有时候只加载自己的pdb还看不出问题所在,需要加载微软的pdb:
在symbols输入框里,除了自己pdb的路径外,还应输入“srv*sym*http://msdl.microsoft.com/download/symbols”,自动加载系统模块所需的dll。
输入pdb路径后,最好再用命令reload -f强制加载pdb。
另外,一般不通过命令行来分析,因为windbg有各种窗口。我一般打开进程窗口、堆栈窗口和源代码窗口进行分析。

posted @ 2017-03-13 11:00  懒猫的新窝  阅读(1544)  评论(0)    收藏  举报