• 调试技巧 —— 如何利用windbg + dump + map分析程序异常


    之前碰到论坛里有几个好友,说程序不时的崩溃,什么xxoo不能read的! 如果光要是这个内存地址,估计你会疯掉~~

    所以分享一下基本的调试技巧,需要准备的工具有WinDbg + VC6.0,

    下面是自己整理的一份自动生成DUMP文件的源代码,只需要添加到工程即可,源代码如下:

    MiniDump.h

    1. #include <windows.h>  
    2. #include <tlhelp32.h>  
    3.   
    4. //#include "dbghelp.h"  
    5. //#define DEBUG_DPRINTF     1   //allow d()  
    6. //#include "wfun.h"  
    7.   
    8. #pragma optimize("y", off)      //generate stack frame pointers for all functions - same as /Oy- in the project  
    9. #pragma warning(disable: 4200)  //nonstandard extension used : zero-sized array in struct/union  
    10. #pragma warning(disable: 4100)  //unreferenced formal parameter  
    11.   
    12. /*BOOL WINAPI Get_Module_By_Ret_Addr(PBYTE Ret_Addr, PCHAR Module_Name, PBYTE & Module_Addr); 
    13. int  WINAPI Get_Call_Stack(PEXCEPTION_POINTERS pException, PCHAR Str); 
    14. int  WINAPI Get_Version_Str(PCHAR Str); 
    15. PCHAR WINAPI Get_Exception_Info(PEXCEPTION_POINTERS pException); 
    16. void WINAPI Create_Dump(PEXCEPTION_POINTERS pException, BOOL File_Flag, BOOL Show_Flag);*/  
    17.   
    18. // In case you don't have dbghelp.h.  
    19. #ifndef _DBGHELP_  
    20.   
    21. typedef struct _MINIDUMP_EXCEPTION_INFORMATION {  
    22.     DWORD   ThreadId;  
    23.     PEXCEPTION_POINTERS ExceptionPointers;  
    24.     BOOL    ClientPointers;  
    25. } MINIDUMP_EXCEPTION_INFORMATION, *PMINIDUMP_EXCEPTION_INFORMATION;  
    26.   
    27. typedef enum _MINIDUMP_TYPE {  
    28.     MiniDumpNormal =            0x00000000,  
    29.         MiniDumpWithDataSegs =      0x00000001,  
    30. } MINIDUMP_TYPE;  
    31.   
    32. typedef BOOL (WINAPI * MINIDUMP_WRITE_DUMP)(  
    33.                                             IN HANDLE           hProcess,  
    34.                                             IN DWORD            ProcessId,  
    35.                                             IN HANDLE           hFile,  
    36.                                             IN MINIDUMP_TYPE    DumpType,  
    37.                                             IN CONST PMINIDUMP_EXCEPTION_INFORMATION    ExceptionParam, OPTIONAL  
    38.                                             IN PVOID                                    UserStreamParam, OPTIONAL  
    39.                                             IN PVOID                                    CallbackParam OPTIONAL  
    40.                                             );  
    41.   
    42. #else  
    43.   
    44. typedef BOOL (WINAPI * MINIDUMP_WRITE_DUMP)(  
    45.                                             IN HANDLE           hProcess,  
    46.                                             IN DWORD            ProcessId,  
    47.                                             IN HANDLE           hFile,  
    48.                                             IN MINIDUMP_TYPE    DumpType,  
    49.                                             IN CONST PMINIDUMP_EXCEPTION_INFORMATION    ExceptionParam, OPTIONAL  
    50.                                             IN PMINIDUMP_USER_STREAM_INFORMATION        UserStreamParam, OPTIONAL  
    51.                                             IN PMINIDUMP_CALLBACK_INFORMATION           CallbackParam OPTIONAL  
    52.                                             );  
    53. #endif //#ifndef _DBGHELP_  
    54.   
    55. // Tool Help functions.  
    56. typedef HANDLE (WINAPI * CREATE_TOOL_HELP32_SNAPSHOT)(DWORD dwFlags, DWORD th32ProcessID);  
    57. typedef BOOL (WINAPI * MODULE32_FIRST)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);  
    58. typedef BOOL (WINAPI * MODULE32_NEST)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);  
    59.   
    60.   
    61. extern void WINAPI Create_Dump(PEXCEPTION_POINTERS pException, BOOL File_Flag, BOOL Show_Flag);  
    62.   
    63. extern HMODULE  hDbgHelp;  
    64. extern MINIDUMP_WRITE_DUMP  MiniDumpWriteDump_;  
    65.   
    66. extern CREATE_TOOL_HELP32_SNAPSHOT  CreateToolhelp32Snapshot_;  
    67. extern MODULE32_FIRST   Module32First_;  
    68. extern MODULE32_NEST    Module32Next_;  

    MiniDump.cpp

    1. /* 
    2.     Author: Vladimir Sedach. 
    3.  
    4.     Purpose: demo of Call Stack creation by our own means, 
    5.     and with MiniDumpWriteDump() function of DbgHelp.dll. 
    6. */  
    7.   
    8. #include "StdAfx.h"  
    9. #include "MiniDump.h"  
    10. #include <Shlwapi.h>  
    11.   
    12. #pragma comment(lib,"shlwapi.lib")  
    13.   
    14. HMODULE hDbgHelp;  
    15. MINIDUMP_WRITE_DUMP MiniDumpWriteDump_;  
    16.   
    17. CREATE_TOOL_HELP32_SNAPSHOT CreateToolhelp32Snapshot_;  
    18. MODULE32_FIRST  Module32First_;  
    19. MODULE32_NEST   Module32Next_;  
    20.   
    21. #define DUMP_SIZE_MAX   8000    //max size of our dump  
    22. #define CALL_TRACE_MAX  ((DUMP_SIZE_MAX - 2000) / (MAX_PATH + 40))  //max number of traced calls  
    23. #define NL              " "  //new line  
    24.   
    25. extern CString GetExePath();  
    26.   
    27. //****************************************************************************************  
    28. BOOL WINAPI Get_Module_By_Ret_Addr(PBYTE Ret_Addr, PCHAR Module_Name, PBYTE & Module_Addr)  
    29. //****************************************************************************************  
    30. // Find module by Ret_Addr (address in the module).  
    31. // Return Module_Name (full path) and Module_Addr (start address).  
    32. // Return TRUE if found.  
    33. {  
    34.     MODULEENTRY32   M = {sizeof(M)};  
    35.     HANDLE  hSnapshot;  
    36.   
    37.     Module_Name[0] = 0;  
    38.       
    39.     if (CreateToolhelp32Snapshot_)  
    40.     {  
    41.         hSnapshot = CreateToolhelp32Snapshot_(TH32CS_SNAPMODULE, 0);  
    42.           
    43.         if ((hSnapshot != INVALID_HANDLE_VALUE) &&  
    44.             Module32First_(hSnapshot, &M))  
    45.         {  
    46.             do  
    47.             {  
    48.                 if (DWORD(Ret_Addr - M.modBaseAddr) < M.modBaseSize)  
    49.                 {  
    50.                     lstrcpyn(Module_Name, M.szExePath, MAX_PATH);  
    51.                     Module_Addr = M.modBaseAddr;  
    52.                     break;  
    53.                 }  
    54.             } while (Module32Next_(hSnapshot, &M));  
    55.         }  
    56.   
    57.         CloseHandle(hSnapshot);  
    58.     }  
    59.   
    60.     return !!Module_Name[0];  
    61. //Get_Module_By_Ret_Addr  
    62.   
    63. //******************************************************************  
    64. int WINAPI Get_Call_Stack(PEXCEPTION_POINTERS pException, PCHAR Str)  
    65. //******************************************************************  
    66. // Fill Str with call stack info.  
    67. // pException can be either GetExceptionInformation() or NULL.  
    68. // If pException = NULL - get current call stack.  
    69. {  
    70.     CHAR    Module_Name[MAX_PATH];  
    71.     PBYTE   Module_Addr = 0;  
    72.     PBYTE   Module_Addr_1;  
    73.     int     Str_Len;  
    74.       
    75.     typedef struct STACK  
    76.     {  
    77.         STACK * Ebp;  
    78.         PBYTE   Ret_Addr;  
    79.         DWORD   Param[0];  
    80.     } STACK, * PSTACK;  
    81.   
    82.     STACK   Stack = {0, 0};  
    83.     PSTACK  Ebp;  
    84.   
    85.     if (pException)     //fake frame for exception address  
    86.     {  
    87.         Stack.Ebp = (PSTACK)pException->ContextRecord->Ebp;  
    88.         Stack.Ret_Addr = (PBYTE)pException->ExceptionRecord->ExceptionAddress;  
    89.         Ebp = &Stack;  
    90.     }  
    91.     else  
    92.     {  
    93.         Ebp = (PSTACK)&pException - 1;  //frame addr of Get_Call_Stack()  
    94.   
    95.         // Skip frame of Get_Call_Stack().  
    96.         if (!IsBadReadPtr(Ebp, sizeof(PSTACK)))  
    97.             Ebp = Ebp->Ebp;      //caller ebp  
    98.     }  
    99.   
    100.     Str[0] = 0;  
    101.     Str_Len = 0;  
    102.   
    103.     // Trace CALL_TRACE_MAX calls maximum - not to exceed DUMP_SIZE_MAX.  
    104.     // Break trace on wrong stack frame.  
    105.     for (int Ret_Addr_I = 0;  
    106.         (Ret_Addr_I < CALL_TRACE_MAX) && !IsBadReadPtr(Ebp, sizeof(PSTACK)) && !IsBadCodePtr(FARPROC(Ebp->Ret_Addr));  
    107.         Ret_Addr_I++, Ebp = Ebp->Ebp)  
    108.     {  
    109.         // If module with Ebp->Ret_Addr found.  
    110.         if (Get_Module_By_Ret_Addr(Ebp->Ret_Addr, Module_Name, Module_Addr_1))  
    111.         {  
    112.             if (Module_Addr_1 != Module_Addr)   //new module  
    113.             {  
    114.                 // Save module's address and full path.  
    115.                 Module_Addr = Module_Addr_1;  
    116.                 Str_Len += wsprintf(Str + Str_Len, NL "%08X  %s", Module_Addr, Module_Name);  
    117.             }  
    118.   
    119.             // Save call offset.  
    120.             Str_Len += wsprintf(Str + Str_Len,  
    121.                 NL "  +%08X", Ebp->Ret_Addr - Module_Addr);  
    122.   
    123.             // Save 5 params of the call. We don't know the real number of params.  
    124.             if (pException && !Ret_Addr_I)  //fake frame for exception address  
    125.                 Str_Len += wsprintf(Str + Str_Len, "  Exception Offset");  
    126.             else if (!IsBadReadPtr(Ebp, sizeof(PSTACK) + 5 * sizeof(DWORD)))  
    127.             {  
    128.                 Str_Len += wsprintf(Str + Str_Len, "  (%X, %X, %X, %X, %X)",  
    129.                     Ebp->Param[0], Ebp->Param[1], Ebp->Param[2], Ebp->Param[3], Ebp->Param[4]);  
    130.             }  
    131.         }  
    132.         else  
    133.             Str_Len += wsprintf(Str + Str_Len, NL "%08X", Ebp->Ret_Addr);  
    134.     }  
    135.   
    136.     return Str_Len;  
    137. //Get_Call_Stack  
    138.   
    139. //***********************************  
    140. int WINAPI Get_Version_Str(PCHAR Str)  
    141. //***********************************  
    142. // Fill Str with Windows version.  
    143. {  
    144.     OSVERSIONINFOEX V = {sizeof(OSVERSIONINFOEX)};  //EX for NT 5.0 and later  
    145.   
    146.     if (!GetVersionEx((POSVERSIONINFO)&V))  
    147.     {  
    148.         ZeroMemory(&V, sizeof(V));  
    149.         V.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);  
    150.         GetVersionEx((POSVERSIONINFO)&V);  
    151.     }  
    152.   
    153.     if (V.dwPlatformId != VER_PLATFORM_WIN32_NT)  
    154.         V.dwBuildNumber = LOWORD(V.dwBuildNumber);  //for 9x HIWORD(dwBuildNumber) = 0x04xx  
    155.   
    156.     return wsprintf(Str,  
    157.         NL "Windows:  %d.%d.%d, SP %d.%d, Product Type %d"//SP - service pack, Product Type - VER_NT_WORKSTATION,...  
    158.         V.dwMajorVersion, V.dwMinorVersion, V.dwBuildNumber, V.wServicePackMajor, V.wServicePackMinor/*, V.wProductType*/);  
    159. //Get_Version_Str  
    160.   
    161. //*************************************************************  
    162. PCHAR WINAPI Get_Exception_Info(PEXCEPTION_POINTERS pException)  
    163. //*************************************************************  
    164. // Allocate Str[DUMP_SIZE_MAX] and return Str with dump, if !pException - just return call stack in Str.  
    165. {  
    166.     PCHAR       Str;  
    167.     int         Str_Len;  
    168.     int         i;  
    169.     CHAR        Module_Name[MAX_PATH];  
    170.     PBYTE       Module_Addr;  
    171.     HANDLE      hFile;  
    172.     FILETIME    Last_Write_Time;  
    173.     FILETIME    Local_File_Time;  
    174.     SYSTEMTIME  T;  
    175.       
    176.     Str = new CHAR[DUMP_SIZE_MAX];  
    177.   
    178.     if (!Str)  
    179.         return NULL;  
    180.   
    181.     Str_Len = 0;  
    182.     Str_Len += Get_Version_Str(Str + Str_Len);  
    183.   
    184.     Str_Len += wsprintf(Str + Str_Len, NL "Process:  ");  
    185.     GetModuleFileName(NULL, Str + Str_Len, MAX_PATH);  
    186.     Str_Len = lstrlen(Str);  
    187.   
    188.     // If exception occurred.  
    189.     if (pException)  
    190.     {  
    191.         EXCEPTION_RECORD &  E = *pException->ExceptionRecord;  
    192.         CONTEXT &           C = *pException->ContextRecord;  
    193.   
    194.         // If module with E.ExceptionAddress found - save its path and date.  
    195.         if (Get_Module_By_Ret_Addr((PBYTE)E.ExceptionAddress, Module_Name, Module_Addr))  
    196.         {  
    197.             Str_Len += wsprintf(Str + Str_Len,  
    198.                 NL "Module:  %s", Module_Name);  
    199.   
    200.             if ((hFile = CreateFile(Module_Name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,  
    201.                 FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE)  
    202.             {  
    203.                 if (GetFileTime(hFile, NULL, NULL, &Last_Write_Time))  
    204.                 {  
    205.                     FileTimeToLocalFileTime(&Last_Write_Time, &Local_File_Time);  
    206.                     FileTimeToSystemTime(&Local_File_Time, &T);  
    207.   
    208.                     Str_Len += wsprintf(Str + Str_Len,  
    209.                         NL "Date Modified:  %02d/%02d/%d",  
    210.                         T.wMonth, T.wDay, T.wYear);  
    211.                 }  
    212.                 CloseHandle(hFile);  
    213.             }  
    214.         }  
    215.         else  
    216.         {  
    217.             Str_Len += wsprintf(Str + Str_Len,  
    218.                 NL "Exception Addr:  %08X", E.ExceptionAddress);  
    219.         }  
    220.           
    221.         Str_Len += wsprintf(Str + Str_Len,  
    222.             NL "Exception Code:  %08X", E.ExceptionCode);  
    223.           
    224.         if (E.ExceptionCode == EXCEPTION_ACCESS_VIOLATION)  
    225.         {  
    226.             // Access violation type - Write/Read.  
    227.             Str_Len += wsprintf(Str + Str_Len,  
    228.                 NL "%s Address:  %08X",  
    229.                 (E.ExceptionInformation[0]) ? "Write" : "Read", E.ExceptionInformation[1]);  
    230.         }  
    231.   
    232.         // Save instruction that caused exception.  
    233.         Str_Len += wsprintf(Str + Str_Len, NL "Instruction: ");  
    234.         for (i = 0; i < 16; i++)  
    235.             Str_Len += wsprintf(Str + Str_Len, " %02X"PBYTE(E.ExceptionAddress)[i]);  
    236.   
    237.         // Save registers at exception.  
    238.         Str_Len += wsprintf(Str + Str_Len, NL "Registers:");  
    239.         Str_Len += wsprintf(Str + Str_Len, NL "EAX: %08X  EBX: %08X  ECX: %08X  EDX: %08X", C.Eax, C.Ebx, C.Ecx, C.Edx);  
    240.         Str_Len += wsprintf(Str + Str_Len, NL "ESI: %08X  EDI: %08X  ESP: %08X  EBP: %08X", C.Esi, C.Edi, C.Esp, C.Ebp);  
    241.         Str_Len += wsprintf(Str + Str_Len, NL "EIP: %08X  EFlags: %08X", C.Eip, C.EFlags);  
    242.     } //if (pException)  
    243.       
    244.     // Save call stack info.  
    245.     Str_Len += wsprintf(Str + Str_Len, NL "Call Stack:");  
    246.     Get_Call_Stack(pException, Str + Str_Len);  
    247.   
    248.     if (Str[0] == NL[0])  
    249.         lstrcpy(Str, Str + sizeof(NL) - 1);  
    250.   
    251.     return Str;  
    252. //Get_Exception_Info  
    253.   
    254. //*************************************************************************************  
    255. void WINAPI Create_Dump(PEXCEPTION_POINTERS pException, BOOL File_Flag, BOOL Show_Flag)  
    256. //*************************************************************************************  
    257. // Create dump.   
    258. // pException can be either GetExceptionInformation() or NULL.  
    259. // If File_Flag = TRUE - write dump files (.dmz and .dmp) with the name of the current process.  
    260. // If Show_Flag = TRUE - show message with Get_Exception_Info() dump.  
    261. {  
    262.     HANDLE  hDump_File;  
    263.     PCHAR   Str;  
    264.     DWORD   Bytes;  
    265.     DWORD   nLen = 0;  
    266.   
    267.     CString strDir,strTXTFile,strDMPFile;  
    268.     CString strDate,strTotal;  
    269.     CTime   tm = CTime::GetCurrentTime();  
    270.       
    271.     strDir.Format(_T("%s\Log"),GetExePath());  
    272.     strTXTFile.Format(_T("%s\Log\%04d-%02d-%02d %02d%02d%02d.txt"),GetExePath(),tm.GetYear(),tm.GetMonth(),  
    273.         tm.GetDay(),tm.GetHour(),tm.GetMinute(),tm.GetSecond());  
    274.     strDMPFile.Format(_T("%s\Log\%04d-%02d-%02d %02d%02d%02d.dmp"),GetExePath(),tm.GetYear(),tm.GetMonth(),  
    275.         tm.GetDay(),tm.GetHour(),tm.GetMinute(),tm.GetSecond());  
    276.   
    277.     if(!PathFileExists(strDir))  
    278.         CreateDirectory(strDir,NULL);  
    279.   
    280.     Str = Get_Exception_Info(pException);  
    281.   
    282.     //if (Show_Flag && Str)  
    283.     //  MessageBox(NULL, Str, "MiniDump", MB_ICONHAND | MB_OK);  
    284.   
    285.     if (File_Flag)  
    286.     {  
    287.         if (Str)  
    288.         {  
    289.             hDump_File = CreateFile(strTXTFile,  
    290.                 GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);  
    291.               
    292.             nLen = lstrlen(Str);  
    293.             Str[nLen] = '';  
    294.   
    295.             WriteFile(hDump_File, Str, lstrlen(Str) + 1, &Bytes, NULL);  
    296.   
    297.             CloseHandle(hDump_File);  
    298.         }  
    299.   
    300.         // If MiniDumpWriteDump() of DbgHelp.dll available.  
    301.         if (MiniDumpWriteDump_)  
    302.         {  
    303.             MINIDUMP_EXCEPTION_INFORMATION  M;  
    304.   
    305.             M.ThreadId = GetCurrentThreadId();  
    306.             M.ExceptionPointers = pException;  
    307.             M.ClientPointers = 0;  
    308.   
    309.             hDump_File = CreateFile(strDMPFile,  
    310.                 GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);  
    311.   
    312.             MiniDumpWriteDump_(GetCurrentProcess(), GetCurrentProcessId(), hDump_File,  
    313.                 MiniDumpNormal, (pException) ? &M : NULL, NULL, NULL);  
    314.   
    315.             CloseHandle(hDump_File);  
    316.         }  
    317.     } //if (File_Flag)  
    318.   
    319.     delete Str;  
    320. //Create_Dump  


    具体参考方法如下:

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

    1. SetUnhandledExceptionFilter(CrashReportEx);  
    2. HMODULE hKernel32;  
    3.   
    4. // Try to get MiniDumpWriteDump() address.  
    5. hDbgHelp = LoadLibrary("DBGHELP.DLL");  
    6. MiniDumpWriteDump_ = (MINIDUMP_WRITE_DUMP)GetProcAddress(hDbgHelp, "MiniDumpWriteDump");  
    7. //  d("hDbgHelp=%X, MiniDumpWriteDump_=%X", hDbgHelp, MiniDumpWriteDump_);  
    8.   
    9. // Try to get Tool Help library functions.  
    10. hKernel32 = GetModuleHandle("KERNEL32");  
    11. CreateToolhelp32Snapshot_ = (CREATE_TOOL_HELP32_SNAPSHOT)GetProcAddress(hKernel32, "CreateToolhelp32Snapshot");  
    12. Module32First_ = (MODULE32_FIRST)GetProcAddress(hKernel32, "Module32First");  
    13. Module32Next_ = (MODULE32_NEST)GetProcAddress(hKernel32, "Module32Next");  

    测试工程下载地址:

    http://download.csdn.net/source/3575167

    更多信息,请移步VC驿站:利用WinDbg找出程序崩溃的代码行号

    from:http://blog.csdn.net/wangningyu/article/details/6748138

  • 相关阅读:
    OnEraseBkgnd、OnPaint与画面重绘
    .编译ADO类DLL时报错的解决方案
    VC列表框样式
    Codeforces 131D. Subway 寻找环树的最短路径
    Codeforces 103B. Cthulhu 寻找奈亚子
    Codeforces 246D. Colorful Graph
    Codeforces 278C. Learning Languages 图的遍历
    Codeforces 217A. Ice Skating 搜索
    Codeforces 107A. Dorm Water Supply 搜图
    Codeforces 263 D. Cycle in Graph 环
  • 原文地址:https://www.cnblogs.com/lidabo/p/3635992.html
Copyright © 2020-2023  润新知