2024-12-21 10:04:04 +08:00
|
|
|
|
#include "stdafx.h"
|
|
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
|
|
|
|
|
|
|
#include <windows.h>
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
#include <time.h>
|
|
|
|
|
|
#include <tchar.h>
|
|
|
|
|
|
#include <DbgHelp.h>
|
|
|
|
|
|
#include <string>
|
|
|
|
|
|
#include <iostream>
|
|
|
|
|
|
#include "ExceptionDump.h"
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
|
|
#define new new(_NORMAL_BLOCK,__FILE__,__LINE__)
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
int ExceptionDump::m_nDumpLevel = ExceptionDump::eMiniDumpNormal;
|
|
|
|
|
|
bool ExceptionDump::m_bEnableDump = false;
|
|
|
|
|
|
std::string ExceptionDump::m_szDumpFileName;
|
|
|
|
|
|
LPTOP_LEVEL_EXCEPTION_FILTER ExceptionDump::m_pExceptionFilter = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// based on dbghelp.h
|
|
|
|
|
|
typedef BOOL (WINAPI *MINIDUMPWRITEDUMP) ( HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType,
|
|
|
|
|
|
CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
|
|
|
|
|
|
CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
|
|
|
|
|
|
CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam );
|
|
|
|
|
|
using std::cout;
|
|
|
|
|
|
using std::endl;
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
ExceptionDump::Enable(DumpLevel level)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
m_bEnableDump = true;
|
|
|
|
|
|
m_nDumpLevel = level;
|
|
|
|
|
|
|
|
|
|
|
|
std::set_new_handler(ExceptionDump::BadAllocFilter);
|
|
|
|
|
|
m_pExceptionFilter = SetUnhandledExceptionFilter(ExceptionDump::Exception_Minidump);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
ExceptionDump::Disable()
|
|
|
|
|
|
{
|
|
|
|
|
|
m_bEnableDump = false;
|
|
|
|
|
|
SetUnhandledExceptionFilter(NULL);
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void __cdecl
|
|
|
|
|
|
ExceptionDump::BadAllocFilter()
|
|
|
|
|
|
{
|
|
|
|
|
|
//MessageBox( NULL, _T("<22><EFBFBD><DEB8><EFBFBD> <20>Ҵ<EFBFBD> <20><><EFBFBD><EFBFBD> <20>Դϴ<D4B4>."), _T("ġ<><C4A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>"), MB_OK );
|
|
|
|
|
|
MessageBox( NULL, _T("Failed to Memory Alloc."), _T("Critical Error"), MB_OK );
|
|
|
|
|
|
throw std::bad_alloc();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LONG __stdcall
|
|
|
|
|
|
ExceptionDump::Exception_Minidump(_EXCEPTION_POINTERS* pExceptionInfo)
|
|
|
|
|
|
{
|
|
|
|
|
|
CallStackDump(pExceptionInfo);
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>˾Ƴ<CBBE><C6B3><EFBFBD>.
|
|
|
|
|
|
CHAR DumpFileName[MAX_PATH];
|
|
|
|
|
|
::GetModuleFileNameA(NULL, DumpFileName, MAX_PATH);
|
|
|
|
|
|
|
|
|
|
|
|
CHAR drive[_MAX_DRIVE];
|
|
|
|
|
|
CHAR dir[_MAX_DIR];
|
|
|
|
|
|
CHAR fname[_MAX_FNAME];
|
|
|
|
|
|
CHAR ext[_MAX_EXT];
|
|
|
|
|
|
|
|
|
|
|
|
_splitpath( DumpFileName, drive, dir, fname, ext );
|
|
|
|
|
|
|
|
|
|
|
|
// Ȯ<><C8AE><EFBFBD>ڸ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD>θ<EFBFBD> <20>غ<EFBFBD><D8BA>صд<D8B5>.
|
|
|
|
|
|
std::string szDumpFileName;
|
|
|
|
|
|
szDumpFileName = drive;
|
|
|
|
|
|
szDumpFileName += dir;
|
|
|
|
|
|
szDumpFileName += fname;
|
|
|
|
|
|
|
|
|
|
|
|
struct tm* now=NULL;
|
|
|
|
|
|
time_t systemTime;
|
|
|
|
|
|
|
|
|
|
|
|
time(&systemTime);
|
|
|
|
|
|
now=localtime(&systemTime);
|
|
|
|
|
|
|
|
|
|
|
|
CHAR szTail[MAX_PATH];
|
|
|
|
|
|
ZeroMemory(szTail, sizeof(CHAR) * MAX_PATH);
|
|
|
|
|
|
|
|
|
|
|
|
sprintf(szTail, "_%04d<34><64>%02d<32><64>%02d<32><64>_%02d<32><64>%02d<32><64>%02d<32><64>",
|
|
|
|
|
|
1900+now->tm_year, now->tm_mon+1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec);
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> + <20>ð<EFBFBD><C3B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
|
|
|
|
|
szDumpFileName += szTail;
|
|
|
|
|
|
|
|
|
|
|
|
cout << _T("unhandled excetpion writing dump...") << endl;
|
|
|
|
|
|
|
|
|
|
|
|
std::string szTimeStampDmpFileName = szDumpFileName + ".dmp";
|
|
|
|
|
|
std::string szTimeStampLogFileName = szTimeStampDmpFileName + "_errorlog_.txt";
|
|
|
|
|
|
|
|
|
|
|
|
HMODULE hDLL = NULL;
|
|
|
|
|
|
CHAR szDbgHelpPath[_MAX_PATH] = {0, };
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ִ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>丮<EFBFBD><E4B8AE><EFBFBD><EFBFBD> DBGHELP.DLL<4C><4C> <20>ε<EFBFBD><CEB5><EFBFBD> <20><><EFBFBD><EFBFBD>.
|
|
|
|
|
|
// Windows 2000 <20><> System32 <20><><EFBFBD><EFBFBD><EFBFBD>丮<EFBFBD><E4B8AE> <20>ִ<EFBFBD> DBGHELP.DLL <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><> <20>ֱ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>̴<EFBFBD>. (<28>ּ<EFBFBD> 5.1.2600.0 <20>̻<EFBFBD><CCBB>̾<EFBFBD><CCBE><EFBFBD> <20>Ѵ<EFBFBD>.)
|
|
|
|
|
|
if (::GetModuleFileNameA(NULL, szDbgHelpPath, _MAX_PATH))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (CHAR* slash = ::strchr(szDbgHelpPath, _T('\\')))
|
|
|
|
|
|
{
|
|
|
|
|
|
::strcpy(slash + 1, "DBGHELP.DLL");
|
|
|
|
|
|
hDLL = ::LoadLibraryA(szDbgHelpPath);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>丮<EFBFBD><E4B8AE> <20><><EFBFBD>ٸ<EFBFBD>, <20>ƹ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>̳<EFBFBD> <20>ε<EFBFBD><CEB5>Ѵ<EFBFBD>.
|
|
|
|
|
|
if (hDLL == NULL)
|
|
|
|
|
|
{
|
|
|
|
|
|
hDLL = ::LoadLibraryA("dbghelp.dll");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// DBGHELP.DLL<4C><4C> ã<><C3A3> <20><> <20><><EFBFBD>ٸ<EFBFBD> <20><> <20>̻<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD>.
|
|
|
|
|
|
if (hDLL == NULL)
|
|
|
|
|
|
{
|
|
|
|
|
|
FILE* pFile = fopen(szTimeStampLogFileName.c_str(), "w");
|
|
|
|
|
|
fprintf(pFile, "dbghelp.dll not found");
|
|
|
|
|
|
fclose(pFile);
|
|
|
|
|
|
|
|
|
|
|
|
// if( m_PrevExceptionFilter ) m_PrevExceptionFilter( pExceptionInfo );
|
|
|
|
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// DLL <20><><EFBFBD>ο<EFBFBD><CEBF><EFBFBD> MiniDumpWriteDump API<50><49> ã<>´<EFBFBD>.
|
|
|
|
|
|
MINIDUMPWRITEDUMP pfnMiniDumpWriteDump = (MINIDUMPWRITEDUMP)::GetProcAddress(hDLL, "MiniDumpWriteDump");
|
|
|
|
|
|
if (pfnMiniDumpWriteDump == NULL)
|
|
|
|
|
|
{
|
|
|
|
|
|
FILE* pFile = fopen(szTimeStampLogFileName.c_str(), "w");
|
|
|
|
|
|
fprintf(pFile, "dbghelp.dll too old");
|
|
|
|
|
|
fclose(pFile);
|
|
|
|
|
|
|
|
|
|
|
|
//if( m_PrevExceptionFilter ) m_PrevExceptionFilter( pExceptionInfo );
|
|
|
|
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HANDLE hFile = ::CreateFileA( szTimeStampDmpFileName.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
|
|
|
|
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
|
|
|
|
{
|
|
|
|
|
|
// <20><><EFBFBD>ð<EFBFBD> <20>ε<EFBFBD><CEB5><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ؽ<EFBFBD>Ʈ <20><><EFBFBD>Ϸ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
|
|
|
|
|
FILE* pFile = fopen(szTimeStampLogFileName.c_str(), "w");
|
|
|
|
|
|
fprintf(pFile, "Failed to save Dump File to %s ( error : %d )\n", szTimeStampLogFileName.c_str(), ::GetLastError());
|
|
|
|
|
|
fclose(pFile);
|
|
|
|
|
|
|
|
|
|
|
|
//if( m_PrevExceptionFilter ) m_PrevExceptionFilter( pExceptionInfo );
|
|
|
|
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
MINIDUMP_EXCEPTION_INFORMATION ExParam;
|
|
|
|
|
|
ExParam.ThreadId = ::GetCurrentThreadId();
|
|
|
|
|
|
ExParam.ExceptionPointers = pExceptionInfo;
|
|
|
|
|
|
ExParam.ClientPointers = FALSE;
|
|
|
|
|
|
|
|
|
|
|
|
MINIDUMP_TYPE dumptype = MiniDumpWithFullMemory;
|
|
|
|
|
|
switch (m_nDumpLevel)
|
|
|
|
|
|
{
|
|
|
|
|
|
case eMiniDumpNormal: dumptype = MiniDumpNormal; break;
|
|
|
|
|
|
case eMiniDumpWithDataSegs: dumptype = MiniDumpWithDataSegs; break;
|
|
|
|
|
|
case eMiniDumpWithFullMemory: dumptype = MiniDumpWithFullMemory; break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>α<EFBFBD> <20><><EFBFBD>Ͽ<EFBFBD><CFBF><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>Ѵ<EFBFBD>.
|
|
|
|
|
|
pfnMiniDumpWriteDump( ::GetCurrentProcess(), ::GetCurrentProcessId(), hFile, dumptype, &ExParam, NULL, NULL);
|
|
|
|
|
|
|
|
|
|
|
|
// dmp <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
|
|
|
|
|
CHAR temp[2048] = "0";
|
|
|
|
|
|
|
|
|
|
|
|
sprintf(temp, "Exception at 0x%08x\nDump to %s", pExceptionInfo->ExceptionRecord->ExceptionCode, szTimeStampDmpFileName.c_str());
|
|
|
|
|
|
MessageBoxA(NULL, temp, szDumpFileName.c_str(), MB_OK);
|
|
|
|
|
|
::CloseHandle(hFile);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if( m_PrevExceptionFilter ) m_PrevExceptionFilter( pExceptionInfo );
|
|
|
|
|
|
return EXCEPTION_EXECUTE_HANDLER;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const int MAX_SYM_SIZE = 512;
|
|
|
|
|
|
const int BUFF_SIZE = 8192;
|
|
|
|
|
|
const int SYM_BUFF_SIZE = 1024;
|
|
|
|
|
|
|
|
|
|
|
|
// The stack frame used in walking the stack
|
|
|
|
|
|
static BOOL g_bSymEngInit = FALSE ;
|
|
|
|
|
|
static STACKFRAME64 g_stFrame;
|
|
|
|
|
|
static CONTEXT g_stContext;
|
|
|
|
|
|
|
|
|
|
|
|
// The static buffer returned by various functions. This buffer
|
|
|
|
|
|
// allows data to be transferred without using the stack.
|
|
|
|
|
|
static CHAR g_szBuff[BUFF_SIZE] = "";
|
|
|
|
|
|
|
|
|
|
|
|
// The static symbol lookup buffer
|
|
|
|
|
|
static BYTE g_stSymbol [ SYM_BUFF_SIZE ] ;
|
|
|
|
|
|
|
|
|
|
|
|
// The static source file and line number structure
|
|
|
|
|
|
static IMAGEHLP_LINE64 g_stLine ;
|
|
|
|
|
|
|
|
|
|
|
|
#define TRACE __noop
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*//////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
Typedefs
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
// The typedefs for the PSAPI.DLL functions used by this module.
|
|
|
|
|
|
typedef BOOL (WINAPI *ENUMPROCESSMODULES) ( HANDLE hProcess ,
|
|
|
|
|
|
HMODULE * lphModule ,
|
|
|
|
|
|
DWORD cb ,
|
|
|
|
|
|
LPDWORD lpcbNeeded ) ;
|
|
|
|
|
|
|
|
|
|
|
|
typedef DWORD (WINAPI *GETMODULEBASENAMEW) ( HANDLE hProcess ,
|
|
|
|
|
|
HMODULE hModule ,
|
|
|
|
|
|
LPWSTR lpBaseName ,
|
|
|
|
|
|
DWORD nSize ) ;
|
|
|
|
|
|
|
|
|
|
|
|
typedef DWORD (WINAPI *GETMODULEFILENAMEEXW) ( HANDLE hProcess ,
|
|
|
|
|
|
HMODULE hModule ,
|
|
|
|
|
|
LPWSTR lpFilename ,
|
|
|
|
|
|
DWORD nSize ) ;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*//////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
File Static Data
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
// Has the function stuff here been initialized? This is only to be
|
|
|
|
|
|
// used by the InitPSAPI function and nothing else.
|
|
|
|
|
|
static BOOL g_bInitialized = FALSE ;
|
|
|
|
|
|
// The pointer to EnumProcessModules.
|
|
|
|
|
|
static ENUMPROCESSMODULES g_pEnumProcessModules = NULL ;
|
|
|
|
|
|
// The pointer to GetModuleBaseName.
|
|
|
|
|
|
static GETMODULEBASENAMEW g_pGetModuleBaseName = NULL ;
|
|
|
|
|
|
// The pointer to GetModuleFileNameEx.
|
|
|
|
|
|
static GETMODULEFILENAMEEXW g_pGetModuleFileNameEx = NULL ;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const char*
|
|
|
|
|
|
GetFaultReason(EXCEPTION_POINTERS* pExPtrs)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (::IsBadReadPtr(pExPtrs, sizeof(EXCEPTION_POINTERS)))
|
|
|
|
|
|
return ("bad exception pointers");
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>ڵ<EFBFBD><DAB5><EFBFBD><EFBFBD><EFBFBD> <20>׳<EFBFBD> <20><>ȯ<EFBFBD><C8AF> <20><> <20>ִ<EFBFBD>.
|
|
|
|
|
|
switch (pExPtrs->ExceptionRecord->ExceptionCode)
|
|
|
|
|
|
{
|
|
|
|
|
|
case EXCEPTION_ACCESS_VIOLATION: return ("EXCEPTION_ACCESS_VIOLATION");
|
|
|
|
|
|
case EXCEPTION_DATATYPE_MISALIGNMENT: return ("EXCEPTION_DATATYPE_MISALIGNMENT");
|
|
|
|
|
|
case EXCEPTION_BREAKPOINT: return ("EXCEPTION_BREAKPOINT");
|
|
|
|
|
|
case EXCEPTION_SINGLE_STEP: return ("EXCEPTION_SINGLE_STEP");
|
|
|
|
|
|
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: return ("EXCEPTION_ARRAY_BOUNDS_EXCEEDED");
|
|
|
|
|
|
case EXCEPTION_FLT_DENORMAL_OPERAND: return ("EXCEPTION_FLT_DENORMAL_OPERAND");
|
|
|
|
|
|
case EXCEPTION_FLT_DIVIDE_BY_ZERO: return ("EXCEPTION_FLT_DIVIDE_BY_ZERO");
|
|
|
|
|
|
case EXCEPTION_FLT_INEXACT_RESULT: return ("EXCEPTION_FLT_INEXACT_RESULT");
|
|
|
|
|
|
case EXCEPTION_FLT_INVALID_OPERATION: return ("EXCEPTION_FLT_INVALID_OPERATION");
|
|
|
|
|
|
case EXCEPTION_FLT_OVERFLOW: return ("EXCEPTION_FLT_OVERFLOW");
|
|
|
|
|
|
case EXCEPTION_FLT_STACK_CHECK: return ("EXCEPTION_FLT_STACK_CHECK");
|
|
|
|
|
|
case EXCEPTION_FLT_UNDERFLOW: return ("EXCEPTION_FLT_UNDERFLOW");
|
|
|
|
|
|
case EXCEPTION_INT_DIVIDE_BY_ZERO: return ("EXCEPTION_INT_DIVIDE_BY_ZERO");
|
|
|
|
|
|
case EXCEPTION_INT_OVERFLOW: return ("EXCEPTION_INT_OVERFLOW");
|
|
|
|
|
|
case EXCEPTION_PRIV_INSTRUCTION: return ("EXCEPTION_PRIV_INSTRUCTION");
|
|
|
|
|
|
case EXCEPTION_IN_PAGE_ERROR: return ("EXCEPTION_IN_PAGE_ERROR");
|
|
|
|
|
|
case EXCEPTION_ILLEGAL_INSTRUCTION: return ("EXCEPTION_ILLEGAL_INSTRUCTION");
|
|
|
|
|
|
case EXCEPTION_NONCONTINUABLE_EXCEPTION: return ("EXCEPTION_NONCONTINUABLE_EXCEPTION");
|
|
|
|
|
|
case EXCEPTION_STACK_OVERFLOW: return ("EXCEPTION_STACK_OVERFLOW");
|
|
|
|
|
|
case EXCEPTION_INVALID_DISPOSITION: return ("EXCEPTION_INVALID_DISPOSITION");
|
|
|
|
|
|
case EXCEPTION_GUARD_PAGE: return ("EXCEPTION_GUARD_PAGE");
|
|
|
|
|
|
case EXCEPTION_INVALID_HANDLE: return ("EXCEPTION_INVALID_HANDLE");
|
|
|
|
|
|
//case EXCEPTION_POSSIBLE_DEADLOCK: return ("EXCEPTION_POSSIBLE_DEADLOCK");
|
|
|
|
|
|
case CONTROL_C_EXIT: return ("CONTROL_C_EXIT");
|
|
|
|
|
|
case 0xE06D7363: return ("Microsoft C++ Exception");
|
|
|
|
|
|
default:
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD> <20><> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>...
|
|
|
|
|
|
static CHAR szFaultReason[2048] = "";
|
|
|
|
|
|
::strcpy(szFaultReason, ("Unknown"));
|
|
|
|
|
|
::FormatMessageA(
|
|
|
|
|
|
FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
|
|
|
|
::GetModuleHandleA(("ntdll.dll")),
|
|
|
|
|
|
pExPtrs->ExceptionRecord->ExceptionCode,
|
|
|
|
|
|
0,
|
|
|
|
|
|
szFaultReason,
|
|
|
|
|
|
0,
|
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
|
|
return szFaultReason;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// \brief <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>ȯ<EFBFBD>Ѵ<EFBFBD>.
|
|
|
|
|
|
/// \return LPCTSTR <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20≯<EFBFBD>
|
|
|
|
|
|
const char*
|
|
|
|
|
|
GetUserInfo()
|
|
|
|
|
|
{
|
|
|
|
|
|
static CHAR szUserName[200] = {0,};
|
|
|
|
|
|
|
|
|
|
|
|
ZeroMemory(szUserName, sizeof(szUserName));
|
|
|
|
|
|
DWORD UserNameSize = sizeof(szUserName) - 1;
|
|
|
|
|
|
|
|
|
|
|
|
if (!::GetUserNameA(szUserName, &UserNameSize))
|
|
|
|
|
|
::strcpy(szUserName, "Unknown");
|
|
|
|
|
|
|
|
|
|
|
|
return szUserName;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// \brief <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>ȯ<EFBFBD>Ѵ<EFBFBD>.
|
|
|
|
|
|
/// \return LPCTSTR <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD>ڿ<EFBFBD>
|
|
|
|
|
|
const char*
|
|
|
|
|
|
GetOSInfo()
|
|
|
|
|
|
{
|
|
|
|
|
|
CHAR szWinVer[50] = {0,};
|
|
|
|
|
|
CHAR szMajorMinorBuild[50] = {0,};
|
|
|
|
|
|
int nWinVer = 0;
|
|
|
|
|
|
::GetWinVersion(szWinVer, &nWinVer, szMajorMinorBuild);
|
|
|
|
|
|
|
|
|
|
|
|
static CHAR szOSInfo[512] = {0,};
|
|
|
|
|
|
|
|
|
|
|
|
sprintf(szOSInfo, "%s (%s)", szWinVer, szMajorMinorBuild);
|
|
|
|
|
|
szOSInfo[512] = 0;
|
|
|
|
|
|
|
|
|
|
|
|
return szOSInfo;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// \brief CPU <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>ȯ<EFBFBD>Ѵ<EFBFBD>.
|
|
|
|
|
|
/// \return LPCTSTR CPU <20><><EFBFBD><EFBFBD> <20><><EFBFBD>ڿ<EFBFBD>
|
|
|
|
|
|
std::string
|
|
|
|
|
|
GetCpuInfo()
|
|
|
|
|
|
{
|
|
|
|
|
|
// CPU <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
|
|
|
|
|
SYSTEM_INFO SystemInfo;
|
|
|
|
|
|
GetSystemInfo(&SystemInfo);
|
|
|
|
|
|
|
|
|
|
|
|
CHAR szCpuInfo[512] = {0,};
|
|
|
|
|
|
|
|
|
|
|
|
sprintf(szCpuInfo, "%d processor(s), type %d",
|
|
|
|
|
|
SystemInfo.dwNumberOfProcessors, SystemInfo.dwProcessorType);
|
|
|
|
|
|
|
|
|
|
|
|
return std::string(szCpuInfo);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::string
|
|
|
|
|
|
GetCpuInfoFromRegistry()
|
|
|
|
|
|
{
|
|
|
|
|
|
std::string szCpuString;
|
|
|
|
|
|
HKEY hKey;
|
|
|
|
|
|
DWORD dataSize=0;
|
|
|
|
|
|
CHAR szCPUNAME [64] = {0,};
|
|
|
|
|
|
CHAR szTempEx [64] = {0,};
|
|
|
|
|
|
ZeroMemory(szCPUNAME,64);
|
|
|
|
|
|
ZeroMemory(szTempEx,64);
|
|
|
|
|
|
LONG regResult;
|
|
|
|
|
|
regResult = ::RegOpenKeyExA (HKEY_LOCAL_MACHINE,
|
|
|
|
|
|
"Hardware\\Description\\System\\CentralProcessor\\0", 0, KEY_QUERY_VALUE, &hKey);
|
|
|
|
|
|
|
|
|
|
|
|
if(regResult == ERROR_SUCCESS){
|
|
|
|
|
|
dataSize = sizeof (szCPUNAME);
|
|
|
|
|
|
regResult = ::RegQueryValueExA (hKey, "ProcessorNameString", NULL, NULL,
|
|
|
|
|
|
(LPBYTE)szCPUNAME, &dataSize);
|
|
|
|
|
|
int num=0;
|
|
|
|
|
|
bool bspace=true;
|
|
|
|
|
|
for(int i=0;i<64;i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
if(szCPUNAME[i] != ' ' || bspace==false)
|
|
|
|
|
|
{
|
|
|
|
|
|
bspace = false;
|
|
|
|
|
|
szTempEx[num++] = szCPUNAME[i];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
szCpuString = szTempEx;
|
|
|
|
|
|
//wcscpy(m_wszCpuString,szTempEx);
|
|
|
|
|
|
}
|
|
|
|
|
|
RegCloseKey (hKey);
|
|
|
|
|
|
|
|
|
|
|
|
return szCpuString;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// \brief <20><EFBFBD><DEB8><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>ȯ<EFBFBD>Ѵ<EFBFBD>.
|
|
|
|
|
|
/// \return LPCTSTR <20><EFBFBD><DEB8><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD>ڿ<EFBFBD>
|
|
|
|
|
|
const char*
|
|
|
|
|
|
GetMemoryInfo()
|
|
|
|
|
|
{
|
|
|
|
|
|
static const int ONE_K = 1024;
|
|
|
|
|
|
static const int ONE_M = ONE_K * ONE_K;
|
|
|
|
|
|
static const int ONE_G = ONE_K * ONE_K * ONE_K;
|
|
|
|
|
|
|
|
|
|
|
|
MEMORYSTATUS MemInfo;
|
|
|
|
|
|
MemInfo.dwLength = sizeof(MemInfo);
|
|
|
|
|
|
GlobalMemoryStatus(&MemInfo);
|
|
|
|
|
|
|
|
|
|
|
|
static CHAR szMemoryInfo[2048] = {0,};
|
|
|
|
|
|
|
|
|
|
|
|
sprintf(szMemoryInfo,
|
|
|
|
|
|
"%d%% of memory in use.\n"
|
|
|
|
|
|
"%d MB physical memory.\n"
|
|
|
|
|
|
"%d MB physical memory free.\n"
|
|
|
|
|
|
"%d MB paging file.\n"
|
|
|
|
|
|
"%d MB paging file free.\n"
|
|
|
|
|
|
"%d MB user address space.\n"
|
|
|
|
|
|
"%d MB user address space free.",
|
|
|
|
|
|
MemInfo.dwMemoryLoad,
|
|
|
|
|
|
(MemInfo.dwTotalPhys + ONE_M - 1) / ONE_M,
|
|
|
|
|
|
(MemInfo.dwAvailPhys + ONE_M - 1) / ONE_M,
|
|
|
|
|
|
(MemInfo.dwTotalPageFile + ONE_M - 1) / ONE_M,
|
|
|
|
|
|
(MemInfo.dwAvailPageFile + ONE_M - 1) / ONE_M,
|
|
|
|
|
|
(MemInfo.dwTotalVirtual + ONE_M - 1) / ONE_M,
|
|
|
|
|
|
(MemInfo.dwAvailVirtual + ONE_M - 1) / ONE_M);
|
|
|
|
|
|
|
|
|
|
|
|
return szMemoryInfo;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// \brief <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>˾Ƴ<CBBE><C6B3><EFBFBD>.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// This table has been assembled from Usenet postings, personal observations,
|
|
|
|
|
|
/// and reading other people's code. Please feel free to add to it or correct
|
|
|
|
|
|
/// it.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// <pre>
|
|
|
|
|
|
/// dwPlatFormID dwMajorVersion dwMinorVersion dwBuildNumber
|
|
|
|
|
|
/// 95 1 4 0 950
|
|
|
|
|
|
/// 95 SP1 1 4 0 >950 && <=1080
|
|
|
|
|
|
/// 95 OSR2 1 4 <10 >1080
|
|
|
|
|
|
/// 98 1 4 10 1998
|
|
|
|
|
|
/// 98 SP1 1 4 10 >1998 && <2183
|
|
|
|
|
|
/// 98 SE 1 4 10 >=2183
|
|
|
|
|
|
/// ME 1 4 90 3000
|
|
|
|
|
|
///
|
|
|
|
|
|
/// NT 3.51 2 3 51
|
|
|
|
|
|
/// NT 4 2 4 0 1381
|
|
|
|
|
|
/// 2000 2 5 0 2195
|
|
|
|
|
|
/// XP 2 5 1 2600
|
|
|
|
|
|
/// 2003 Server 2 5 2 3790
|
|
|
|
|
|
///
|
|
|
|
|
|
/// CE 3
|
|
|
|
|
|
/// </pre>
|
|
|
|
|
|
///
|
|
|
|
|
|
/// \param pszVersion <20><><EFBFBD><EFBFBD> <20><><EFBFBD>ڿ<EFBFBD><DABF><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
/// \param nVersion <20><><EFBFBD><EFBFBD> <20><><EFBFBD>ڰ<EFBFBD><DAB0><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
/// \param pszMajorMinorBuild <20><><EFBFBD><EFBFBD> <20><><EFBFBD>ڿ<EFBFBD><DABF><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
/// \return bool <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>쿡<EFBFBD><ECBFA1> true, <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD>쿡<EFBFBD><ECBFA1> false
|
|
|
|
|
|
bool
|
|
|
|
|
|
GetWinVersion(char* pszVersion, int *nVersion, char* pszMajorMinorBuild)
|
|
|
|
|
|
{
|
|
|
|
|
|
// from winbase.h
|
|
|
|
|
|
#ifndef VER_PLATFORM_WIN32s
|
|
|
|
|
|
#define VER_PLATFORM_WIN32s 0
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef VER_PLATFORM_WIN32_WINDOWS
|
|
|
|
|
|
#define VER_PLATFORM_WIN32_WINDOWS 1
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef VER_PLATFORM_WIN32_NT
|
|
|
|
|
|
#define VER_PLATFORM_WIN32_NT 2
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef VER_PLATFORM_WIN32_CE
|
|
|
|
|
|
#define VER_PLATFORM_WIN32_CE 3
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
static const char* WUNKNOWNSTR = ("Unknown Windows Version");
|
|
|
|
|
|
static const char* W95STR = ("Windows 95");
|
|
|
|
|
|
static const char* W95SP1STR = ("Windows 95 SP1");
|
|
|
|
|
|
static const char* W95OSR2STR = ("Windows 95 OSR2");
|
|
|
|
|
|
static const char* W98STR = ("Windows 98");
|
|
|
|
|
|
static const char* W98SP1STR = ("Windows 98 SP1");
|
|
|
|
|
|
static const char* W98SESTR = ("Windows 98 SE");
|
|
|
|
|
|
static const char* WMESTR = ("Windows ME");
|
|
|
|
|
|
static const char* WNT351STR = ("Windows NT 3.51");
|
|
|
|
|
|
static const char* WNT4STR = ("Windows NT 4");
|
|
|
|
|
|
static const char* W2KSTR = ("Windows 2000");
|
|
|
|
|
|
static const char* WXPSTR = ("Windows XP");
|
|
|
|
|
|
static const char* W2003SERVERSTR = ("Windows 2003 Server");
|
|
|
|
|
|
static const char* WCESTR = ("Windows CE");
|
|
|
|
|
|
|
|
|
|
|
|
static const int WUNKNOWN = 0;
|
|
|
|
|
|
static const int W9XFIRST = 1;
|
|
|
|
|
|
static const int W95 = 1;
|
|
|
|
|
|
static const int W95SP1 = 2;
|
|
|
|
|
|
static const int W95OSR2 = 3;
|
|
|
|
|
|
static const int W98 = 4;
|
|
|
|
|
|
static const int W98SP1 = 5;
|
|
|
|
|
|
static const int W98SE = 6;
|
|
|
|
|
|
static const int WME = 7;
|
|
|
|
|
|
static const int W9XLAST = 99;
|
|
|
|
|
|
static const int WNTFIRST = 101;
|
|
|
|
|
|
static const int WNT351 = 101;
|
|
|
|
|
|
static const int WNT4 = 102;
|
|
|
|
|
|
static const int W2K = 103;
|
|
|
|
|
|
static const int WXP = 104;
|
|
|
|
|
|
static const int W2003SERVER = 105;
|
|
|
|
|
|
static const int WNTLAST = 199;
|
|
|
|
|
|
static const int WCEFIRST = 201;
|
|
|
|
|
|
static const int WCE = 201;
|
|
|
|
|
|
static const int WCELAST = 299;
|
|
|
|
|
|
|
|
|
|
|
|
if (!pszVersion || !nVersion || !pszMajorMinorBuild)
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
::strcpy(pszVersion, WUNKNOWNSTR);
|
|
|
|
|
|
*nVersion = WUNKNOWN;
|
|
|
|
|
|
|
|
|
|
|
|
OSVERSIONINFO osinfo;
|
|
|
|
|
|
osinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
|
|
|
|
|
|
|
|
|
|
if (!GetVersionEx(&osinfo)) return false;
|
|
|
|
|
|
|
|
|
|
|
|
DWORD dwPlatformId = osinfo.dwPlatformId;
|
|
|
|
|
|
DWORD dwMinorVersion = osinfo.dwMinorVersion;
|
|
|
|
|
|
DWORD dwMajorVersion = osinfo.dwMajorVersion;
|
|
|
|
|
|
DWORD dwBuildNumber = osinfo.dwBuildNumber & 0xFFFF; // Win 95 needs this
|
|
|
|
|
|
|
|
|
|
|
|
CHAR buf[1024] = {0, };
|
|
|
|
|
|
sprintf(buf, "%u.%u.%u", dwMajorVersion, dwMinorVersion, dwBuildNumber);
|
|
|
|
|
|
::strcpy(pszMajorMinorBuild, buf);
|
|
|
|
|
|
|
|
|
|
|
|
if ((dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) && (dwMajorVersion == 4))
|
|
|
|
|
|
{
|
|
|
|
|
|
if ((dwMinorVersion < 10) && (dwBuildNumber == 950))
|
|
|
|
|
|
{
|
|
|
|
|
|
::strcpy(pszVersion, W95STR);
|
|
|
|
|
|
*nVersion = W95;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if ((dwMinorVersion < 10) &&
|
|
|
|
|
|
((dwBuildNumber > 950) && (dwBuildNumber <= 1080)))
|
|
|
|
|
|
{
|
|
|
|
|
|
::strcpy(pszVersion, W95SP1STR);
|
|
|
|
|
|
*nVersion = W95SP1;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if ((dwMinorVersion < 10) && (dwBuildNumber > 1080))
|
|
|
|
|
|
{
|
|
|
|
|
|
::strcpy(pszVersion, W95OSR2STR);
|
|
|
|
|
|
*nVersion = W95OSR2;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if ((dwMinorVersion == 10) && (dwBuildNumber == 1998))
|
|
|
|
|
|
{
|
|
|
|
|
|
::strcpy(pszVersion, W98STR);
|
|
|
|
|
|
*nVersion = W98;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if ((dwMinorVersion == 10) &&
|
|
|
|
|
|
((dwBuildNumber > 1998) && (dwBuildNumber < 2183)))
|
|
|
|
|
|
{
|
|
|
|
|
|
::strcpy(pszVersion, W98SP1STR);
|
|
|
|
|
|
*nVersion = W98SP1;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if ((dwMinorVersion == 10) && (dwBuildNumber >= 2183))
|
|
|
|
|
|
{
|
|
|
|
|
|
::strcpy(pszVersion, W98SESTR);
|
|
|
|
|
|
*nVersion = W98SE;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (dwMinorVersion == 90)
|
|
|
|
|
|
{
|
|
|
|
|
|
::strcpy(pszVersion, WMESTR);
|
|
|
|
|
|
*nVersion = WME;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (dwPlatformId == VER_PLATFORM_WIN32_NT)
|
|
|
|
|
|
{
|
|
|
|
|
|
if ((dwMajorVersion == 3) && (dwMinorVersion == 51))
|
|
|
|
|
|
{
|
|
|
|
|
|
::strcpy(pszVersion, WNT351STR);
|
|
|
|
|
|
*nVersion = WNT351;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if ((dwMajorVersion == 4) && (dwMinorVersion == 0))
|
|
|
|
|
|
{
|
|
|
|
|
|
::strcpy(pszVersion, WNT4STR);
|
|
|
|
|
|
*nVersion = WNT4;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if ((dwMajorVersion == 5) && (dwMinorVersion == 0))
|
|
|
|
|
|
{
|
|
|
|
|
|
::strcpy(pszVersion, W2KSTR);
|
|
|
|
|
|
*nVersion = W2K;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if ((dwMajorVersion == 5) && (dwMinorVersion == 1))
|
|
|
|
|
|
{
|
|
|
|
|
|
::strcpy(pszVersion, WXPSTR);
|
|
|
|
|
|
*nVersion = WXP;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if ((dwMajorVersion == 5) && (dwMinorVersion == 2))
|
|
|
|
|
|
{
|
|
|
|
|
|
::strcpy(pszVersion, W2003SERVERSTR);
|
|
|
|
|
|
*nVersion = W2003SERVER;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (dwPlatformId == VER_PLATFORM_WIN32_CE)
|
|
|
|
|
|
{
|
|
|
|
|
|
::strcpy(pszVersion, WCESTR);
|
|
|
|
|
|
*nVersion = WCE;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
|
|
#undef VER_PLATFORM_WIN32s
|
|
|
|
|
|
#undef VER_PLATFORM_WIN32_WINDOWS
|
|
|
|
|
|
#undef VER_PLATFORM_WIN32_NT
|
|
|
|
|
|
#undef VER_PLATFORM_WIN32_CE
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const char*
|
|
|
|
|
|
GetRegisterString(EXCEPTION_POINTERS* pExPtrs)
|
|
|
|
|
|
{
|
|
|
|
|
|
static CHAR szBuff[8192] = "";
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef _X86_
|
|
|
|
|
|
// This call puts 48 bytes on the stack, which could be a problem if
|
|
|
|
|
|
// the stack is blown.
|
|
|
|
|
|
sprintf(szBuff ,
|
|
|
|
|
|
"EAX=%08X EBX=%08X ECX=%08X EDX=%08X ESI=%08X\n"\
|
|
|
|
|
|
"EDI=%08X EBP=%08X ESP=%08X EIP=%08X FLG=%08X\n"\
|
|
|
|
|
|
"CS=%04X DS=%04X SS=%04X ES=%04X "\
|
|
|
|
|
|
"FS=%04X GS=%04X" ,
|
|
|
|
|
|
pExPtrs->ContextRecord->Eax ,
|
|
|
|
|
|
pExPtrs->ContextRecord->Ebx ,
|
|
|
|
|
|
pExPtrs->ContextRecord->Ecx ,
|
|
|
|
|
|
pExPtrs->ContextRecord->Edx ,
|
|
|
|
|
|
pExPtrs->ContextRecord->Esi ,
|
|
|
|
|
|
pExPtrs->ContextRecord->Edi ,
|
|
|
|
|
|
pExPtrs->ContextRecord->Ebp ,
|
|
|
|
|
|
pExPtrs->ContextRecord->Esp ,
|
|
|
|
|
|
pExPtrs->ContextRecord->Eip ,
|
|
|
|
|
|
pExPtrs->ContextRecord->EFlags ,
|
|
|
|
|
|
pExPtrs->ContextRecord->SegCs ,
|
|
|
|
|
|
pExPtrs->ContextRecord->SegDs ,
|
|
|
|
|
|
pExPtrs->ContextRecord->SegSs ,
|
|
|
|
|
|
pExPtrs->ContextRecord->SegEs ,
|
|
|
|
|
|
pExPtrs->ContextRecord->SegFs ,
|
|
|
|
|
|
pExPtrs->ContextRecord->SegGs ) ;
|
|
|
|
|
|
#elif _AMD64_
|
|
|
|
|
|
sprintf ( szBuff ,
|
|
|
|
|
|
"RAX=%016X RBX=%016X RCX=%016X RDX=%016X RSI=%016X\n"\
|
|
|
|
|
|
"RDI=%016X RBP=%016X RSP=%016X RIP=%016X FLG=%016X\n"\
|
|
|
|
|
|
" R8=%016X R9=%016X R10=%016X R11=%016X R12=%016X\n"\
|
|
|
|
|
|
"R13=%016X R14=%016X R15=%016X" ,
|
|
|
|
|
|
pExPtrs->ContextRecord->Rax ,
|
|
|
|
|
|
pExPtrs->ContextRecord->Rbx ,
|
|
|
|
|
|
pExPtrs->ContextRecord->Rcx ,
|
|
|
|
|
|
pExPtrs->ContextRecord->Rdx ,
|
|
|
|
|
|
pExPtrs->ContextRecord->Rsi ,
|
|
|
|
|
|
pExPtrs->ContextRecord->Rdi ,
|
|
|
|
|
|
pExPtrs->ContextRecord->Rbp ,
|
|
|
|
|
|
pExPtrs->ContextRecord->Rsp ,
|
|
|
|
|
|
pExPtrs->ContextRecord->Rip ,
|
|
|
|
|
|
pExPtrs->ContextRecord->EFlags ,
|
|
|
|
|
|
pExPtrs->ContextRecord->R8 ,
|
|
|
|
|
|
pExPtrs->ContextRecord->R9 ,
|
|
|
|
|
|
pExPtrs->ContextRecord->R10 ,
|
|
|
|
|
|
pExPtrs->ContextRecord->R11 ,
|
|
|
|
|
|
pExPtrs->ContextRecord->R12 ,
|
|
|
|
|
|
pExPtrs->ContextRecord->R13 ,
|
|
|
|
|
|
pExPtrs->ContextRecord->R14 ,
|
|
|
|
|
|
pExPtrs->ContextRecord->R15 ) ;
|
|
|
|
|
|
#elif _IA64_
|
|
|
|
|
|
#pragma message ( "IA64 NOT DEFINED!!" )
|
|
|
|
|
|
#pragma FORCE COMPILATION ABORT!
|
|
|
|
|
|
#else
|
|
|
|
|
|
#pragma message ( "CPU NOT DEFINED!!" )
|
|
|
|
|
|
#pragma FORCE COMPILATION ABORT!
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
return ( szBuff ) ;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const char* __stdcall
|
|
|
|
|
|
GetFirstStackTraceString( DWORD dwOpts, EXCEPTION_POINTERS * pExPtrs )
|
|
|
|
|
|
{
|
|
|
|
|
|
assert ( FALSE == IsBadReadPtr ( pExPtrs , sizeof(EXCEPTION_POINTERS*)) );
|
|
|
|
|
|
|
|
|
|
|
|
if ( TRUE == IsBadReadPtr ( pExPtrs, sizeof(EXCEPTION_POINTERS*)) )
|
|
|
|
|
|
{
|
|
|
|
|
|
return ("GetFirstStackTraceString - invalid pExPtrs!\n");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Get the stack frame filled in.
|
|
|
|
|
|
FillInStackFrame ( pExPtrs->ContextRecord ) ;
|
|
|
|
|
|
|
|
|
|
|
|
// Copy over the exception pointers fields so I don't corrupt the
|
|
|
|
|
|
// real one.
|
|
|
|
|
|
g_stContext = *(pExPtrs->ContextRecord) ;
|
|
|
|
|
|
|
|
|
|
|
|
return ( InternalGetStackTraceString ( dwOpts ) ) ;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const char* __stdcall
|
|
|
|
|
|
GetNextStackTraceString( DWORD dwOpts, EXCEPTION_POINTERS* pExPtrs )
|
|
|
|
|
|
{
|
|
|
|
|
|
// All error checking is in InternalGetStackTraceString.
|
|
|
|
|
|
// Assume that GetFirstStackTraceString has already initialized the
|
|
|
|
|
|
// stack frame information.
|
|
|
|
|
|
return ( InternalGetStackTraceString ( dwOpts ) ) ;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Helper function to isolate filling out the stack frame, which is CPU
|
|
|
|
|
|
// specific.
|
|
|
|
|
|
void FillInStackFrame ( PCONTEXT pCtx )
|
|
|
|
|
|
{
|
|
|
|
|
|
// Initialize the STACKFRAME structure.
|
|
|
|
|
|
ZeroMemory ( &g_stFrame , sizeof ( STACKFRAME64 ) ) ;
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef _X86_
|
|
|
|
|
|
g_stFrame.AddrPC.Offset = pCtx->Eip ;
|
|
|
|
|
|
g_stFrame.AddrPC.Mode = AddrModeFlat ;
|
|
|
|
|
|
g_stFrame.AddrStack.Offset = pCtx->Esp ;
|
|
|
|
|
|
g_stFrame.AddrStack.Mode = AddrModeFlat ;
|
|
|
|
|
|
g_stFrame.AddrFrame.Offset = pCtx->Ebp ;
|
|
|
|
|
|
g_stFrame.AddrFrame.Mode = AddrModeFlat ;
|
|
|
|
|
|
#elif _AMD64_
|
|
|
|
|
|
g_stFrame.AddrPC.Offset = pCtx->Rip ;
|
|
|
|
|
|
g_stFrame.AddrPC.Mode = AddrModeFlat ;
|
|
|
|
|
|
g_stFrame.AddrStack.Offset = pCtx->Rsp ;
|
|
|
|
|
|
g_stFrame.AddrStack.Mode = AddrModeFlat ;
|
|
|
|
|
|
g_stFrame.AddrFrame.Offset = pCtx->Rbp ;
|
|
|
|
|
|
g_stFrame.AddrFrame.Mode = AddrModeFlat ;
|
|
|
|
|
|
#elif _IA64_
|
|
|
|
|
|
#pragma message ( "IA64 NOT DEFINED!!" )
|
|
|
|
|
|
#pragma FORCE COMPILATION ABORT!
|
|
|
|
|
|
#else
|
|
|
|
|
|
#pragma message ( "CPU NOT DEFINED!!" )
|
|
|
|
|
|
#pragma FORCE COMPILATION ABORT!
|
|
|
|
|
|
#endif
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Initializes the symbol engine if needed
|
|
|
|
|
|
void InitSymEng ( void )
|
|
|
|
|
|
{
|
|
|
|
|
|
if ( FALSE == g_bSymEngInit )
|
|
|
|
|
|
{
|
|
|
|
|
|
// Set up the symbol engine.
|
|
|
|
|
|
DWORD dwOpts = SymGetOptions ( ) ;
|
|
|
|
|
|
|
|
|
|
|
|
// Turn on line loading.
|
|
|
|
|
|
SymSetOptions ( dwOpts |
|
|
|
|
|
|
SYMOPT_LOAD_LINES ) ;
|
|
|
|
|
|
|
|
|
|
|
|
// Force the invade process flag on.
|
|
|
|
|
|
BOOL bRet = SymInitialize ( GetCurrentProcess ( ) ,
|
|
|
|
|
|
NULL ,
|
|
|
|
|
|
TRUE ) ;
|
|
|
|
|
|
assert ( TRUE == bRet ) ;
|
|
|
|
|
|
g_bSymEngInit = bRet ;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Cleans up the symbol engine if needed
|
|
|
|
|
|
void CleanupSymEng ( void )
|
|
|
|
|
|
{
|
|
|
|
|
|
if ( TRUE == g_bSymEngInit )
|
|
|
|
|
|
{
|
|
|
|
|
|
assert ( SymCleanup ( GetCurrentProcess ( ) ) ) ;
|
|
|
|
|
|
g_bSymEngInit = FALSE ;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BOOL __stdcall CH_ReadProcessMemory ( HANDLE ,
|
|
|
|
|
|
DWORD64 qwBaseAddress ,
|
|
|
|
|
|
PVOID lpBuffer ,
|
|
|
|
|
|
DWORD nSize ,
|
|
|
|
|
|
LPDWORD lpNumberOfBytesRead )
|
|
|
|
|
|
{
|
|
|
|
|
|
return ( ReadProcessMemory ( GetCurrentProcess ( ) ,
|
|
|
|
|
|
(LPCVOID)qwBaseAddress ,
|
|
|
|
|
|
lpBuffer ,
|
|
|
|
|
|
nSize ,
|
|
|
|
|
|
(SIZE_T*)lpNumberOfBytesRead ) ) ;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// The internal function that does all the stack walking
|
|
|
|
|
|
const char* InternalGetStackTraceString ( DWORD dwOpts )
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
// The value that is returned
|
|
|
|
|
|
const char* szRet ;
|
|
|
|
|
|
// The module base address. I look this up right after the stack
|
|
|
|
|
|
// walk to ensure that the module is valid.
|
|
|
|
|
|
DWORD64 dwModBase ;
|
|
|
|
|
|
|
|
|
|
|
|
__try
|
|
|
|
|
|
{
|
|
|
|
|
|
// Initialize the symbol engine in case it isn't initialized.
|
|
|
|
|
|
InitSymEng ( ) ;
|
|
|
|
|
|
|
|
|
|
|
|
// Note: If the source file and line number functions are used,
|
|
|
|
|
|
// StackWalk can cause an access violation.
|
|
|
|
|
|
BOOL bSWRet = StackWalk64 ( CH_MACHINE ,
|
|
|
|
|
|
GetCurrentProcess ( ) ,
|
|
|
|
|
|
GetCurrentThread ( ) ,
|
|
|
|
|
|
&g_stFrame ,
|
|
|
|
|
|
&g_stContext ,
|
|
|
|
|
|
CH_ReadProcessMemory ,
|
|
|
|
|
|
SymFunctionTableAccess64 ,
|
|
|
|
|
|
SymGetModuleBase64 ,
|
|
|
|
|
|
NULL );
|
|
|
|
|
|
if ( ( FALSE == bSWRet ) || ( 0 == g_stFrame.AddrFrame.Offset ))
|
|
|
|
|
|
{
|
|
|
|
|
|
szRet = NULL ;
|
|
|
|
|
|
__leave ;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Before I get too carried away and start calculating
|
|
|
|
|
|
// everything, I need to double-check that the address returned
|
|
|
|
|
|
// by StackWalk really exists. I've seen cases in which
|
|
|
|
|
|
// StackWalk returns TRUE but the address doesn't belong to
|
|
|
|
|
|
// a module in the process.
|
|
|
|
|
|
dwModBase = SymGetModuleBase64 ( GetCurrentProcess ( ) ,
|
|
|
|
|
|
g_stFrame.AddrPC.Offset ) ;
|
|
|
|
|
|
if ( 0 == dwModBase )
|
|
|
|
|
|
{
|
|
|
|
|
|
szRet = NULL ;
|
|
|
|
|
|
__leave ;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int iCurr = 0 ;
|
|
|
|
|
|
|
|
|
|
|
|
// At a minimum, put in the address.
|
|
|
|
|
|
#ifdef _WIN64
|
|
|
|
|
|
iCurr += sprintf ( g_szBuff + iCurr ,
|
|
|
|
|
|
( "0x%016X" ) ,
|
|
|
|
|
|
g_stFrame.AddrPC.Offset ) ;
|
|
|
|
|
|
#else
|
|
|
|
|
|
iCurr += sprintf ( g_szBuff + iCurr ,
|
|
|
|
|
|
( "%04X:%08X" ) ,
|
|
|
|
|
|
g_stContext.SegCs ,
|
|
|
|
|
|
g_stFrame.AddrPC.Offset ) ;
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
// Output the parameters?
|
|
|
|
|
|
if ( GSTSO_PARAMS == ( dwOpts & GSTSO_PARAMS ) )
|
|
|
|
|
|
{
|
|
|
|
|
|
iCurr += sprintf ( g_szBuff + iCurr ,
|
|
|
|
|
|
k_PARAMFMTSTRING ,
|
|
|
|
|
|
g_stFrame.Params[ 0 ] ,
|
|
|
|
|
|
g_stFrame.Params[ 1 ] ,
|
|
|
|
|
|
g_stFrame.Params[ 2 ] ,
|
|
|
|
|
|
g_stFrame.Params[ 3 ] ) ;
|
|
|
|
|
|
}
|
|
|
|
|
|
// Output the module name.
|
|
|
|
|
|
if ( GSTSO_MODULE == ( dwOpts & GSTSO_MODULE ) )
|
|
|
|
|
|
{
|
|
|
|
|
|
iCurr += sprintf ( g_szBuff + iCurr , ( " " ) ) ;
|
|
|
|
|
|
|
|
|
|
|
|
assert ( iCurr < ( BUFF_SIZE - MAX_PATH ) ) ;
|
|
|
|
|
|
iCurr += BSUGetModuleBaseNameA ( GetCurrentProcess ( ) ,
|
|
|
|
|
|
(HINSTANCE)dwModBase ,
|
|
|
|
|
|
g_szBuff + iCurr ,
|
|
|
|
|
|
BUFF_SIZE - iCurr ) ;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
assert ( iCurr < ( BUFF_SIZE - MAX_PATH ) ) ;
|
|
|
|
|
|
DWORD64 dwDisp ;
|
|
|
|
|
|
|
|
|
|
|
|
// Output the symbol name?
|
|
|
|
|
|
if ( GSTSO_SYMBOL == ( dwOpts & GSTSO_SYMBOL ) )
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
// Start looking up the exception address.
|
|
|
|
|
|
PIMAGEHLP_SYMBOL64 pSym = (PIMAGEHLP_SYMBOL64)&g_stSymbol ;
|
|
|
|
|
|
ZeroMemory ( pSym , SYM_BUFF_SIZE ) ;
|
|
|
|
|
|
pSym->SizeOfStruct = sizeof ( IMAGEHLP_SYMBOL64 ) ;
|
|
|
|
|
|
pSym->MaxNameLength = SYM_BUFF_SIZE -
|
|
|
|
|
|
sizeof ( IMAGEHLP_SYMBOL64 ) ;
|
|
|
|
|
|
pSym->Address = g_stFrame.AddrPC.Offset ;
|
|
|
|
|
|
|
|
|
|
|
|
if ( TRUE ==
|
|
|
|
|
|
SymGetSymFromAddr64 ( GetCurrentProcess ( ) ,
|
|
|
|
|
|
g_stFrame.AddrPC.Offset ,
|
|
|
|
|
|
&dwDisp ,
|
|
|
|
|
|
pSym ) )
|
|
|
|
|
|
{
|
|
|
|
|
|
if ( dwOpts & ~GSTSO_SYMBOL )
|
|
|
|
|
|
{
|
|
|
|
|
|
iCurr += sprintf ( g_szBuff + iCurr , ( "," ));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Copy no more symbol information than there's room
|
|
|
|
|
|
// for. Symbols are ANSI
|
|
|
|
|
|
int iLen = (int)strlen ( pSym->Name ) ;
|
|
|
|
|
|
if ( iLen > ( BUFF_SIZE - iCurr -
|
|
|
|
|
|
( MAX_SYM_SIZE + 50 ) ) )
|
|
|
|
|
|
{
|
|
|
|
|
|
strncpy ( g_szBuff + iCurr ,
|
|
|
|
|
|
pSym->Name ,
|
|
|
|
|
|
BUFF_SIZE - iCurr - 1 ) ;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Gotta leave now
|
|
|
|
|
|
szRet = g_szBuff ;
|
|
|
|
|
|
__leave ;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
if ( dwDisp > 0 )
|
|
|
|
|
|
{
|
|
|
|
|
|
iCurr += sprintf ( g_szBuff + iCurr ,
|
|
|
|
|
|
k_NAMEDISPFMT ,
|
|
|
|
|
|
pSym->Name ,
|
|
|
|
|
|
dwDisp ) ;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
iCurr += sprintf ( g_szBuff + iCurr ,
|
|
|
|
|
|
k_NAMEFMT ,
|
|
|
|
|
|
pSym->Name ) ;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// If the symbol wasn't found, the source file and line
|
|
|
|
|
|
// number won't be found either, so leave now.
|
|
|
|
|
|
szRet = g_szBuff ;
|
|
|
|
|
|
__leave ;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
assert ( iCurr < ( BUFF_SIZE - MAX_PATH ) ) ;
|
|
|
|
|
|
|
|
|
|
|
|
// Output the source file and line number information?
|
|
|
|
|
|
if ( GSTSO_SRCLINE == ( dwOpts & GSTSO_SRCLINE ) )
|
|
|
|
|
|
{
|
|
|
|
|
|
ZeroMemory ( &g_stLine , sizeof ( IMAGEHLP_LINE64 ) ) ;
|
|
|
|
|
|
g_stLine.SizeOfStruct = sizeof ( IMAGEHLP_LINE64 ) ;
|
|
|
|
|
|
|
|
|
|
|
|
DWORD dwLineDisp ;
|
|
|
|
|
|
if ( TRUE == SymGetLineFromAddr64 ( GetCurrentProcess ( ) ,
|
|
|
|
|
|
g_stFrame.AddrPC.Offset,
|
|
|
|
|
|
&dwLineDisp ,
|
|
|
|
|
|
&g_stLine ))
|
|
|
|
|
|
{
|
|
|
|
|
|
if ( dwOpts & ~GSTSO_SRCLINE )
|
|
|
|
|
|
{
|
|
|
|
|
|
iCurr += sprintf ( g_szBuff + iCurr , ( "," ));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Copy no more of the source file and line number
|
|
|
|
|
|
// information than there's room for.
|
|
|
|
|
|
int iLen = lstrlenA ( g_stLine.FileName ) ;
|
|
|
|
|
|
if ( iLen > ( BUFF_SIZE - iCurr -
|
|
|
|
|
|
( MAX_PATH + 50 ) ) )
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
strncpy ( g_szBuff + iCurr ,
|
|
|
|
|
|
g_stLine.FileName ,
|
|
|
|
|
|
BUFF_SIZE - iCurr - 1 ) ;
|
|
|
|
|
|
|
|
|
|
|
|
// Gotta leave now
|
|
|
|
|
|
szRet = g_szBuff ;
|
|
|
|
|
|
__leave ;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
if ( dwLineDisp > 0 )
|
|
|
|
|
|
{
|
|
|
|
|
|
iCurr += sprintf( g_szBuff + iCurr ,
|
|
|
|
|
|
k_FILELINEDISPFMT ,
|
|
|
|
|
|
g_stLine.FileName ,
|
|
|
|
|
|
g_stLine.LineNumber ,
|
|
|
|
|
|
dwLineDisp ) ;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
iCurr += sprintf ( g_szBuff + iCurr ,
|
|
|
|
|
|
k_FILELINEFMT ,
|
|
|
|
|
|
g_stLine.FileName ,
|
|
|
|
|
|
g_stLine.LineNumber ) ;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
szRet = g_szBuff ;
|
|
|
|
|
|
}
|
|
|
|
|
|
__except ( EXCEPTION_EXECUTE_HANDLER )
|
|
|
|
|
|
{
|
|
|
|
|
|
assert ( !"Crashed in InternalGetStackTraceString" ) ;
|
|
|
|
|
|
szRet = NULL ;
|
|
|
|
|
|
}
|
|
|
|
|
|
return ( szRet ) ;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Helper define to let code compile on pre W2K systems.
|
|
|
|
|
|
#if _WIN32 >= 0x500
|
|
|
|
|
|
#define GET_THREAD_ACP() CP_THREAD_ACP
|
|
|
|
|
|
#else
|
|
|
|
|
|
#define GET_THREAD_ACP() GetACP ()
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DWORD __stdcall
|
|
|
|
|
|
BSUWide2Ansi ( const wchar_t * szWide ,
|
|
|
|
|
|
char * szANSI ,
|
|
|
|
|
|
int iANSILen)
|
|
|
|
|
|
{
|
|
|
|
|
|
assert ( NULL != szWide ) ;
|
|
|
|
|
|
assert ( NULL != szANSI ) ;
|
|
|
|
|
|
assert ( FALSE == IsBadStringPtrW ( szWide , MAX_PATH ) ) ;
|
|
|
|
|
|
|
|
|
|
|
|
int iRet = WideCharToMultiByte ( GET_THREAD_ACP() ,
|
|
|
|
|
|
0 ,
|
|
|
|
|
|
szWide ,
|
|
|
|
|
|
-1 ,
|
|
|
|
|
|
szANSI ,
|
|
|
|
|
|
iANSILen ,
|
|
|
|
|
|
NULL ,
|
|
|
|
|
|
NULL ) ;
|
|
|
|
|
|
return ( iRet ) ;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DWORD __stdcall
|
|
|
|
|
|
BSUAnsi2Wide ( const char * szANSI ,
|
|
|
|
|
|
wchar_t * szWide ,
|
|
|
|
|
|
int iWideLen )
|
|
|
|
|
|
{
|
|
|
|
|
|
assert ( NULL != szWide ) ;
|
|
|
|
|
|
assert ( NULL != szANSI ) ;
|
|
|
|
|
|
assert ( FALSE == IsBadStringPtrA ( szANSI , MAX_PATH ) ) ;
|
|
|
|
|
|
|
|
|
|
|
|
int iRet = MultiByteToWideChar ( GET_THREAD_ACP ( ) ,
|
|
|
|
|
|
0 ,
|
|
|
|
|
|
szANSI ,
|
|
|
|
|
|
-1 ,
|
|
|
|
|
|
szWide ,
|
|
|
|
|
|
iWideLen ) ;
|
|
|
|
|
|
return ( iRet ) ;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DWORD __stdcall NTGetModuleBaseNameW ( HANDLE hProcess ,
|
|
|
|
|
|
HMODULE hModule ,
|
|
|
|
|
|
LPWSTR lpBaseName ,
|
|
|
|
|
|
DWORD nSize )
|
|
|
|
|
|
{
|
|
|
|
|
|
// Initialize PSAPI.DLL, if needed.
|
|
|
|
|
|
if ( FALSE == InitPSAPI ( ) )
|
|
|
|
|
|
{
|
|
|
|
|
|
assert ( !"InitiPSAPI failed!" ) ;
|
|
|
|
|
|
SetLastErrorEx ( ERROR_DLL_INIT_FAILED , SLE_ERROR ) ;
|
|
|
|
|
|
return ( FALSE ) ;
|
|
|
|
|
|
}
|
|
|
|
|
|
return ( g_pGetModuleBaseName ( hProcess ,
|
|
|
|
|
|
hModule ,
|
|
|
|
|
|
lpBaseName ,
|
|
|
|
|
|
nSize ) ) ;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*//////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
Function Implementation
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
DWORD __stdcall BSUGetModuleBaseNameA ( HANDLE hProcess ,
|
|
|
|
|
|
HMODULE hModule ,
|
|
|
|
|
|
LPSTR lpBaseName ,
|
|
|
|
|
|
DWORD nSize )
|
|
|
|
|
|
{
|
|
|
|
|
|
wchar_t * pWideName = (wchar_t*)HeapAlloc ( GetProcessHeap ( ) ,
|
|
|
|
|
|
HEAP_GENERATE_EXCEPTIONS|
|
|
|
|
|
|
HEAP_ZERO_MEMORY ,
|
|
|
|
|
|
nSize * sizeof(wchar_t));
|
|
|
|
|
|
DWORD dwRet = BSUGetModuleBaseNameW ( hProcess ,
|
|
|
|
|
|
hModule ,
|
|
|
|
|
|
pWideName ,
|
|
|
|
|
|
nSize ) ;
|
|
|
|
|
|
if ( 0 != dwRet )
|
|
|
|
|
|
{
|
|
|
|
|
|
if ( FALSE == BSUWide2Ansi ( pWideName , lpBaseName , nSize ) )
|
|
|
|
|
|
{
|
|
|
|
|
|
dwRet = 0 ;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
//VERIFY ( HeapFree ( GetProcessHeap ( ) , 0 , pWideName ) ) ;
|
|
|
|
|
|
return ( dwRet ) ;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DWORD __stdcall BSUGetModuleBaseNameW ( HANDLE hProcess ,
|
|
|
|
|
|
HMODULE hModule ,
|
|
|
|
|
|
LPWSTR lpBaseName ,
|
|
|
|
|
|
DWORD nSize )
|
|
|
|
|
|
{
|
|
|
|
|
|
// Call the NT version. It is in NT4ProcessInfo because that is
|
|
|
|
|
|
// where all the PSAPI wrappers are kept.
|
|
|
|
|
|
return ( NTGetModuleBaseNameW ( hProcess ,
|
|
|
|
|
|
hModule ,
|
|
|
|
|
|
lpBaseName ,
|
|
|
|
|
|
nSize ) ) ;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
|
|
|
|
FUNCTION : InitPSAPI
|
|
|
|
|
|
DISCUSSION :
|
|
|
|
|
|
Loads PSAPI.DLL and initializes all the pointers needed by this
|
|
|
|
|
|
file. If BugslayerUtil.DLL statically linked to PSAPI.DLL, it would not
|
|
|
|
|
|
work on Windows9x.
|
|
|
|
|
|
Note that I conciously chose to allow the resource leak on loading
|
|
|
|
|
|
PSAPI.DLL.
|
|
|
|
|
|
PARAMETERS :
|
|
|
|
|
|
None.
|
|
|
|
|
|
RETURNS :
|
|
|
|
|
|
TRUE - Everything initialized properly.
|
|
|
|
|
|
FALSE - There was a problem.
|
|
|
|
|
|
----------------------------------------------------------------------*/
|
|
|
|
|
|
static BOOL InitPSAPI ( void )
|
|
|
|
|
|
{
|
|
|
|
|
|
if ( TRUE == g_bInitialized )
|
|
|
|
|
|
{
|
|
|
|
|
|
return ( TRUE ) ;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Load up PSAPI.DLL.
|
|
|
|
|
|
HINSTANCE hInst = LoadLibraryA( "PSAPI.DLL" ) ;
|
|
|
|
|
|
assert ( NULL != hInst ) ;
|
|
|
|
|
|
if ( NULL == hInst )
|
|
|
|
|
|
{
|
|
|
|
|
|
TRACE ( "Unable to load PSAPI.DLL!\n" ) ;
|
|
|
|
|
|
return ( FALSE ) ;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Now do the GetProcAddress stuff.
|
|
|
|
|
|
g_pEnumProcessModules =
|
|
|
|
|
|
(ENUMPROCESSMODULES)GetProcAddress ( hInst ,
|
|
|
|
|
|
"EnumProcessModules" ) ;
|
|
|
|
|
|
assert ( NULL != g_pEnumProcessModules ) ;
|
|
|
|
|
|
if ( NULL == g_pEnumProcessModules )
|
|
|
|
|
|
{
|
|
|
|
|
|
TRACE ( "GetProcAddress failed on EnumProcessModules!\n" ) ;
|
|
|
|
|
|
return ( FALSE ) ;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
g_pGetModuleBaseName =
|
|
|
|
|
|
(GETMODULEBASENAMEW)GetProcAddress ( hInst ,
|
|
|
|
|
|
"GetModuleBaseNameW" ) ;
|
|
|
|
|
|
assert ( NULL != g_pGetModuleBaseName ) ;
|
|
|
|
|
|
if ( NULL == g_pGetModuleBaseName )
|
|
|
|
|
|
{
|
|
|
|
|
|
TRACE ( "GetProcAddress failed on GetModuleBaseNameW!\n" ) ;
|
|
|
|
|
|
return ( FALSE ) ;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
g_pGetModuleFileNameEx =
|
|
|
|
|
|
(GETMODULEFILENAMEEXW)GetProcAddress ( hInst ,
|
|
|
|
|
|
"GetModuleFileNameExW" );
|
|
|
|
|
|
assert ( NULL != g_pGetModuleFileNameEx ) ;
|
|
|
|
|
|
if ( NULL == g_pGetModuleFileNameEx )
|
|
|
|
|
|
{
|
|
|
|
|
|
TRACE ( "GetProcAddress failed on GetModuleFileNameExW\n" ) ;
|
|
|
|
|
|
return ( FALSE ) ;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// All OK, Jumpmaster!
|
|
|
|
|
|
g_bInitialized = TRUE ;
|
|
|
|
|
|
return ( TRUE ) ;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void NxGetCallStack(OUT std::string& szString, EXCEPTION_POINTERS* pExPtrs, DWORD dwOpt )
|
|
|
|
|
|
{
|
|
|
|
|
|
szString = "";
|
|
|
|
|
|
|
|
|
|
|
|
#define _ALL (GSTSO_PARAMS|GSTSO_MODULE|GSTSO_SYMBOL|GSTSO_SRCLINE)
|
|
|
|
|
|
|
|
|
|
|
|
const char* szBuff = GetFirstStackTraceString ( dwOpt , pExPtrs ) ;
|
|
|
|
|
|
do
|
|
|
|
|
|
{
|
|
|
|
|
|
szString += szBuff;
|
|
|
|
|
|
szString += "\n";
|
|
|
|
|
|
szBuff = GetNextStackTraceString ( dwOpt , pExPtrs ) ;
|
|
|
|
|
|
}while ( NULL != szBuff ) ;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LONG __stdcall
|
|
|
|
|
|
CallStackDump(EXCEPTION_POINTERS* pExPtrs)
|
|
|
|
|
|
{
|
|
|
|
|
|
std::string szDumpFileName;
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>˾Ƴ<CBBE><C6B3><EFBFBD>.
|
|
|
|
|
|
CHAR DumpFileName[MAX_PATH];
|
|
|
|
|
|
::GetModuleFileNameA(NULL, DumpFileName, MAX_PATH);
|
|
|
|
|
|
|
|
|
|
|
|
CHAR drive[_MAX_DRIVE];
|
|
|
|
|
|
CHAR dir[_MAX_DIR];
|
|
|
|
|
|
CHAR fname[_MAX_FNAME];
|
|
|
|
|
|
CHAR ext[_MAX_EXT];
|
|
|
|
|
|
|
|
|
|
|
|
_splitpath( DumpFileName, drive, dir, fname, ext );
|
|
|
|
|
|
|
|
|
|
|
|
// Ȯ<><C8AE><EFBFBD>ڸ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD>θ<EFBFBD> <20>غ<EFBFBD><D8BA>صд<D8B5>.
|
|
|
|
|
|
szDumpFileName = drive;
|
|
|
|
|
|
szDumpFileName += dir;
|
|
|
|
|
|
szDumpFileName += fname;
|
|
|
|
|
|
|
|
|
|
|
|
struct tm* now=NULL;
|
|
|
|
|
|
time_t systemTime;
|
|
|
|
|
|
|
|
|
|
|
|
time(&systemTime);
|
|
|
|
|
|
now=localtime(&systemTime);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CHAR szTail[MAX_PATH];
|
|
|
|
|
|
ZeroMemory(szTail, sizeof(CHAR) * MAX_PATH);
|
|
|
|
|
|
|
|
|
|
|
|
sprintf(szTail, "_%04d<34><64>%02d<32><64>%02d<32><64>_%02d<32><64>%02d<32><64>%02d<32><64>",
|
|
|
|
|
|
1900+now->tm_year, now->tm_mon+1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec);
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> + <20>ð<EFBFBD><C3B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
|
|
|
|
|
szDumpFileName += szTail;
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD> <20>ݽ<EFBFBD><DDBD>ð<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>ڿ<EFBFBD><DABF><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
|
|
|
|
|
std::string szStackString ;
|
|
|
|
|
|
|
|
|
|
|
|
NxGetCallStack(szStackString, pExPtrs, GSTSO_ALL);
|
|
|
|
|
|
|
|
|
|
|
|
std::string szTimeStampLogFileName = szDumpFileName + ".txt";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::string szStack;
|
|
|
|
|
|
szStack = "\n------------------------------------ Stack --------------------------------------------\n";
|
|
|
|
|
|
|
|
|
|
|
|
std::string szRegister;
|
|
|
|
|
|
szRegister = "\n------------------------------------ Register --------------------------------------------\n";
|
|
|
|
|
|
szRegister += GetRegisterString(pExPtrs);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD>ð<EFBFBD> <20>ε<EFBFBD><CEB5><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ؽ<EFBFBD>Ʈ <20><><EFBFBD>Ϸ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
|
|
|
|
|
FILE* pFile = fopen(szTimeStampLogFileName.c_str(), "w");
|
|
|
|
|
|
fprintf(pFile, "saved dump file to '%s'\n"
|
|
|
|
|
|
"\n<fault reason>\n%s"
|
|
|
|
|
|
"\n\n<user>\n%s"
|
|
|
|
|
|
"\n\n<os>\n%s"
|
|
|
|
|
|
"\n\n<cpu>\n%s"
|
|
|
|
|
|
"\n\n<memory>\n%s\n",
|
|
|
|
|
|
szTimeStampLogFileName.c_str(),
|
|
|
|
|
|
GetFaultReason(pExPtrs),
|
|
|
|
|
|
GetUserInfo(),
|
|
|
|
|
|
GetOSInfo(),
|
|
|
|
|
|
GetCpuInfo(),
|
|
|
|
|
|
GetMemoryInfo()
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
fwrite(szRegister.c_str(), 1, szRegister.size(), pFile );
|
|
|
|
|
|
|
|
|
|
|
|
fwrite(szStack.c_str(), 1, szStack.size(), pFile );
|
|
|
|
|
|
fwrite(szStackString.c_str(), 1, szStackString.size(), pFile);
|
|
|
|
|
|
fclose(pFile);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// dmp <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
|
|
|
|
|
CHAR temp[2048] = "0";
|
|
|
|
|
|
|
|
|
|
|
|
sprintf(temp, "Exception at 0x%08x\n\nCallstack Logging %s", pExPtrs->ExceptionRecord->ExceptionCode, szTimeStampLogFileName.c_str());
|
|
|
|
|
|
MessageBoxA(NULL, temp, szDumpFileName.c_str(), MB_OK);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return EXCEPTION_EXECUTE_HANDLER;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endif
|