-/**********************************************************************\r
- * \r
- * stack_walker.h\r
- *\r
- *\r
- * History:\r
- * 2005-07-27 v1 - First public release on http://www.codeproject.com/\r
- * (for additional changes see History in 'stack_walker.cpp'!\r
- *\r
- **********************************************************************/\r
-// #pragma once is supported starting with _MCS_VER 1000, \r
-// so we need not to check the version (because we only support _MSC_VER >= 1100)!\r
-#pragma once\r
-\r
-#include <windows.h>\r
-\r
-// special defines for VC5/6 (if no actual PSDK is installed):\r
-#if _MSC_VER < 1300\r
-typedef unsigned __int64 DWORD64, *PDWORD64;\r
-#if defined(_WIN64)\r
-typedef unsigned __int64 SIZE_T, *PSIZE_T;\r
-#else\r
-typedef unsigned long SIZE_T, *PSIZE_T;\r
-#endif\r
-#endif // _MSC_VER < 1300\r
-\r
-class stack_walkerInternal; // forward\r
-class stack_walker\r
-{\r
-public:\r
- typedef enum StackWalkOptions\r
- {\r
- // No addition info will be retrived \r
- // (only the address is available)\r
- RetrieveNone = 0,\r
- \r
- // Try to get the symbol-name\r
- RetrieveSymbol = 1,\r
- \r
- // Try to get the line for this symbol\r
- RetrieveLine = 2,\r
- \r
- // Try to retrieve the module-infos\r
- RetrieveModuleInfo = 4,\r
- \r
- // Also retrieve the version for the DLL/EXE\r
- RetrieveFileVersion = 8,\r
- \r
- // Contains all the abouve\r
- RetrieveVerbose = 0xF,\r
- \r
- // Generate a "good" symbol-search-path\r
- SymBuildPath = 0x10,\r
- \r
- // Also use the public Microsoft-Symbol-Server\r
- SymUseSymSrv = 0x20,\r
- \r
- // Contains all the abouve "Sym"-options\r
- SymAll = 0x30,\r
- \r
- // Contains all options (default)\r
- OptionsAll = 0x3F\r
- } StackWalkOptions;\r
-\r
- stack_walker(\r
- int options = OptionsAll, // 'int' is by design, to combine the enum-flags\r
- LPCSTR szSymPath = NULL, \r
- DWORD dwProcessId = GetCurrentProcessId(), \r
- HANDLE hProcess = GetCurrentProcess()\r
- );\r
- stack_walker(DWORD dwProcessId, HANDLE hProcess);\r
- virtual ~stack_walker();\r
-\r
- typedef BOOL (__stdcall *PReadProcessMemoryRoutine)(\r
- HANDLE hProcess,\r
- DWORD64 qwBaseAddress,\r
- PVOID lpBuffer,\r
- DWORD nSize,\r
- LPDWORD lpNumberOfBytesRead,\r
- LPVOID pUserData // optional data, which was passed in "ShowCallstack"\r
- );\r
-\r
- BOOL LoadModules();\r
-\r
- BOOL ShowCallstack(\r
- HANDLE hThread = GetCurrentThread(), \r
- const CONTEXT *context = NULL, \r
- PReadProcessMemoryRoutine readMemoryFunction = NULL,\r
- LPVOID pUserData = NULL // optional to identify some data in the 'readMemoryFunction'-callback\r
- );\r
-\r
-#if _MSC_VER >= 1300\r
-// due to some reasons, the "STACKWALK_MAX_NAMELEN" must be declared as "public" \r
-// in older compilers in order to use it... starting with VC7 we can declare it as "protected"\r
-protected:\r
-#endif\r
- enum { STACKWALK_MAX_NAMELEN = 1024 }; // max name length for found symbols\r
-\r
-protected:\r
- // Entry for each Callstack-Entry\r
- typedef struct CallstackEntry\r
- {\r
- DWORD64 offset; // if 0, we have no valid entry\r
- CHAR name[STACKWALK_MAX_NAMELEN];\r
- CHAR undName[STACKWALK_MAX_NAMELEN];\r
- CHAR undFullName[STACKWALK_MAX_NAMELEN];\r
- DWORD64 offsetFromSmybol;\r
- DWORD offsetFromLine;\r
- DWORD lineNumber;\r
- CHAR lineFileName[STACKWALK_MAX_NAMELEN];\r
- DWORD symType;\r
- LPCSTR symTypeString;\r
- CHAR moduleName[STACKWALK_MAX_NAMELEN];\r
- DWORD64 baseOfImage;\r
- CHAR loadedImageName[STACKWALK_MAX_NAMELEN];\r
- } CallstackEntry;\r
-\r
- typedef enum CallstackEntryType {firstEntry, nextEntry, lastEntry};\r
-\r
- virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName);\r
- virtual void OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion);\r
- virtual void OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry);\r
- virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr);\r
- virtual void OnOutput(LPCSTR szText);\r
-\r
- stack_walkerInternal *m_sw;\r
- HANDLE m_hProcess;\r
- DWORD m_dwProcessId;\r
- BOOL m_modulesLoaded;\r
- LPSTR m_szSymPath;\r
-\r
- int m_options;\r
-\r
- static BOOL __stdcall myReadProcMem(HANDLE hProcess, DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead);\r
-\r
- friend stack_walkerInternal;\r
-};\r
-\r
-\r
-// The "ugly" assembler-implementation is needed for systems before XP\r
-// If you have a new PSDK and you only compile for XP and later, then you can use \r
-// the "RtlCaptureContext"\r
-// Currently there is no define which determines the PSDK-Version... \r
-// So we just use the compiler-version (and assumes that the PSDK is \r
-// the one which was installed by the VS-IDE)\r
-\r
-// INFO: If you want, you can use the RtlCaptureContext if you only target XP and later...\r
-// But I currently use it in x64/IA64 environments...\r
-//#if defined(_M_IX86) && (_WIN32_WINNT <= 0x0500) && (_MSC_VER < 1400)\r
-\r
-#if defined(_M_IX86)\r
-#ifdef CURRENT_THREAD_VIA_EXCEPTION\r
-// TODO: The following is not a "good" implementation, \r
-// because the callstack is only valid in the "__except" block...\r
-#define GET_CURRENT_CONTEXT(c, contextFlags) \\r
- do { \\r
- memset(&c, 0, sizeof(CONTEXT)); \\r
- EXCEPTION_POINTERS *pExp = NULL; \\r
- __try { \\r
- throw 0; \\r
- } __except( ( (pExp = GetExceptionInformation()) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_EXECUTE_HANDLER)) {} \\r
- if (pExp != NULL) \\r
- memcpy(&c, pExp->ContextRecord, sizeof(CONTEXT)); \\r
- c.ContextFlags = contextFlags; \\r
- } while(0);\r
-#else\r
-// The following should be enough for walking the callstack...\r
-#define GET_CURRENT_CONTEXT(c, contextFlags) \\r
- do { \\r
- memset(&c, 0, sizeof(CONTEXT)); \\r
- c.ContextFlags = contextFlags; \\r
- __asm call x \\r
- __asm x: pop eax \\r
- __asm mov c.Eip, eax \\r
- __asm mov c.Ebp, ebp \\r
- __asm mov c.Esp, esp \\r
- } while(0);\r
-#endif\r
-\r
-#else\r
-\r
-// The following is defined for x86 (XP and higher), x64 and IA64:\r
-#define GET_CURRENT_CONTEXT(c, contextFlags) \\r
- do { \\r
- memset(&c, 0, sizeof(CONTEXT)); \\r
- c.ContextFlags = contextFlags; \\r
- RtlCaptureContext(&c); \\r
-} while(0);\r
-#endif\r
+/**********************************************************************
+ *
+ * stack_walker.h
+ *
+ *
+ * History:
+ * 2005-07-27 v1 - First public release on http://www.codeproject.com/
+ * (for additional changes see History in 'stack_walker.cpp'!
+ *
+ **********************************************************************/
+// #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 stack_walkerInternal; // forward
+class stack_walker
+{
+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;
+
+ stack_walker(
+ int options = OptionsAll, // 'int' is by design, to combine the enum-flags
+ LPCSTR szSymPath = NULL,
+ DWORD dwProcessId = GetCurrentProcessId(),
+ HANDLE hProcess = GetCurrentProcess()
+ );
+ stack_walker(DWORD dwProcessId, HANDLE hProcess);
+ virtual ~stack_walker();
+
+ 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);
+
+ stack_walkerInternal *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 stack_walkerInternal;
+};
+
+
+// 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