• 调试技巧 —— 如何利用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

  • 相关阅读:
    eventbus 备注
    Retrofit 备注
    RxJava 备注
    dagger2 备注
    JVM 备注
    UI控件(UIPickerView)
    Android 知识杂记(MVP模式)
    UI控件(UIToolbar)
    UI控件(UIAlertController)
    UI控件(UIScrollView)
  • 原文地址:https://www.cnblogs.com/lidabo/p/3635992.html
Copyright © 2020-2023  润新知