DragonNest/Common/BugReporter/StackWalker.cpp
Cussrro 47f7895977 Revert "修复编码问题"
This reverts commit 9e69c01767.
2024-12-21 10:04:04 +08:00

712 lines
20 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "stdafx.h"
#include <windows.h>
#include <assert.h>
#include <time.h>
#include <tchar.h>
#include <DbgHelp.h>
#include <string>
#include <iostream>
#include "StackWalker.h"
#ifdef _DEBUG
#define new new(_NORMAL_BLOCK,__FILE__,__LINE__)
#endif
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;
}
const char*
GetRegisterString(EXCEPTION_POINTERS* pExPtrs)
{
static CHAR szBuff[8192*4] = {0,};
#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" ) ;
FreeLibrary(hInst);
return ( FALSE ) ;
}
g_pGetModuleBaseName =
(GETMODULEBASENAMEW)GetProcAddress ( hInst ,
"GetModuleBaseNameW" ) ;
assert ( NULL != g_pGetModuleBaseName ) ;
if ( NULL == g_pGetModuleBaseName )
{
TRACE ( "GetProcAddress failed on GetModuleBaseNameW!\n" ) ;
FreeLibrary(hInst);
return ( FALSE ) ;
}
g_pGetModuleFileNameEx =
(GETMODULEFILENAMEEXW)GetProcAddress ( hInst ,
"GetModuleFileNameExW" );
assert ( NULL != g_pGetModuleFileNameEx ) ;
if ( NULL == g_pGetModuleFileNameEx )
{
TRACE ( "GetProcAddress failed on GetModuleFileNameExW\n" ) ;
FreeLibrary(hInst);
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 ) ;
while ( NULL != szBuff )
{
szString += szBuff;
szString += "\n";
szBuff = GetNextStackTraceString ( dwOpt , pExPtrs ) ;
}
}