調試技巧 —— 如何利用windbg + dump + map剖析器異常

來源:互聯網
上載者:User

之前碰到論壇裡有幾個好友,說程式不時的崩潰,什麼xxoo不能read的! 如果光要是這個記憶體位址,估計你會瘋掉~~

所以分享一下基本的調試技巧,需要準備的工具有WinDbg + VC6.0,

下面是自己整理的一份自動產生DUMP檔案的原始碼,只需要添加到工程即可,原始碼如下:

MiniDump.h

#include <windows.h>#include <tlhelp32.h>//#include "dbghelp.h"//#define DEBUG_DPRINTF1//allow d()//#include "wfun.h"#pragma optimize("y", off)//generate stack frame pointers for all functions - same as /Oy- in the project#pragma warning(disable: 4200)//nonstandard extension used : zero-sized array in struct/union#pragma warning(disable: 4100)//unreferenced formal parameter/*BOOL WINAPI Get_Module_By_Ret_Addr(PBYTE Ret_Addr, PCHAR Module_Name, PBYTE & Module_Addr);int WINAPI Get_Call_Stack(PEXCEPTION_POINTERS pException, PCHAR Str);int  WINAPI Get_Version_Str(PCHAR Str);PCHAR WINAPI Get_Exception_Info(PEXCEPTION_POINTERS pException);void WINAPI Create_Dump(PEXCEPTION_POINTERS pException, BOOL File_Flag, BOOL Show_Flag);*/// In case you don't have dbghelp.h.#ifndef _DBGHELP_typedef struct _MINIDUMP_EXCEPTION_INFORMATION {DWORDThreadId;PEXCEPTION_POINTERSExceptionPointers;BOOLClientPointers;} MINIDUMP_EXCEPTION_INFORMATION, *PMINIDUMP_EXCEPTION_INFORMATION;typedef enum _MINIDUMP_TYPE {MiniDumpNormal =0x00000000,MiniDumpWithDataSegs =0x00000001,} MINIDUMP_TYPE;typedefBOOL (WINAPI * MINIDUMP_WRITE_DUMP)(IN HANDLEhProcess,IN DWORDProcessId,IN HANDLEhFile,IN MINIDUMP_TYPEDumpType,IN CONST PMINIDUMP_EXCEPTION_INFORMATIONExceptionParam, OPTIONALIN PVOIDUserStreamParam, OPTIONALIN PVOIDCallbackParam OPTIONAL);#elsetypedefBOOL (WINAPI * MINIDUMP_WRITE_DUMP)(IN HANDLEhProcess,IN DWORDProcessId,IN HANDLEhFile,IN MINIDUMP_TYPEDumpType,IN CONST PMINIDUMP_EXCEPTION_INFORMATIONExceptionParam, OPTIONALIN PMINIDUMP_USER_STREAM_INFORMATIONUserStreamParam, OPTIONALIN PMINIDUMP_CALLBACK_INFORMATIONCallbackParam OPTIONAL);#endif //#ifndef _DBGHELP_// Tool Help functions.typedefHANDLE (WINAPI * CREATE_TOOL_HELP32_SNAPSHOT)(DWORD dwFlags, DWORD th32ProcessID);typedefBOOL (WINAPI * MODULE32_FIRST)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);typedefBOOL (WINAPI * MODULE32_NEST)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);extern void WINAPI Create_Dump(PEXCEPTION_POINTERS pException, BOOL File_Flag, BOOL Show_Flag);extern HMODULEhDbgHelp;extern MINIDUMP_WRITE_DUMPMiniDumpWriteDump_;extern CREATE_TOOL_HELP32_SNAPSHOTCreateToolhelp32Snapshot_;extern MODULE32_FIRSTModule32First_;extern MODULE32_NESTModule32Next_;

MiniDump.cpp

/*Author:Vladimir Sedach.Purpose: demo of Call Stack creation by our own means,and with MiniDumpWriteDump() function of DbgHelp.dll.*/#include "StdAfx.h"#include "MiniDump.h"#include <Shlwapi.h>#pragma comment(lib,"shlwapi.lib")HMODULEhDbgHelp;MINIDUMP_WRITE_DUMPMiniDumpWriteDump_;CREATE_TOOL_HELP32_SNAPSHOTCreateToolhelp32Snapshot_;MODULE32_FIRSTModule32First_;MODULE32_NESTModule32Next_;#defineDUMP_SIZE_MAX8000//max size of our dump#defineCALL_TRACE_MAX((DUMP_SIZE_MAX - 2000) / (MAX_PATH + 40))//max number of traced calls#defineNL"\r\n"//new lineextern CString GetExePath();//****************************************************************************************BOOL WINAPI Get_Module_By_Ret_Addr(PBYTE Ret_Addr, PCHAR Module_Name, PBYTE & Module_Addr)//****************************************************************************************// Find module by Ret_Addr (address in the module).// Return Module_Name (full path) and Module_Addr (start address).// Return TRUE if found.{MODULEENTRY32M = {sizeof(M)};HANDLEhSnapshot;Module_Name[0] = 0;if (CreateToolhelp32Snapshot_){hSnapshot = CreateToolhelp32Snapshot_(TH32CS_SNAPMODULE, 0);if ((hSnapshot != INVALID_HANDLE_VALUE) &&Module32First_(hSnapshot, &M)){do{if (DWORD(Ret_Addr - M.modBaseAddr) < M.modBaseSize){lstrcpyn(Module_Name, M.szExePath, MAX_PATH);Module_Addr = M.modBaseAddr;break;}} while (Module32Next_(hSnapshot, &M));}CloseHandle(hSnapshot);}return !!Module_Name[0];} //Get_Module_By_Ret_Addr//******************************************************************int WINAPI Get_Call_Stack(PEXCEPTION_POINTERS pException, PCHAR Str)//******************************************************************// Fill Str with call stack info.// pException can be either GetExceptionInformation() or NULL.// If pException = NULL - get current call stack.{CHARModule_Name[MAX_PATH];PBYTEModule_Addr = 0;PBYTEModule_Addr_1;intStr_Len;typedef struct STACK{STACK *Ebp;PBYTERet_Addr;DWORDParam[0];} STACK, * PSTACK;STACKStack = {0, 0};PSTACKEbp;if (pException)//fake frame for exception address{Stack.Ebp = (PSTACK)pException->ContextRecord->Ebp;Stack.Ret_Addr = (PBYTE)pException->ExceptionRecord->ExceptionAddress;Ebp = &Stack;}else{Ebp = (PSTACK)&pException - 1;//frame addr of Get_Call_Stack()// Skip frame of Get_Call_Stack().if (!IsBadReadPtr(Ebp, sizeof(PSTACK)))Ebp = Ebp->Ebp;//caller ebp}Str[0] = 0;Str_Len = 0;// Trace CALL_TRACE_MAX calls maximum - not to exceed DUMP_SIZE_MAX.// Break trace on wrong stack frame.for (int Ret_Addr_I = 0;(Ret_Addr_I < CALL_TRACE_MAX) && !IsBadReadPtr(Ebp, sizeof(PSTACK)) && !IsBadCodePtr(FARPROC(Ebp->Ret_Addr));Ret_Addr_I++, Ebp = Ebp->Ebp){// If module with Ebp->Ret_Addr found.if (Get_Module_By_Ret_Addr(Ebp->Ret_Addr, Module_Name, Module_Addr_1)){if (Module_Addr_1 != Module_Addr)//new module{// Save module's address and full path.Module_Addr = Module_Addr_1;Str_Len += wsprintf(Str + Str_Len, NL "%08X  %s", Module_Addr, Module_Name);}// Save call offset.Str_Len += wsprintf(Str + Str_Len,NL "  +%08X", Ebp->Ret_Addr - Module_Addr);// Save 5 params of the call. We don't know the real number of params.if (pException && !Ret_Addr_I)//fake frame for exception addressStr_Len += wsprintf(Str + Str_Len, "  Exception Offset");else if (!IsBadReadPtr(Ebp, sizeof(PSTACK) + 5 * sizeof(DWORD))){Str_Len += wsprintf(Str + Str_Len, "  (%X, %X, %X, %X, %X)",Ebp->Param[0], Ebp->Param[1], Ebp->Param[2], Ebp->Param[3], Ebp->Param[4]);}}elseStr_Len += wsprintf(Str + Str_Len, NL "%08X", Ebp->Ret_Addr);}return Str_Len;} //Get_Call_Stack//***********************************int WINAPI Get_Version_Str(PCHAR Str)//***********************************// Fill Str with Windows version.{OSVERSIONINFOEXV = {sizeof(OSVERSIONINFOEX)};//EX for NT 5.0 and laterif (!GetVersionEx((POSVERSIONINFO)&V)){ZeroMemory(&V, sizeof(V));V.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);GetVersionEx((POSVERSIONINFO)&V);}if (V.dwPlatformId != VER_PLATFORM_WIN32_NT)V.dwBuildNumber = LOWORD(V.dwBuildNumber);//for 9x HIWORD(dwBuildNumber) = 0x04xxreturn wsprintf(Str,NL "Windows:  %d.%d.%d, SP %d.%d, Product Type %d",//SP - service pack, Product Type - VER_NT_WORKSTATION,...V.dwMajorVersion, V.dwMinorVersion, V.dwBuildNumber, V.wServicePackMajor, V.wServicePackMinor/*, V.wProductType*/);} //Get_Version_Str//*************************************************************PCHAR WINAPI Get_Exception_Info(PEXCEPTION_POINTERS pException)//*************************************************************// Allocate Str[DUMP_SIZE_MAX] and return Str with dump, if !pException - just return call stack in Str.{PCHARStr;intStr_Len;inti;CHARModule_Name[MAX_PATH];PBYTEModule_Addr;HANDLEhFile;FILETIMELast_Write_Time;FILETIMELocal_File_Time;SYSTEMTIMET;Str = new CHAR[DUMP_SIZE_MAX];if (!Str)return NULL;Str_Len = 0;Str_Len += Get_Version_Str(Str + Str_Len);Str_Len += wsprintf(Str + Str_Len, NL "Process:  ");GetModuleFileName(NULL, Str + Str_Len, MAX_PATH);Str_Len = lstrlen(Str);// If exception occurred.if (pException){EXCEPTION_RECORD &E = *pException->ExceptionRecord;CONTEXT &C = *pException->ContextRecord;// If module with E.ExceptionAddress found - save its path and date.if (Get_Module_By_Ret_Addr((PBYTE)E.ExceptionAddress, Module_Name, Module_Addr)){Str_Len += wsprintf(Str + Str_Len,NL "Module:  %s", Module_Name);if ((hFile = CreateFile(Module_Name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE){if (GetFileTime(hFile, NULL, NULL, &Last_Write_Time)){FileTimeToLocalFileTime(&Last_Write_Time, &Local_File_Time);FileTimeToSystemTime(&Local_File_Time, &T);Str_Len += wsprintf(Str + Str_Len,NL "Date Modified:  %02d/%02d/%d",T.wMonth, T.wDay, T.wYear);}CloseHandle(hFile);}}else{Str_Len += wsprintf(Str + Str_Len,NL "Exception Addr:  %08X", E.ExceptionAddress);}Str_Len += wsprintf(Str + Str_Len,NL "Exception Code:  %08X", E.ExceptionCode);if (E.ExceptionCode == EXCEPTION_ACCESS_VIOLATION){// Access violation type - Write/Read.Str_Len += wsprintf(Str + Str_Len,NL "%s Address:  %08X",(E.ExceptionInformation[0]) ? "Write" : "Read", E.ExceptionInformation[1]);}// Save instruction that caused exception.Str_Len += wsprintf(Str + Str_Len, NL "Instruction: ");for (i = 0; i < 16; i++)Str_Len += wsprintf(Str + Str_Len, " %02X", PBYTE(E.ExceptionAddress)[i]);// Save registers at exception.Str_Len += wsprintf(Str + Str_Len, NL "Registers:");Str_Len += wsprintf(Str + Str_Len, NL "EAX: %08X  EBX: %08X  ECX: %08X  EDX: %08X", C.Eax, C.Ebx, C.Ecx, C.Edx);Str_Len += wsprintf(Str + Str_Len, NL "ESI: %08X  EDI: %08X  ESP: %08X  EBP: %08X", C.Esi, C.Edi, C.Esp, C.Ebp);Str_Len += wsprintf(Str + Str_Len, NL "EIP: %08X  EFlags: %08X", C.Eip, C.EFlags);} //if (pException)// Save call stack info.Str_Len += wsprintf(Str + Str_Len, NL "Call Stack:");Get_Call_Stack(pException, Str + Str_Len);if (Str[0] == NL[0])lstrcpy(Str, Str + sizeof(NL) - 1);return Str;} //Get_Exception_Info//*************************************************************************************void WINAPI Create_Dump(PEXCEPTION_POINTERS pException, BOOL File_Flag, BOOL Show_Flag)//*************************************************************************************// Create dump. // pException can be either GetExceptionInformation() or NULL.// If File_Flag = TRUE - write dump files (.dmz and .dmp) with the name of the current process.// If Show_Flag = TRUE - show message with Get_Exception_Info() dump.{HANDLEhDump_File;PCHARStr;DWORDBytes;DWORDnLen = 0;CString strDir,strTXTFile,strDMPFile;CString strDate,strTotal;CTimetm = CTime::GetCurrentTime();strDir.Format(_T("%s\\Log"),GetExePath());strTXTFile.Format(_T("%s\\Log\\%04d-%02d-%02d %02d%02d%02d.txt"),GetExePath(),tm.GetYear(),tm.GetMonth(),tm.GetDay(),tm.GetHour(),tm.GetMinute(),tm.GetSecond());strDMPFile.Format(_T("%s\\Log\\%04d-%02d-%02d %02d%02d%02d.dmp"),GetExePath(),tm.GetYear(),tm.GetMonth(),tm.GetDay(),tm.GetHour(),tm.GetMinute(),tm.GetSecond());if(!PathFileExists(strDir))CreateDirectory(strDir,NULL);Str = Get_Exception_Info(pException);//if (Show_Flag && Str)//MessageBox(NULL, Str, "MiniDump", MB_ICONHAND | MB_OK);if (File_Flag){if (Str){hDump_File = CreateFile(strTXTFile,GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);nLen = lstrlen(Str);Str[nLen] = '\0';WriteFile(hDump_File, Str, lstrlen(Str) + 1, &Bytes, NULL);CloseHandle(hDump_File);}// If MiniDumpWriteDump() of DbgHelp.dll available.if (MiniDumpWriteDump_){MINIDUMP_EXCEPTION_INFORMATIONM;M.ThreadId = GetCurrentThreadId();M.ExceptionPointers = pException;M.ClientPointers = 0;hDump_File = CreateFile(strDMPFile,GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);MiniDumpWriteDump_(GetCurrentProcess(), GetCurrentProcessId(), hDump_File,MiniDumpNormal, (pException) ? &M : NULL, NULL, NULL);CloseHandle(hDump_File);}} //if (File_Flag)delete Str;} //Create_Dump

具體參考方法如下:

1、在CXXDlg::OnInitDialog()中添加這樣一段:

SetUnhandledExceptionFilter(CrashReportEx);HMODULEhKernel32;// 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");

測試工程:

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

更多資訊,請移步VC驛站:利用WinDbg找出程式崩潰的程式碼號

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.