mirror of
https://github.com/EQEmu/Server.git
synced 2026-04-02 08:12:25 +00:00
- License was intended to be GPLv3 per earlier commit of GPLv3 LICENSE FILE - This is confirmed by the inclusion of libraries that are incompatible with GPLv2 - This is also confirmed by KLS and the agreement of KLS's predecessors - Added GPLv3 license headers to the compilable source files - Removed Folly licensing in strings.h since the string functions do not match the Folly functions and are standard functions - this must have been left over from previous implementations - Removed individual contributor license headers since the project has been under the "developer" mantle for many years - Removed comments on files that were previously automatically generated since they've been manually modified multiple times and there are no automatic scripts referencing them (removed in 2023)
210 lines
6.7 KiB
C++
210 lines
6.7 KiB
C++
/* EQEmu: EQEmulator
|
|
|
|
Copyright (C) 2001-2026 EQEmu Development Team
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
/**********************************************************************
|
|
*
|
|
* StackWalker.h
|
|
*
|
|
*
|
|
* History:
|
|
* 2005-07-27 v1 - First public release on http://www.codeproject.com/
|
|
* (for additional changes see History in 'StackWalker.cpp'!
|
|
* 2013-01-26 - Modified by KimLS(KLS) for EQEmu's purposes
|
|
*
|
|
**********************************************************************/
|
|
#ifdef _WINDOWS
|
|
// #pragma once is supported starting with _MCS_VER 1000,
|
|
// so we need not to check the version (because we only support _MSC_VER >= 1100)!
|
|
#pragma once
|
|
|
|
#include "common/platform/win/include_windows.h"
|
|
|
|
// special defines for VC5/6 (if no actual PSDK is installed):
|
|
#if _MSC_VER < 1300
|
|
typedef unsigned __int64 DWORD64, *PDWORD64;
|
|
#if defined(_WIN64)
|
|
typedef unsigned __int64 SIZE_T, *PSIZE_T;
|
|
#else
|
|
typedef unsigned long SIZE_T, *PSIZE_T;
|
|
#endif
|
|
#endif // _MSC_VER < 1300
|
|
|
|
class StackWalkerInternal; // forward
|
|
class StackWalker
|
|
{
|
|
public:
|
|
typedef enum StackWalkOptions
|
|
{
|
|
// No addition info will be retrived
|
|
// (only the address is available)
|
|
RetrieveNone = 0,
|
|
|
|
// Try to get the symbol-name
|
|
RetrieveSymbol = 1,
|
|
|
|
// Try to get the line for this symbol
|
|
RetrieveLine = 2,
|
|
|
|
// Try to retrieve the module-infos
|
|
RetrieveModuleInfo = 4,
|
|
|
|
// Also retrieve the version for the DLL/EXE
|
|
RetrieveFileVersion = 8,
|
|
|
|
// Contains all the abouve
|
|
RetrieveVerbose = 0xF,
|
|
|
|
// Generate a "good" symbol-search-path
|
|
SymBuildPath = 0x10,
|
|
|
|
// Also use the public Microsoft-Symbol-Server
|
|
SymUseSymSrv = 0x20,
|
|
|
|
// Contains all the abouve "Sym"-options
|
|
SymAll = 0x30,
|
|
|
|
// Contains all options (default)
|
|
OptionsAll = 0x3F
|
|
} StackWalkOptions;
|
|
|
|
StackWalker(
|
|
int options = OptionsAll, // 'int' is by design, to combine the enum-flags
|
|
LPCSTR szSymPath = nullptr,
|
|
DWORD dwProcessId = GetCurrentProcessId(),
|
|
HANDLE hProcess = GetCurrentProcess()
|
|
);
|
|
StackWalker(DWORD dwProcessId, HANDLE hProcess);
|
|
virtual ~StackWalker();
|
|
|
|
typedef BOOL (__stdcall *PReadProcessMemoryRoutine)(
|
|
HANDLE hProcess,
|
|
DWORD64 qwBaseAddress,
|
|
PVOID lpBuffer,
|
|
DWORD nSize,
|
|
LPDWORD lpNumberOfBytesRead,
|
|
LPVOID pUserData // optional data, which was passed in "ShowCallstack"
|
|
);
|
|
|
|
BOOL LoadModules();
|
|
|
|
BOOL ShowCallstack(
|
|
HANDLE hThread = GetCurrentThread(),
|
|
const CONTEXT *context = nullptr,
|
|
PReadProcessMemoryRoutine readMemoryFunction = nullptr,
|
|
LPVOID pUserData = nullptr // optional to identify some data in the 'readMemoryFunction'-callback
|
|
);
|
|
|
|
#if _MSC_VER >= 1300
|
|
// due to some reasons, the "STACKWALK_MAX_NAMELEN" must be declared as "public"
|
|
// in older compilers in order to use it... starting with VC7 we can declare it as "protected"
|
|
protected:
|
|
#endif
|
|
enum { STACKWALK_MAX_NAMELEN = 1024 }; // max name length for found symbols
|
|
|
|
protected:
|
|
// Entry for each Callstack-Entry
|
|
typedef struct CallstackEntry
|
|
{
|
|
DWORD64 offset; // if 0, we have no valid entry
|
|
CHAR name[STACKWALK_MAX_NAMELEN];
|
|
CHAR undName[STACKWALK_MAX_NAMELEN];
|
|
CHAR undFullName[STACKWALK_MAX_NAMELEN];
|
|
DWORD64 offsetFromSmybol;
|
|
DWORD offsetFromLine;
|
|
DWORD lineNumber;
|
|
CHAR lineFileName[STACKWALK_MAX_NAMELEN];
|
|
DWORD symType;
|
|
LPCSTR symTypeString;
|
|
CHAR moduleName[STACKWALK_MAX_NAMELEN];
|
|
DWORD64 baseOfImage;
|
|
CHAR loadedImageName[STACKWALK_MAX_NAMELEN];
|
|
} CallstackEntry;
|
|
|
|
typedef enum CallstackEntryType {firstEntry, nextEntry, lastEntry};
|
|
|
|
virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName);
|
|
virtual void OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion);
|
|
virtual void OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry);
|
|
virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr);
|
|
virtual void OnOutput(LPCSTR szText);
|
|
|
|
StackWalkerInternal *m_sw;
|
|
HANDLE m_hProcess;
|
|
DWORD m_dwProcessId;
|
|
BOOL m_modulesLoaded;
|
|
LPSTR m_szSymPath;
|
|
|
|
int m_options;
|
|
|
|
static BOOL __stdcall myReadProcMem(HANDLE hProcess, DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead);
|
|
|
|
friend StackWalkerInternal;
|
|
};
|
|
|
|
|
|
// The "ugly" assembler-implementation is needed for systems before XP
|
|
// If you have a new PSDK and you only compile for XP and later, then you can use
|
|
// the "RtlCaptureContext"
|
|
// Currently there is no define which determines the PSDK-Version...
|
|
// So we just use the compiler-version (and assumes that the PSDK is
|
|
// the one which was installed by the VS-IDE)
|
|
|
|
// INFO: If you want, you can use the RtlCaptureContext if you only target XP and later...
|
|
// But I currently use it in x64/IA64 environments...
|
|
//#if defined(_M_IX86) && (_WIN32_WINNT <= 0x0500) && (_MSC_VER < 1400)
|
|
|
|
#if defined(_M_IX86)
|
|
#ifdef CURRENT_THREAD_VIA_EXCEPTION
|
|
// TODO: The following is not a "good" implementation,
|
|
// because the callstack is only valid in the "__except" block...
|
|
#define GET_CURRENT_CONTEXT(c, contextFlags) \
|
|
do { \
|
|
memset(&c, 0, sizeof(CONTEXT)); \
|
|
EXCEPTION_POINTERS *pExp = nullptr; \
|
|
__try { \
|
|
throw 0; \
|
|
} __except( ( (pExp = GetExceptionInformation()) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_EXECUTE_HANDLER)) {} \
|
|
if (pExp != nullptr) \
|
|
memcpy(&c, pExp->ContextRecord, sizeof(CONTEXT)); \
|
|
c.ContextFlags = contextFlags; \
|
|
} while(0);
|
|
#else
|
|
// The following should be enough for walking the callstack...
|
|
#define GET_CURRENT_CONTEXT(c, contextFlags) \
|
|
do { \
|
|
memset(&c, 0, sizeof(CONTEXT)); \
|
|
c.ContextFlags = contextFlags; \
|
|
__asm call x \
|
|
__asm x: pop eax \
|
|
__asm mov c.Eip, eax \
|
|
__asm mov c.Ebp, ebp \
|
|
__asm mov c.Esp, esp \
|
|
} while(0);
|
|
#endif
|
|
|
|
#else
|
|
|
|
// The following is defined for x86 (XP and higher), x64 and IA64:
|
|
#define GET_CURRENT_CONTEXT(c, contextFlags) \
|
|
do { \
|
|
memset(&c, 0, sizeof(CONTEXT)); \
|
|
c.ContextFlags = contextFlags; \
|
|
RtlCaptureContext(&c); \
|
|
} while(0);
|
|
#endif
|
|
#endif
|