diff options
Diffstat (limited to 'source/StackWalker.h')
-rw-r--r-- | source/StackWalker.h | 428 |
1 files changed, 214 insertions, 214 deletions
diff --git a/source/StackWalker.h b/source/StackWalker.h index 212e02a9f..bf47d3726 100644 --- a/source/StackWalker.h +++ b/source/StackWalker.h @@ -1,214 +1,214 @@ -/**********************************************************************
- *
- * StackWalker.h
- *
- *
- *
- * LICENSE (http://www.opensource.org/licenses/bsd-license.php)
- *
- * Copyright (c) 2005-2010, Jochen Kalmbach
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * Neither the name of Jochen Kalmbach nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * **********************************************************************/
-// #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 <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 = NULL,
- 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 = NULL,
- PReadProcessMemoryRoutine readMemoryFunction = NULL,
- LPVOID pUserData = NULL // 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;
- int m_MaxRecursionCount;
-
- 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 = NULL; \
- __try { \
- throw 0; \
- } __except( ( (pExp = GetExceptionInformation()) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_EXECUTE_HANDLER)) {} \
- if (pExp != NULL) \
- 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
+/********************************************************************** + * + * StackWalker.h + * + * + * + * LICENSE (http://www.opensource.org/licenses/bsd-license.php) + * + * Copyright (c) 2005-2010, Jochen Kalmbach + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of Jochen Kalmbach nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * **********************************************************************/ +// #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 <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 = NULL, + 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 = NULL, + PReadProcessMemoryRoutine readMemoryFunction = NULL, + LPVOID pUserData = NULL // 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; + int m_MaxRecursionCount; + + 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 = NULL; \ + __try { \ + throw 0; \ + } __except( ( (pExp = GetExceptionInformation()) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_EXECUTE_HANDLER)) {} \ + if (pExp != NULL) \ + 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 |