之前碰到论坛里有几个好友,说程序不时的崩溃,什么xxoo不能read的! 如果光要是这个内存地址,估计你会疯掉~~
所以分享一下基本的调试技巧,需要准备的工具有WinDbg + VC6.0,
下面是自己整理的一份自动生成DUMP文件的源代码,只需要添加到工程即可,源代码如下:
MiniDump.h
view plain copy to clipboard print ?
- #include <windows.h>
- #include <tlhelp32.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
-
-
-
-
-
-
-
-
- #ifndef _DBGHELP_
-
- typedef struct _MINIDUMP_EXCEPTION_INFORMATION {
- DWORD ThreadId;
- PEXCEPTION_POINTERS ExceptionPointers;
- BOOL ClientPointers;
- } MINIDUMP_EXCEPTION_INFORMATION, *PMINIDUMP_EXCEPTION_INFORMATION;
-
- typedef enum _MINIDUMP_TYPE {
- MiniDumpNormal = 0x00000000,
- MiniDumpWithDataSegs = 0x00000001,
- } MINIDUMP_TYPE;
-
- typedef BOOL (WINAPI * MINIDUMP_WRITE_DUMP)(
- IN HANDLE hProcess,
- IN DWORD ProcessId,
- IN HANDLE hFile,
- IN MINIDUMP_TYPE DumpType,
- IN CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, OPTIONAL
- IN PVOID UserStreamParam, OPTIONAL
- IN PVOID CallbackParam OPTIONAL
- );
-
- #else
-
- typedef BOOL (WINAPI * MINIDUMP_WRITE_DUMP)(
- IN HANDLE hProcess,
- IN DWORD ProcessId,
- IN HANDLE hFile,
- IN MINIDUMP_TYPE DumpType,
- IN CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, OPTIONAL
- IN PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, OPTIONAL
- IN PMINIDUMP_CALLBACK_INFORMATION CallbackParam OPTIONAL
- );
- #endif //#ifndef _DBGHELP_
-
-
- typedef HANDLE (WINAPI * CREATE_TOOL_HELP32_SNAPSHOT)(DWORD dwFlags, DWORD th32ProcessID);
- typedef BOOL (WINAPI * MODULE32_FIRST)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
- typedef BOOL (WINAPI * MODULE32_NEST)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
-
-
- extern void WINAPI Create_Dump(PEXCEPTION_POINTERS pException, BOOL File_Flag, BOOL Show_Flag);
-
- extern HMODULE hDbgHelp;
- extern MINIDUMP_WRITE_DUMP MiniDumpWriteDump_;
-
- extern CREATE_TOOL_HELP32_SNAPSHOT CreateToolhelp32Snapshot_;
- extern MODULE32_FIRST Module32First_;
- extern MODULE32_NEST Module32Next_;
#include <windows.h> #include <tlhelp32.h> //#include "dbghelp.h" //#define DEBUG_DPRINTF 1 //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 { DWORD ThreadId; PEXCEPTION_POINTERS ExceptionPointers; BOOL ClientPointers; } MINIDUMP_EXCEPTION_INFORMATION, *PMINIDUMP_EXCEPTION_INFORMATION; typedef enum _MINIDUMP_TYPE { MiniDumpNormal = 0x00000000, MiniDumpWithDataSegs = 0x00000001, } MINIDUMP_TYPE; typedef BOOL (WINAPI * MINIDUMP_WRITE_DUMP)( IN HANDLE hProcess, IN DWORD ProcessId, IN HANDLE hFile, IN MINIDUMP_TYPE DumpType, IN CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, OPTIONAL IN PVOID UserStreamParam, OPTIONAL IN PVOID CallbackParam OPTIONAL ); #else typedef BOOL (WINAPI * MINIDUMP_WRITE_DUMP)( IN HANDLE hProcess, IN DWORD ProcessId, IN HANDLE hFile, IN MINIDUMP_TYPE DumpType, IN CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, OPTIONAL IN PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, OPTIONAL IN PMINIDUMP_CALLBACK_INFORMATION CallbackParam OPTIONAL ); #endif //#ifndef _DBGHELP_ // Tool Help functions. typedef HANDLE (WINAPI * CREATE_TOOL_HELP32_SNAPSHOT)(DWORD dwFlags, DWORD th32ProcessID); typedef BOOL (WINAPI * MODULE32_FIRST)(HANDLE hSnapshot, LPMODULEENTRY32 lpme); typedef BOOL (WINAPI * MODULE32_NEST)(HANDLE hSnapshot, LPMODULEENTRY32 lpme); extern void WINAPI Create_Dump(PEXCEPTION_POINTERS pException, BOOL File_Flag, BOOL Show_Flag); extern HMODULE hDbgHelp; extern MINIDUMP_WRITE_DUMP MiniDumpWriteDump_; extern CREATE_TOOL_HELP32_SNAPSHOT CreateToolhelp32Snapshot_; extern MODULE32_FIRST Module32First_; extern MODULE32_NEST Module32Next_;
MiniDump.cpp
view plain copy to clipboard print ?
-
-
-
-
-
-
-
- #include "StdAfx.h"
- #include "MiniDump.h"
- #include <Shlwapi.h>
-
- #pragma comment(lib,"shlwapi.lib")
-
- HMODULE hDbgHelp;
- MINIDUMP_WRITE_DUMP MiniDumpWriteDump_;
-
- CREATE_TOOL_HELP32_SNAPSHOT CreateToolhelp32Snapshot_;
- MODULE32_FIRST Module32First_;
- MODULE32_NEST Module32Next_;
-
- #define DUMP_SIZE_MAX 8000 //max size of our dump
- #define CALL_TRACE_MAX ((DUMP_SIZE_MAX - 2000) / (MAX_PATH + 40)) //max number of traced calls
- #define NL "\r\n" //new line
-
- extern CString GetExePath();
-
-
- BOOL WINAPI Get_Module_By_Ret_Addr(PBYTE Ret_Addr, PCHAR Module_Name, PBYTE & Module_Addr)
-
-
-
-
- {
- MODULEENTRY32 M = {sizeof(M)};
- HANDLE hSnapshot;
-
- 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];
- }
-
-
- int WINAPI Get_Call_Stack(PEXCEPTION_POINTERS pException, PCHAR Str)
-
-
-
-
- {
- CHAR Module_Name[MAX_PATH];
- PBYTE Module_Addr = 0;
- PBYTE Module_Addr_1;
- int Str_Len;
-
- typedef struct STACK
- {
- STACK * Ebp;
- PBYTE Ret_Addr;
- DWORD Param[0];
- } STACK, * PSTACK;
-
- STACK Stack = {0, 0};
- PSTACK Ebp;
-
- if (pException)
- {
- Stack.Ebp = (PSTACK)pException->ContextRecord->Ebp;
- Stack.Ret_Addr = (PBYTE)pException->ExceptionRecord->ExceptionAddress;
- Ebp = &Stack;
- }
- else
- {
- Ebp = (PSTACK)&pException - 1;
-
-
- if (!IsBadReadPtr(Ebp, sizeof(PSTACK)))
- Ebp = Ebp->Ebp;
- }
-
- Str[0] = 0;
- Str_Len = 0;
-
-
-
- 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 (Get_Module_By_Ret_Addr(Ebp->Ret_Addr, Module_Name, Module_Addr_1))
- {
- if (Module_Addr_1 != Module_Addr)
- {
-
- Module_Addr = Module_Addr_1;
- Str_Len += wsprintf(Str + Str_Len, NL "%08X %s", Module_Addr, Module_Name);
- }
-
-
- Str_Len += wsprintf(Str + Str_Len,
- NL " +%08X", Ebp->Ret_Addr - Module_Addr);
-
-
- if (pException && !Ret_Addr_I)
- Str_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]);
- }
- }
- else
- Str_Len += wsprintf(Str + Str_Len, NL "%08X", Ebp->Ret_Addr);
- }
-
- return Str_Len;
- }
-
-
- int WINAPI Get_Version_Str(PCHAR Str)
-
-
- {
- OSVERSIONINFOEX V = {sizeof(OSVERSIONINFOEX)};
-
- if (!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);
-
- return wsprintf(Str,
- NL "Windows: %d.%d.%d, SP %d.%d, Product Type %d",
- V.dwMajorVersion, V.dwMinorVersion, V.dwBuildNumber, V.wServicePackMajor, V.wServicePackMinor/*, V.wProductType*/);
- }
-
-
- PCHAR WINAPI Get_Exception_Info(PEXCEPTION_POINTERS pException)
-
-
- {
- PCHAR Str;
- int Str_Len;
- int i;
- CHAR Module_Name[MAX_PATH];
- PBYTE Module_Addr;
- HANDLE hFile;
- FILETIME Last_Write_Time;
- FILETIME Local_File_Time;
- SYSTEMTIME T;
-
- 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 (pException)
- {
- EXCEPTION_RECORD & E = *pException->ExceptionRecord;
- CONTEXT & C = *pException->ContextRecord;
-
-
- 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)
- {
-
- Str_Len += wsprintf(Str + Str_Len,
- NL "%s Address: %08X",
- (E.ExceptionInformation[0]) ? "Write" : "Read", E.ExceptionInformation[1]);
- }
-
-
- 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]);
-
-
- 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);
- }
-
-
- 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;
- }
-
-
- void WINAPI Create_Dump(PEXCEPTION_POINTERS pException, BOOL File_Flag, BOOL Show_Flag)
-
-
-
-
-
- {
- HANDLE hDump_File;
- PCHAR Str;
- DWORD Bytes;
- DWORD nLen = 0;
-
- CString strDir,strTXTFile,strDMPFile;
- CString strDate,strTotal;
- CTime tm = 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 (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_)
- {
- MINIDUMP_EXCEPTION_INFORMATION M;
-
- 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);
- }
- }
-
- delete Str;
- }
/* 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") HMODULE hDbgHelp; MINIDUMP_WRITE_DUMP MiniDumpWriteDump_; CREATE_TOOL_HELP32_SNAPSHOT CreateToolhelp32Snapshot_; MODULE32_FIRST Module32First_; MODULE32_NEST Module32Next_; #define DUMP_SIZE_MAX 8000 //max size of our dump #define CALL_TRACE_MAX ((DUMP_SIZE_MAX - 2000) / (MAX_PATH + 40)) //max number of traced calls #define NL "\r\n" //new line extern 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. { MODULEENTRY32 M = {sizeof(M)}; HANDLE hSnapshot; 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. { CHAR Module_Name[MAX_PATH]; PBYTE Module_Addr = 0; PBYTE Module_Addr_1; int Str_Len; typedef struct STACK { STACK * Ebp; PBYTE Ret_Addr; DWORD Param[0]; } STACK, * PSTACK; STACK Stack = {0, 0}; PSTACK Ebp; 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 address Str_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]); } } else Str_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. { OSVERSIONINFOEX V = {sizeof(OSVERSIONINFOEX)}; //EX for NT 5.0 and later if (!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) = 0x04xx return 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. { PCHAR Str; int Str_Len; int i; CHAR Module_Name[MAX_PATH]; PBYTE Module_Addr; HANDLE hFile; FILETIME Last_Write_Time; FILETIME Local_File_Time; SYSTEMTIME T; 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. { HANDLE hDump_File; PCHAR Str; DWORD Bytes; DWORD nLen = 0; CString strDir,strTXTFile,strDMPFile; CString strDate,strTotal; CTime tm = 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_INFORMATION M; 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()中添加这样一段:
view plain copy to clipboard print ?
- SetUnhandledExceptionFilter(CrashReportEx);
- HMODULE hKernel32;
-
-
- hDbgHelp = LoadLibrary("DBGHELP.DLL");
- MiniDumpWriteDump_ = (MINIDUMP_WRITE_DUMP)GetProcAddress(hDbgHelp, "MiniDumpWriteDump");
-
-
-
- hKernel32 = GetModuleHandle("KERNEL32");
- CreateToolhelp32Snapshot_ = (CREATE_TOOL_HELP32_SNAPSHOT)GetProcAddress(hKernel32, "CreateToolhelp32Snapshot");
- Module32First_ = (MODULE32_FIRST)GetProcAddress(hKernel32, "Module32First");
- Module32Next_ = (MODULE32_NEST)GetProcAddress(hKernel32, "Module32Next");
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");
测试代码如下:
view plain copy to clipboard print ?
- class CTestDlg : public CDialog
- {
-
- public:
- CTestDlg(CWnd* pParent = NULL);
-
- void Fun1(char *pszBuffer);
- void Fun2(char *pszBuffer);
- void Fun3(char *pszBuffer);
- };
class CTestDlg : public CDialog { // Construction public: CTestDlg(CWnd* pParent = NULL); // standard constructor void Fun1(char *pszBuffer); void Fun2(char *pszBuffer); void Fun3(char *pszBuffer); };
view plain copy to clipboard print ?
- void CTestDlg::Fun1(char *pszBuffer)
- {
- Fun2(pszBuffer);
- }
-
- void CTestDlg::Fun2(char *pszBuffer)
- {
- Fun3(pszBuffer);
- }
-
- void CTestDlg::Fun3(char *pszBuffer)
- {
- pszBuffer[1] = 0x00;
- }
void CTestDlg::Fun1(char *pszBuffer) { Fun2(pszBuffer); } void CTestDlg::Fun2(char *pszBuffer) { Fun3(pszBuffer); } void CTestDlg::Fun3(char *pszBuffer) { pszBuffer[1] = 0x00; }
我们在双击确定按钮时的响应代码如下:
view plain copy to clipboard print ?
- void CTestDlg::OnOK()
- {
-
- Fun1(NULL);
- }
void CTestDlg::OnOK() { // TODO: Add extra validation here Fun1(NULL); }
2、设置VC编译选项,勾选生成MAP和Debug Info:
3、将编译生成的Release目录中的pdb、map文件保存起来,以后调试会用到:
4、运行程序,单击确定按钮出现异常后自动重启,并创建一个Log文件夹,里面生成dump文件:
5、我们打开WinDbg,设置一下pdb路径(File \ Symbol File Path):
6、用WiinDbg打开dump文件(File \ Open Crash Dump)
7、输入命令!analyze -v,等待几秒后会打印出错误信息,函数调用栈如下图:
OK ,这样我们就能在发布版本的程序中,准确的定位到哪个函数出了问题,所以发布程序时,一定要记得生成pdb、map文件,不然客户运行出错的话,你不死也残!
测试工程下载地址:
http://download.csdn.net/source/3575167
http://blog.csdn.net/wangningyu/article/details/6748138