2004-11-14 08:29:32 +00:00
|
|
|
|
// $Id$
|
|
|
|
|
//
|
2006-04-08 20:22:08 +00:00
|
|
|
|
|
2004-02-06 03:12:30 +00:00
|
|
|
|
/*////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
* Project:
|
|
|
|
|
* Memory_and_Exception_Trace
|
|
|
|
|
*
|
|
|
|
|
* ///////////////////////////////////////////////////////////////////////////
|
|
|
|
|
* File:
|
|
|
|
|
* Stackwalker.cpp
|
|
|
|
|
*
|
|
|
|
|
* Remarks:
|
|
|
|
|
* Dumps the stack of an thread if an exepction occurs
|
|
|
|
|
*
|
|
|
|
|
* Author:
|
|
|
|
|
* Jochen Kalmbach, Germany
|
2004-03-06 09:45:25 +00:00
|
|
|
|
* (c) 2002-2003 (Freeware)
|
|
|
|
|
* http://www.codeproject.com/tools/leakfinder.asp
|
|
|
|
|
*
|
|
|
|
|
* License (The zlib/libpng License, http://www.opensource.org/licenses/zlib-license.php):
|
|
|
|
|
*
|
|
|
|
|
* Copyright (c) 2003 Jochen Kalmbach
|
|
|
|
|
*
|
|
|
|
|
* This software is provided 'as-is', without any express or implied warranty.
|
|
|
|
|
* In no event will the authors be held liable for any damages arising from the
|
|
|
|
|
* use of this software.
|
|
|
|
|
*
|
|
|
|
|
* Permission is granted to anyone to use this software for any purpose, including
|
|
|
|
|
* commercial applications, and to alter it and redistribute it freely, subject to
|
|
|
|
|
* the following restrictions:
|
|
|
|
|
*
|
|
|
|
|
* 1. The origin of this software must not be misrepresented; you must not claim
|
|
|
|
|
* that you wrote the original software. If you use this software in a product,
|
|
|
|
|
* an acknowledgment in the product documentation would be appreciated but is
|
|
|
|
|
* not required.
|
|
|
|
|
*
|
|
|
|
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
|
|
|
|
* misrepresented as being the original software.
|
|
|
|
|
*
|
|
|
|
|
* 3. This notice may not be removed or altered from any source distribution.
|
2004-02-06 03:12:30 +00:00
|
|
|
|
*
|
|
|
|
|
*//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2005-08-03 00:14:26 +00:00
|
|
|
|
|
|
|
|
|
#if defined(_WIN32) && !defined(__STDWX_H__) && !defined(_BOINC_WIN_) && !defined(_AFX_STDAFX_H_)
|
|
|
|
|
#include "boinc_win.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
2004-02-06 03:12:30 +00:00
|
|
|
|
|
2006-04-08 20:22:08 +00:00
|
|
|
|
#include "version.h"
|
|
|
|
|
#include "dbghelp.h"
|
|
|
|
|
#include "stackwalker_win.h"
|
2004-02-06 03:12:30 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define gle (GetLastError())
|
|
|
|
|
#define lenof(a) (sizeof(a) / sizeof((a)[0]))
|
|
|
|
|
#define IMGSYMLEN ( sizeof IMAGEHLP_SYMBOL )
|
|
|
|
|
#define TTBUFLEN 8096 // for a temp buffer (2^13)
|
|
|
|
|
|
|
|
|
|
|
2006-04-08 20:22:08 +00:00
|
|
|
|
// ImagehlpApiVersion()
|
|
|
|
|
typedef LPAPI_VERSION (__stdcall WINAPI *tIAV)(
|
|
|
|
|
VOID
|
|
|
|
|
);
|
|
|
|
|
tIAV pIAV = NULL;
|
2004-02-06 03:12:30 +00:00
|
|
|
|
|
|
|
|
|
// SymCleanup()
|
2006-04-08 20:22:08 +00:00
|
|
|
|
typedef BOOL (__stdcall *tSC)(
|
|
|
|
|
IN HANDLE hProcess
|
|
|
|
|
);
|
2004-02-06 03:12:30 +00:00
|
|
|
|
tSC pSC = NULL;
|
|
|
|
|
|
2006-04-08 20:22:08 +00:00
|
|
|
|
// SymEnumerateModules64()
|
|
|
|
|
typedef BOOL (__stdcall WINAPI *tSEM)(
|
|
|
|
|
IN HANDLE hProcess,
|
|
|
|
|
IN PSYM_ENUMMODULES_CALLBACK64 EnumModulesCallback,
|
|
|
|
|
IN PVOID UserContext
|
|
|
|
|
);
|
|
|
|
|
tSEM pSEM = NULL;
|
|
|
|
|
|
|
|
|
|
// SymFunctionTableAccess64()
|
|
|
|
|
typedef PVOID (__stdcall *tSFTA)(
|
|
|
|
|
IN HANDLE hProcess,
|
|
|
|
|
IN DWORD64 AddrBase
|
|
|
|
|
);
|
2004-02-06 03:12:30 +00:00
|
|
|
|
tSFTA pSFTA = NULL;
|
|
|
|
|
|
2006-04-08 20:22:08 +00:00
|
|
|
|
// SymGetLineFromAddr64()
|
|
|
|
|
typedef BOOL (__stdcall *tSGLFA)(
|
|
|
|
|
IN HANDLE hProcess,
|
|
|
|
|
IN DWORD64 dwAddr,
|
|
|
|
|
OUT PDWORD pdwDisplacement,
|
|
|
|
|
OUT PIMAGEHLP_LINE64 Line
|
|
|
|
|
);
|
2004-02-06 03:12:30 +00:00
|
|
|
|
tSGLFA pSGLFA = NULL;
|
|
|
|
|
|
2006-04-08 20:22:08 +00:00
|
|
|
|
// SymGetModuleBase64()
|
|
|
|
|
typedef DWORD64 (__stdcall *tSGMB)(
|
|
|
|
|
IN HANDLE hProcess,
|
|
|
|
|
IN DWORD64 dwAddr
|
|
|
|
|
);
|
2004-02-06 03:12:30 +00:00
|
|
|
|
tSGMB pSGMB = NULL;
|
|
|
|
|
|
2006-04-08 20:22:08 +00:00
|
|
|
|
// SymGetModuleInfo64()
|
|
|
|
|
typedef BOOL (__stdcall *tSGMI)(
|
|
|
|
|
IN HANDLE hProcess,
|
|
|
|
|
IN DWORD64 dwAddr,
|
|
|
|
|
OUT PIMAGEHLP_MODULE64 ModuleInfo );
|
2004-02-06 03:12:30 +00:00
|
|
|
|
tSGMI pSGMI = NULL;
|
|
|
|
|
|
|
|
|
|
// SymGetOptions()
|
2006-04-08 20:22:08 +00:00
|
|
|
|
typedef DWORD (__stdcall *tSGO)(
|
|
|
|
|
VOID
|
|
|
|
|
);
|
2004-02-06 03:12:30 +00:00
|
|
|
|
tSGO pSGO = NULL;
|
|
|
|
|
|
2006-04-08 20:22:08 +00:00
|
|
|
|
// SymGetSearchPath()
|
|
|
|
|
typedef BOOL (__stdcall *tSGSP)(
|
|
|
|
|
IN HANDLE hProcess,
|
|
|
|
|
OUT PTSTR SearchPath,
|
|
|
|
|
IN DWORD SearchPathLength
|
|
|
|
|
);
|
|
|
|
|
tSGSP pSGSP = NULL;
|
|
|
|
|
|
|
|
|
|
// SymFromAddr()
|
|
|
|
|
typedef BOOL (__stdcall *tSFA)(
|
|
|
|
|
IN HANDLE hProcess,
|
|
|
|
|
IN DWORD64 dwAddr,
|
|
|
|
|
OUT PDWORD64 pdwDisplacement,
|
|
|
|
|
OUT PSYMBOL_INFO Symbol
|
|
|
|
|
);
|
|
|
|
|
tSFA pSFA = NULL;
|
2004-02-06 03:12:30 +00:00
|
|
|
|
|
|
|
|
|
// SymInitialize()
|
2006-04-08 20:22:08 +00:00
|
|
|
|
typedef BOOL (__stdcall *tSI)(
|
|
|
|
|
IN HANDLE hProcess,
|
|
|
|
|
IN PCTSTR UserSearchPath,
|
|
|
|
|
IN BOOL fInvadeProcess
|
|
|
|
|
);
|
2004-02-06 03:12:30 +00:00
|
|
|
|
tSI pSI = NULL;
|
|
|
|
|
|
2006-04-08 20:22:08 +00:00
|
|
|
|
// SymLoadModuleEx()
|
|
|
|
|
typedef DWORD64 (__stdcall *tSLM)(
|
|
|
|
|
IN HANDLE hProcess,
|
|
|
|
|
IN HANDLE hFile,
|
|
|
|
|
IN PCSTR ImageName,
|
|
|
|
|
IN PCSTR ModuleName,
|
|
|
|
|
IN DWORD64 BaseOfDll,
|
|
|
|
|
IN DWORD SizeOfDll
|
|
|
|
|
);
|
2004-02-06 03:12:30 +00:00
|
|
|
|
tSLM pSLM = NULL;
|
|
|
|
|
|
2006-04-08 20:22:08 +00:00
|
|
|
|
// SymRegisterCallback64()
|
|
|
|
|
typedef BOOL (__stdcall *tSRC)(
|
|
|
|
|
IN HANDLE hProcess,
|
|
|
|
|
PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,
|
|
|
|
|
ULONG64 UserContext
|
|
|
|
|
);
|
|
|
|
|
tSRC pSRC = NULL;
|
|
|
|
|
|
2004-02-06 03:12:30 +00:00
|
|
|
|
// SymSetOptions()
|
2006-04-08 20:22:08 +00:00
|
|
|
|
typedef DWORD (__stdcall *tSSO)(
|
|
|
|
|
IN DWORD SymOptions
|
|
|
|
|
);
|
2004-02-06 03:12:30 +00:00
|
|
|
|
tSSO pSSO = NULL;
|
|
|
|
|
|
|
|
|
|
// StackWalk()
|
2006-04-08 20:22:08 +00:00
|
|
|
|
typedef BOOL (__stdcall *tSW)(
|
|
|
|
|
DWORD MachineType,
|
|
|
|
|
HANDLE hProcess,
|
|
|
|
|
HANDLE hThread,
|
|
|
|
|
LPSTACKFRAME64 StackFrame,
|
|
|
|
|
PVOID ContextRecord,
|
|
|
|
|
PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
|
|
|
|
|
PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
|
|
|
|
|
PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
|
|
|
|
|
PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
|
|
|
|
|
);
|
2004-02-06 03:12:30 +00:00
|
|
|
|
tSW pSW = NULL;
|
|
|
|
|
|
|
|
|
|
// UnDecorateSymbolName()
|
2006-04-08 20:22:08 +00:00
|
|
|
|
typedef DWORD (__stdcall WINAPI *tUDSN)(
|
|
|
|
|
PCSTR DecoratedName,
|
|
|
|
|
PSTR UnDecoratedName,
|
|
|
|
|
DWORD UndecoratedLength,
|
|
|
|
|
DWORD Flags
|
|
|
|
|
);
|
2004-02-06 03:12:30 +00:00
|
|
|
|
tUDSN pUDSN = NULL;
|
|
|
|
|
|
2006-04-08 20:22:08 +00:00
|
|
|
|
#ifndef SYMOPT_NO_PROMPTS
|
|
|
|
|
#define SYMOPT_NO_PROMPTS 0x00080000
|
|
|
|
|
#endif
|
2004-02-06 03:12:30 +00:00
|
|
|
|
|
2006-04-08 20:22:08 +00:00
|
|
|
|
// Forward definitions of functions:
|
|
|
|
|
static void ShowStackRM( HANDLE hThread, CONTEXT& c, HANDLE hProcess);
|
2004-02-06 03:12:30 +00:00
|
|
|
|
|
2006-04-08 20:22:08 +00:00
|
|
|
|
// Global data:
|
|
|
|
|
static BOOL g_bInitialized = FALSE;
|
|
|
|
|
static DWORD g_dwShowCount = 0; // increase at every ShowStack-Call
|
|
|
|
|
static HINSTANCE g_hDbgHelpDll = NULL;
|
|
|
|
|
static HINSTANCE g_hSymSrvDll = NULL;
|
|
|
|
|
static HINSTANCE g_hSrcSrvDll = NULL;
|
|
|
|
|
static CRITICAL_SECTION g_csFileOpenClose = {0};
|
|
|
|
|
|
|
|
|
|
ULONG64 gSymbolBuffer[
|
|
|
|
|
(sizeof(SYMBOL_INFO) +
|
|
|
|
|
MAX_SYM_NAME*sizeof(TCHAR) +
|
|
|
|
|
sizeof(ULONG64) - 1) /
|
|
|
|
|
sizeof(ULONG64)
|
|
|
|
|
];
|
|
|
|
|
PSYMBOL_INFO gpSymbol = (PSYMBOL_INFO)gSymbolBuffer;
|
|
|
|
|
|
|
|
|
|
// ##########################################################################################
|
|
|
|
|
// ##########################################################################################
|
|
|
|
|
// ##########################################################################################
|
|
|
|
|
// ##########################################################################################
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Write Date/Time to specified file (will also work after 2038)
|
|
|
|
|
static void WriteDateTime() {
|
|
|
|
|
TCHAR pszTemp[11], pszTemp2[11];
|
|
|
|
|
|
|
|
|
|
_tstrdate( pszTemp );
|
|
|
|
|
_tstrtime( pszTemp2 );
|
|
|
|
|
|
|
|
|
|
_ftprintf(stderr, _T("%s %s"), pszTemp, pszTemp2 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BOOL CALLBACK SymRegisterCallbackProc(HANDLE hProcess, ULONG ActionCode, ULONG64 CallbackData, ULONG64 UserContext)
|
2004-02-06 03:12:30 +00:00
|
|
|
|
{
|
2006-04-08 20:22:08 +00:00
|
|
|
|
BOOL bRetVal = FALSE;
|
|
|
|
|
PIMAGEHLP_DEFERRED_SYMBOL_LOAD64 pModule;
|
|
|
|
|
|
|
|
|
|
switch(ActionCode) {
|
|
|
|
|
case CBA_DEBUG_INFO:
|
|
|
|
|
_ftprintf(stderr, _T("DEBUG: %s\n"), CallbackData);
|
|
|
|
|
bRetVal = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE:
|
|
|
|
|
pModule = (PIMAGEHLP_DEFERRED_SYMBOL_LOAD64)CallbackData;
|
|
|
|
|
_ftprintf(stderr, _T("MODLOAD: %.8x %s (Symbols Loaded)\n"), pModule->BaseOfImage, pModule->FileName);
|
|
|
|
|
bRetVal = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fflush(stderr);
|
|
|
|
|
return bRetVal;
|
|
|
|
|
}
|
2004-02-06 03:12:30 +00:00
|
|
|
|
|
|
|
|
|
|
2006-04-08 20:22:08 +00:00
|
|
|
|
BOOL CALLBACK SymEnumerateModulesProc(LPSTR ModuleName, DWORD64 BaseOfDll, PVOID UserContext)
|
2004-02-06 03:12:30 +00:00
|
|
|
|
{
|
2006-04-08 20:22:08 +00:00
|
|
|
|
IMAGEHLP_MODULE64 Module;
|
|
|
|
|
char type[MAX_SYM_NAME];
|
2004-02-06 03:12:30 +00:00
|
|
|
|
|
2006-04-08 20:22:08 +00:00
|
|
|
|
memset( &Module, '\0', sizeof(IMAGEHLP_MODULE64) );
|
|
|
|
|
Module.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
|
2004-02-06 03:12:30 +00:00
|
|
|
|
|
2006-04-08 20:22:08 +00:00
|
|
|
|
memset( &type, '\0', sizeof type );
|
2004-02-06 03:12:30 +00:00
|
|
|
|
|
2006-04-08 20:22:08 +00:00
|
|
|
|
if ( !pSGMI( GetCurrentProcess(), BaseOfDll, &Module ) )
|
|
|
|
|
{
|
|
|
|
|
_ftprintf(stderr, _T("SymGetModuleInfo(): GetLastError = %lu\n"), gle );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
switch ( Module.SymType )
|
|
|
|
|
{
|
|
|
|
|
case SymNone:
|
|
|
|
|
strcpy( type, "-nosymbols-" );
|
|
|
|
|
break;
|
|
|
|
|
case SymCoff:
|
|
|
|
|
strcpy( type, "COFF" );
|
|
|
|
|
break;
|
|
|
|
|
case SymCv:
|
|
|
|
|
strcpy( type, "CV" );
|
|
|
|
|
break;
|
|
|
|
|
case SymPdb:
|
|
|
|
|
strcpy( type, "PDB" );
|
|
|
|
|
break;
|
|
|
|
|
case SymExport:
|
|
|
|
|
strcpy( type, "-exported-" );
|
|
|
|
|
break;
|
|
|
|
|
case SymDeferred:
|
|
|
|
|
strcpy( type, "-deferred-" );
|
|
|
|
|
break;
|
|
|
|
|
case SymSym:
|
|
|
|
|
strcpy( type, "SYM" );
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
_snprintf( type, sizeof type, "symtype=%ld", (long) Module.SymType );
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-02-06 03:12:30 +00:00
|
|
|
|
|
2006-04-08 20:22:08 +00:00
|
|
|
|
_ftprintf(stderr, _T("ModLoad: "));
|
|
|
|
|
_ftprintf(stderr, _T("%.8x ") , Module.BaseOfImage);
|
|
|
|
|
_ftprintf(stderr, _T("%.8x ") , Module.ImageSize);
|
|
|
|
|
_ftprintf(stderr, _T("%s ") , Module.LoadedImageName);
|
|
|
|
|
_ftprintf(stderr, _T("(%s Symbols Loaded)"), type);
|
|
|
|
|
_ftprintf(stderr, _T("\n"));
|
|
|
|
|
fflush(stderr);
|
2004-02-06 03:12:30 +00:00
|
|
|
|
|
2006-04-08 20:22:08 +00:00
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int DebuggerInitialize()
|
2004-02-06 03:12:30 +00:00
|
|
|
|
{
|
2006-04-08 20:22:08 +00:00
|
|
|
|
if (g_bInitialized != FALSE)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
g_hDbgHelpDll = LoadLibrary( _T("C:\\Program Files\\BOINC\\dbghelp.dll") );
|
|
|
|
|
if ( g_hDbgHelpDll == NULL )
|
|
|
|
|
{
|
|
|
|
|
g_hDbgHelpDll = LoadLibrary( _T("dbghelp.dll") );
|
|
|
|
|
if ( g_hDbgHelpDll == NULL )
|
|
|
|
|
{
|
|
|
|
|
_ftprintf( stderr, "LoadLibrary( \"dbghelp.dll\" ): GetLastError = %lu\n", gle );
|
|
|
|
|
g_bInitialized = FALSE;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_hSymSrvDll = LoadLibrary( _T("C:\\Program Files\\BOINC\\symsrv.dll") );
|
|
|
|
|
if ( g_hSymSrvDll == NULL )
|
|
|
|
|
{
|
|
|
|
|
g_hSymSrvDll = LoadLibrary( _T("symsrv.dll") );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_hSrcSrvDll = LoadLibrary( _T("C:\\Program Files\\BOINC\\srcsrv.dll") );
|
|
|
|
|
if ( g_hSrcSrvDll == NULL )
|
|
|
|
|
{
|
|
|
|
|
g_hSrcSrvDll = LoadLibrary( _T("srcsrv.dll") );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pIAV = (tIAV) GetProcAddress( g_hDbgHelpDll, "ImagehlpApiVersion" );
|
|
|
|
|
pSC = (tSC) GetProcAddress( g_hDbgHelpDll, "SymCleanup" );
|
|
|
|
|
pSEM = (tSEM) GetProcAddress( g_hDbgHelpDll, "SymEnumerateModules64" );
|
|
|
|
|
pSFTA = (tSFTA) GetProcAddress( g_hDbgHelpDll, "SymFunctionTableAccess64" );
|
|
|
|
|
pSGLFA = (tSGLFA) GetProcAddress( g_hDbgHelpDll, "SymGetLineFromAddr64" );
|
|
|
|
|
pSGMB = (tSGMB) GetProcAddress( g_hDbgHelpDll, "SymGetModuleBase64" );
|
|
|
|
|
pSGMI = (tSGMI) GetProcAddress( g_hDbgHelpDll, "SymGetModuleInfo64" );
|
|
|
|
|
pSGO = (tSGO) GetProcAddress( g_hDbgHelpDll, "SymGetOptions" );
|
|
|
|
|
pSGSP = (tSGSP) GetProcAddress( g_hDbgHelpDll, "SymGetSearchPath" );
|
|
|
|
|
pSFA = (tSFA) GetProcAddress( g_hDbgHelpDll, "SymFromAddr" );
|
|
|
|
|
pSI = (tSI) GetProcAddress( g_hDbgHelpDll, "SymInitialize" );
|
|
|
|
|
pSRC = (tSRC) GetProcAddress( g_hDbgHelpDll, "SymRegisterCallback64" );
|
|
|
|
|
pSSO = (tSSO) GetProcAddress( g_hDbgHelpDll, "SymSetOptions" );
|
|
|
|
|
pSW = (tSW) GetProcAddress( g_hDbgHelpDll, "StackWalk64" );
|
|
|
|
|
pUDSN = (tUDSN) GetProcAddress( g_hDbgHelpDll, "UnDecorateSymbolName" );
|
|
|
|
|
pSLM = (tSLM) GetProcAddress( g_hDbgHelpDll, "SymLoadModuleEx" );
|
|
|
|
|
|
|
|
|
|
if ( pIAV == NULL || pSC == NULL || pSEM == NULL || pSFTA == NULL ||
|
|
|
|
|
pSGMB == NULL || pSGMI == NULL || pSGO == NULL || pSFA == NULL ||
|
|
|
|
|
pSI == NULL || pSRC == NULL || pSSO == NULL || pSW == NULL ||
|
|
|
|
|
pUDSN == NULL || pSLM == NULL )
|
2006-03-17 09:03:29 +00:00
|
|
|
|
{
|
2006-04-08 20:22:08 +00:00
|
|
|
|
_ftprintf( stderr, "GetProcAddress(): some required function not found.\n" );
|
|
|
|
|
FreeLibrary( g_hDbgHelpDll );
|
2006-03-17 09:03:29 +00:00
|
|
|
|
g_bInitialized = FALSE;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2006-04-08 20:22:08 +00:00
|
|
|
|
|
|
|
|
|
g_bInitialized = TRUE;
|
|
|
|
|
|
|
|
|
|
InitializeCriticalSection(&g_csFileOpenClose);
|
|
|
|
|
EnterCriticalSection(&g_csFileOpenClose);
|
|
|
|
|
|
|
|
|
|
CHAR* tt;
|
|
|
|
|
CHAR* p;
|
|
|
|
|
DWORD symOptions; // symbol handler settings
|
|
|
|
|
std::string symSearchPath;
|
|
|
|
|
|
|
|
|
|
// NOTE: normally, the exe directory and the current directory should be taken
|
|
|
|
|
// from the target process. The current dir would be gotten through injection
|
|
|
|
|
// of a remote thread; the exe fir through either ToolHelp32 or PSAPI.
|
|
|
|
|
|
|
|
|
|
tt = (CHAR*) malloc(sizeof(CHAR) * TTBUFLEN); // Get the temporary buffer
|
|
|
|
|
if (!tt) return 1; // not enough memory...
|
|
|
|
|
|
|
|
|
|
// build symbol search path from:
|
|
|
|
|
symSearchPath = "";
|
|
|
|
|
|
|
|
|
|
// current directory
|
|
|
|
|
if ( GetCurrentDirectoryA( TTBUFLEN, tt ) )
|
|
|
|
|
symSearchPath += tt + std::string( ";" );
|
|
|
|
|
|
|
|
|
|
// dir with executable
|
|
|
|
|
if ( GetModuleFileNameA( 0, tt, TTBUFLEN ) )
|
|
|
|
|
{
|
|
|
|
|
for ( p = tt + strlen( tt ) - 1; p >= tt; -- p )
|
|
|
|
|
{
|
|
|
|
|
// locate the rightmost path separator
|
|
|
|
|
if ( *p == '\\' || *p == '/' || *p == ':' )
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
// if we found one, p is pointing at it; if not, tt only contains
|
|
|
|
|
// an exe name (no path), and p points before its first byte
|
|
|
|
|
if ( p != tt ) // path sep found?
|
|
|
|
|
{
|
|
|
|
|
if ( *p == ':' ) // we leave colons in place
|
|
|
|
|
++p;
|
|
|
|
|
*p = '\0'; // eliminate the exe name and last path sep
|
|
|
|
|
symSearchPath += tt + std::string( ";" );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// environment variable _NT_SYMBOL_PATH
|
|
|
|
|
if ( GetEnvironmentVariableA( "_NT_SYMBOL_PATH", tt, TTBUFLEN ) )
|
|
|
|
|
symSearchPath += tt + std::string( ";" );
|
|
|
|
|
// environment variable _NT_ALTERNATE_SYMBOL_PATH
|
|
|
|
|
if ( GetEnvironmentVariableA( "_NT_ALTERNATE_SYMBOL_PATH", tt, TTBUFLEN ) )
|
|
|
|
|
symSearchPath += tt + std::string( ";" );
|
|
|
|
|
|
|
|
|
|
// microsoft public symbol server
|
|
|
|
|
symSearchPath += std::string( "srv*c:\\windows\\symbols*http://msdl.microsoft.com/download/symbols;" );
|
|
|
|
|
|
|
|
|
|
if ( symSearchPath.size() > 0 ) // if we added anything, we have a trailing semicolon
|
|
|
|
|
symSearchPath = symSearchPath.substr( 0, symSearchPath.size() - 1 );
|
|
|
|
|
|
|
|
|
|
// init symbol handler stuff (SymInitialize())
|
|
|
|
|
if ( ! pSI(GetCurrentProcess(), symSearchPath.c_str(), TRUE ) )
|
|
|
|
|
{
|
|
|
|
|
_ftprintf(stderr, _T("SymInitialize(): GetLastError = %lu\n"), gle );
|
|
|
|
|
if (tt) free( tt );
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SymGetOptions()
|
|
|
|
|
symOptions = pSGO();
|
|
|
|
|
symOptions |= SYMOPT_LOAD_LINES;
|
|
|
|
|
symOptions |= SYMOPT_DEBUG;
|
|
|
|
|
symOptions |= SYMOPT_NO_PROMPTS;
|
|
|
|
|
symOptions &= ~SYMOPT_UNDNAME;
|
|
|
|
|
pSSO( symOptions ); // SymSetOptions()
|
|
|
|
|
|
|
|
|
|
if (tt)
|
|
|
|
|
free( tt );
|
|
|
|
|
|
|
|
|
|
LeaveCriticalSection(&g_csFileOpenClose);
|
|
|
|
|
return 0;
|
2004-02-06 03:12:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
2006-04-08 20:22:08 +00:00
|
|
|
|
int DebuggerDisplayDiagnostics()
|
2004-02-06 03:12:30 +00:00
|
|
|
|
{
|
2006-04-08 20:22:08 +00:00
|
|
|
|
EnterCriticalSection(&g_csFileOpenClose);
|
2004-02-06 03:12:30 +00:00
|
|
|
|
|
2006-04-08 20:22:08 +00:00
|
|
|
|
LPAPI_VERSION lpDV = NULL;
|
|
|
|
|
TCHAR buf[TTBUFLEN];
|
2004-02-06 03:12:30 +00:00
|
|
|
|
|
2006-04-08 20:22:08 +00:00
|
|
|
|
lpDV = pIAV();
|
|
|
|
|
pSGSP(GetCurrentProcess(), buf, TTBUFLEN);
|
|
|
|
|
|
|
|
|
|
_ftprintf( stderr, _T("\n\n"));
|
|
|
|
|
_ftprintf( stderr, _T("BOINC Windows Debugger Version %s\n"), BOINC_VERSION_STRING);
|
|
|
|
|
_ftprintf( stderr, _T("\n"));
|
|
|
|
|
_ftprintf( stderr, _T("Dump Timestamp : "));
|
|
|
|
|
WriteDateTime();
|
|
|
|
|
_ftprintf( stderr, _T("\n"));
|
|
|
|
|
_ftprintf( stderr, _T("Debugger Engine : %d.%d.%d.%d\n"), lpDV->MajorVersion, lpDV->MinorVersion, lpDV->Revision, lpDV->Reserved);
|
|
|
|
|
_ftprintf( stderr, _T("Symbol Search Path: %s\n"), buf);
|
|
|
|
|
_ftprintf( stderr, _T("\n\n"));
|
|
|
|
|
|
|
|
|
|
if (!pSRC(GetCurrentProcess(), SymRegisterCallbackProc, NULL))
|
|
|
|
|
{
|
|
|
|
|
_ftprintf(stderr, _T("SymRegisterCallback64(): GetLastError = %lu\n"), gle );
|
|
|
|
|
}
|
2004-02-06 03:12:30 +00:00
|
|
|
|
|
2006-04-08 20:22:08 +00:00
|
|
|
|
if (!pSEM(GetCurrentProcess(), SymEnumerateModulesProc, NULL))
|
2004-02-06 03:12:30 +00:00
|
|
|
|
{
|
2006-04-08 20:22:08 +00:00
|
|
|
|
_ftprintf(stderr, _T("SymEnumerateModules64(): GetLastError = %lu\n"), gle );
|
2004-02-06 03:12:30 +00:00
|
|
|
|
}
|
2006-04-08 20:22:08 +00:00
|
|
|
|
|
|
|
|
|
_ftprintf( stderr, _T("\n"));
|
|
|
|
|
|
|
|
|
|
LeaveCriticalSection(&g_csFileOpenClose);
|
|
|
|
|
|
|
|
|
|
return 0;
|
2004-02-06 03:12:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// #################################################################################
|
|
|
|
|
// #################################################################################
|
|
|
|
|
// Here the Stackwalk-Part begins.
|
|
|
|
|
// Some of the code is from an example from a book
|
|
|
|
|
// But I couldn<64>t find the reference anymore... sorry...
|
|
|
|
|
// If someone knowns, please let me know...
|
|
|
|
|
// #################################################################################
|
|
|
|
|
// #################################################################################
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if you use C++ exception handling: install a translator function
|
|
|
|
|
// with set_se_translator(). In the context of that function (but *not*
|
|
|
|
|
// afterwards), you can either do your stack dump, or save the CONTEXT
|
|
|
|
|
// record as a local copy. Note that you must do the stack sump at the
|
|
|
|
|
// earliest opportunity, to avoid the interesting stackframes being gone
|
|
|
|
|
// by the time you do the dump.
|
|
|
|
|
|
|
|
|
|
// status:
|
|
|
|
|
// - EXCEPTION_CONTINUE_SEARCH: exception wird weitergereicht
|
|
|
|
|
// - EXCEPTION_CONTINUE_EXECUTION:
|
|
|
|
|
// - EXCEPTION_EXECUTE_HANDLER:
|
2006-04-08 20:22:08 +00:00
|
|
|
|
DWORD StackwalkFilter(EXCEPTION_POINTERS *ep, DWORD status)
|
2004-02-06 03:12:30 +00:00
|
|
|
|
{
|
|
|
|
|
HANDLE hThread;
|
|
|
|
|
|
|
|
|
|
DuplicateHandle( GetCurrentProcess(), GetCurrentThread(),
|
|
|
|
|
GetCurrentProcess(), &hThread, 0, false, DUPLICATE_SAME_ACCESS );
|
|
|
|
|
|
2006-04-08 20:22:08 +00:00
|
|
|
|
StackwalkThread( hThread, ep->ContextRecord);
|
2004-02-06 03:12:30 +00:00
|
|
|
|
|
2006-04-08 20:22:08 +00:00
|
|
|
|
CloseHandle( hThread );
|
2004-02-06 03:12:30 +00:00
|
|
|
|
|
|
|
|
|
return status;
|
|
|
|
|
} // StackwalkFilter
|
|
|
|
|
|
2006-04-08 20:22:08 +00:00
|
|
|
|
void StackwalkThread(HANDLE hThread, CONTEXT* c)
|
2006-03-21 12:04:14 +00:00
|
|
|
|
{
|
2006-04-08 20:22:08 +00:00
|
|
|
|
ShowStackRM( hThread, *c, GetCurrentProcess() );
|
2006-03-21 12:04:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
2006-04-08 20:22:08 +00:00
|
|
|
|
static void ShowStackRM(HANDLE hThread, CONTEXT& Context, HANDLE hSWProcess)
|
2004-02-06 03:12:30 +00:00
|
|
|
|
{
|
2006-04-08 20:22:08 +00:00
|
|
|
|
BOOL bRetVal = FALSE;
|
2004-02-06 03:12:30 +00:00
|
|
|
|
|
2006-04-08 20:22:08 +00:00
|
|
|
|
int frameNum; // counts walked frames
|
|
|
|
|
DWORD64 offsetFromSymbol; // tells us how far from the symbol we were
|
|
|
|
|
DWORD offsetFromLine; // tells us how far from the line we were
|
2004-02-06 03:12:30 +00:00
|
|
|
|
|
2006-04-08 20:22:08 +00:00
|
|
|
|
char undName[MAX_SYM_NAME]; // undecorated name
|
|
|
|
|
IMAGEHLP_MODULE64 Module;
|
|
|
|
|
IMAGEHLP_LINE64 Line;
|
|
|
|
|
STACKFRAME64 StackFrame;
|
2004-02-06 03:12:30 +00:00
|
|
|
|
|
2006-04-08 20:22:08 +00:00
|
|
|
|
if (g_bInitialized == FALSE)
|
2004-02-06 03:12:30 +00:00
|
|
|
|
{
|
2006-04-08 20:22:08 +00:00
|
|
|
|
_ftprintf(stderr, _T("Stackwalker not initialized (or was not able to initialize)!\n"));
|
|
|
|
|
return;
|
2004-02-06 03:12:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2006-04-08 20:22:08 +00:00
|
|
|
|
// Critical section begin...
|
|
|
|
|
EnterCriticalSection(&g_csFileOpenClose);
|
|
|
|
|
InterlockedIncrement((long*) &g_dwShowCount); // erh<72>he counter
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Dump the Context data
|
|
|
|
|
_ftprintf(stderr,
|
|
|
|
|
_T("eax=%.8x ebx=%.8x ecx=%.8x edx=%.8x esi=%.8x edi=%.8x\n"),
|
|
|
|
|
Context.Eax, Context.Ebx, Context.Ecx, Context.Edx, Context.Esi, Context.Edi
|
|
|
|
|
);
|
|
|
|
|
_ftprintf(stderr,
|
|
|
|
|
_T("eip=%.8x esp=%.8x ebp=%.8x\n"),
|
|
|
|
|
Context.Eip, Context.Esp, Context.Ebp
|
|
|
|
|
);
|
|
|
|
|
_ftprintf(stderr,
|
|
|
|
|
_T("cs=%.4x ss=%.4x ds=%.4x es=%.4x fs=%.4x gs=%.4x efl=%.8x\n\n"),
|
|
|
|
|
Context.SegCs, Context.SegSs, Context.SegDs, Context.SegEs, Context.SegFs, Context.SegGs, Context.EFlags
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Stack Header
|
|
|
|
|
_ftprintf(stderr, _T("ChildEBP RetAddr Args to Child\n"));
|
|
|
|
|
fflush( stderr );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// init STACKFRAME for first call
|
|
|
|
|
// Notes: AddrModeFlat is just an assumption. I hate VDM debugging.
|
|
|
|
|
// Notes: will have to be #ifdef-ed for Alphas; MIPSes are dead anyway,
|
|
|
|
|
// and good riddance.
|
|
|
|
|
memset( &StackFrame, '\0', sizeof(STACKFRAME64) );
|
|
|
|
|
StackFrame.AddrPC.Offset = Context.Eip;
|
|
|
|
|
StackFrame.AddrPC.Mode = AddrModeFlat;
|
|
|
|
|
StackFrame.AddrFrame.Offset = Context.Ebp;
|
|
|
|
|
StackFrame.AddrFrame.Mode = AddrModeFlat;
|
|
|
|
|
|
|
|
|
|
memset( gpSymbol, '\0', sizeof(gSymbolBuffer) );
|
|
|
|
|
gpSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
|
|
|
|
gpSymbol->MaxNameLen = MAX_SYM_NAME;
|
|
|
|
|
|
|
|
|
|
memset( &Line, '\0', sizeof(IMAGEHLP_LINE64) );
|
|
|
|
|
Line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
|
|
|
|
|
|
|
|
|
memset( &Module, '\0', sizeof(IMAGEHLP_MODULE64) );
|
|
|
|
|
Module.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
|
|
|
|
|
|
|
|
|
|
for ( frameNum = 0; ; ++frameNum )
|
2004-02-06 03:12:30 +00:00
|
|
|
|
{
|
2006-04-08 20:22:08 +00:00
|
|
|
|
// get next stack frame (StackWalk(), SymFunctionTableAccess(), SymGetModuleBase())
|
|
|
|
|
// if this returns ERROR_INVALID_ADDRESS (487) or ERROR_NOACCESS (998), you can
|
|
|
|
|
// assume that either you are done, or that the stack is so hosed that the next
|
|
|
|
|
// deeper frame could not be found.
|
|
|
|
|
bRetVal = pSW(
|
|
|
|
|
IMAGE_FILE_MACHINE_I386,
|
|
|
|
|
hSWProcess,
|
|
|
|
|
hThread,
|
|
|
|
|
&StackFrame,
|
|
|
|
|
&Context,
|
|
|
|
|
NULL,
|
|
|
|
|
(PFUNCTION_TABLE_ACCESS_ROUTINE64)pSFTA,
|
|
|
|
|
(PGET_MODULE_BASE_ROUTINE64)pSGMB,
|
|
|
|
|
NULL
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (!bRetVal)
|
|
|
|
|
break;
|
2004-02-06 03:12:30 +00:00
|
|
|
|
|
2006-04-08 20:22:08 +00:00
|
|
|
|
if ( StackFrame.AddrPC.Offset == 0 )
|
2004-02-06 03:12:30 +00:00
|
|
|
|
{
|
2006-04-08 20:22:08 +00:00
|
|
|
|
// Special case: If we are here, we have no valid callstack entry!
|
|
|
|
|
_ftprintf(stderr, _T("(-nosymbols- PC == 0)\n"), g_dwShowCount);
|
2004-02-06 03:12:30 +00:00
|
|
|
|
}
|
2006-04-08 20:22:08 +00:00
|
|
|
|
else
|
2004-02-06 03:12:30 +00:00
|
|
|
|
{
|
2006-04-08 20:22:08 +00:00
|
|
|
|
// show procedure info (SymFromAddr())
|
|
|
|
|
undName[0] = 0;
|
|
|
|
|
offsetFromSymbol = 0;
|
|
|
|
|
if ( !pSFA( hSWProcess, StackFrame.AddrPC.Offset, &offsetFromSymbol, gpSymbol ) )
|
2004-02-06 03:12:30 +00:00
|
|
|
|
{
|
2006-04-08 20:22:08 +00:00
|
|
|
|
if ( gle != 487 )
|
|
|
|
|
_ftprintf(stderr, _T("SymFromAddr(): GetLastError = %lu\n"), gle );
|
2004-02-06 03:12:30 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
2006-04-08 20:22:08 +00:00
|
|
|
|
{
|
|
|
|
|
// UnDecorateSymbolName()
|
|
|
|
|
pUDSN( gpSymbol->Name, undName, MAX_SYM_NAME, UNDNAME_NAME_ONLY );
|
|
|
|
|
}
|
2004-02-06 03:12:30 +00:00
|
|
|
|
|
2006-04-08 20:22:08 +00:00
|
|
|
|
// show line number info (SymGetLineFromAddr())
|
|
|
|
|
offsetFromLine = 0;
|
|
|
|
|
if ( !pSGLFA( hSWProcess, StackFrame.AddrPC.Offset, &offsetFromLine, &Line ) )
|
|
|
|
|
{
|
|
|
|
|
if ( (gle != 487) && (frameNum > 0) ) // ignore error for first frame
|
|
|
|
|
{
|
|
|
|
|
_ftprintf(stderr, _T("SymGetLineFromAddr(): GetLastError = %lu\n"), gle );
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-02-06 03:12:30 +00:00
|
|
|
|
|
2006-04-08 20:22:08 +00:00
|
|
|
|
// show module info (SymGetModuleInfo())
|
|
|
|
|
if ( !pSGMI( hSWProcess, StackFrame.AddrPC.Offset, &Module ) )
|
2004-02-06 03:12:30 +00:00
|
|
|
|
{
|
2006-04-08 20:22:08 +00:00
|
|
|
|
_ftprintf(stderr, _T("SymGetModuleInfo(): GetLastError = %lu\n"), gle );
|
2004-02-06 03:12:30 +00:00
|
|
|
|
}
|
2006-04-08 20:22:08 +00:00
|
|
|
|
} // we seem to have a valid PC
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_ftprintf(stderr, "%.8x ", StackFrame.AddrFrame.Offset);
|
|
|
|
|
_ftprintf(stderr, "%.8x ", StackFrame.AddrReturn.Offset);
|
|
|
|
|
_ftprintf(stderr, "%.8x ", StackFrame.Params[0]);
|
|
|
|
|
_ftprintf(stderr, "%.8x ", StackFrame.Params[1]);
|
|
|
|
|
_ftprintf(stderr, "%.8x ", StackFrame.Params[2]);
|
|
|
|
|
_ftprintf(stderr, "%s", Module.ModuleName);
|
|
|
|
|
_ftprintf(stderr, "!%s+", undName);
|
|
|
|
|
_ftprintf(stderr, "0x%x ", offsetFromLine);
|
|
|
|
|
|
|
|
|
|
if (Line.LineNumber)
|
|
|
|
|
_ftprintf(stderr, "(%s:%lu) ", Line.FileName, Line.LineNumber);
|
|
|
|
|
|
|
|
|
|
if (StackFrame.FuncTableEntry) {
|
|
|
|
|
// FPO Data
|
|
|
|
|
PFPO_DATA pFPO = (PFPO_DATA)StackFrame.FuncTableEntry;
|
|
|
|
|
switch(pFPO->cbFrame) {
|
|
|
|
|
case FRAME_NONFPO:
|
|
|
|
|
_ftprintf(stderr, "FPO: [non-Fpo] ");
|
|
|
|
|
break;
|
|
|
|
|
case FRAME_FPO:
|
|
|
|
|
_ftprintf(stderr, "FPO: [%d,%d,%d] ", pFPO->cdwParams, pFPO->cdwLocals, pFPO->cbRegs);
|
|
|
|
|
break;
|
|
|
|
|
case FRAME_TRAP:
|
|
|
|
|
_ftprintf(stderr, "FPO: [%d,%d] TrapFrame @ 0x%.8x ", pFPO->cdwParams, pFPO->cdwLocals, pFPO->ulOffStart);
|
|
|
|
|
break;
|
|
|
|
|
case FRAME_TSS:
|
|
|
|
|
_ftprintf(stderr, "FPO: TaskGate Segment: 0 ");
|
|
|
|
|
break;
|
2004-02-06 03:12:30 +00:00
|
|
|
|
}
|
2006-04-08 20:22:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_ftprintf(stderr, "\n");
|
|
|
|
|
fflush( stderr );
|
2004-02-06 03:12:30 +00:00
|
|
|
|
|
|
|
|
|
|
2006-04-08 20:22:08 +00:00
|
|
|
|
// Zero out params so we have fresh parameters through the next interation
|
|
|
|
|
StackFrame.Params[0] = NULL;
|
|
|
|
|
StackFrame.Params[1] = NULL;
|
|
|
|
|
StackFrame.Params[2] = NULL;
|
|
|
|
|
StackFrame.Params[3] = NULL;
|
2004-02-06 03:12:30 +00:00
|
|
|
|
|
|
|
|
|
|
2006-04-08 20:22:08 +00:00
|
|
|
|
// no return address means no deeper stackframe
|
|
|
|
|
if ( StackFrame.AddrReturn.Offset == 0 )
|
|
|
|
|
{
|
|
|
|
|
// avoid misunderstandings in the printf() following the loop
|
|
|
|
|
SetLastError( 0 );
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} // for ( frameNum )
|
|
|
|
|
|
2006-04-08 23:45:57 +00:00
|
|
|
|
switch(gle)
|
|
|
|
|
{
|
|
|
|
|
case ERROR_INVALID_ADDRESS:
|
|
|
|
|
_ftprintf(stderr, _T("\nStackWalk(): ERROR_INVALID_ADDRESS (%lu) - Possible stack corruption.\n"), gle );
|
|
|
|
|
break;
|
|
|
|
|
case ERROR_NOACCESS:
|
|
|
|
|
_ftprintf(stderr, _T("\nStackWalk(): ERROR_NOACCESS (%lu) - Possible stack corruption.\n"), gle );
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
_ftprintf(stderr, _T("\nStackWalk(): GetLastError = %lu\n"), gle );
|
|
|
|
|
break;
|
|
|
|
|
}
|
2006-04-08 20:22:08 +00:00
|
|
|
|
|
|
|
|
|
fflush(stderr);
|
|
|
|
|
|
|
|
|
|
LeaveCriticalSection(&g_csFileOpenClose);
|
|
|
|
|
}
|
2004-12-08 00:40:19 +00:00
|
|
|
|
|
2005-01-02 18:29:53 +00:00
|
|
|
|
const char *BOINC_RCSID_e8b4633192 = "$Id$";
|