DragonNest/Common/BugReporter/StackWalker.cpp

713 lines
20 KiB
C++
Raw Permalink Normal View History

#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 ) ;
}
}