]> git.sesse.net Git - casparcg/blobdiff - common/compiler/vs/stack_walker.h
set svn:eol-style native on .h and .cpp files
[casparcg] / common / compiler / vs / stack_walker.h
index 0eb3384c79691c20c866b72145a2bc6e9b3e94dc..0e6a7017c5030aa7cdcc842cbe5cc3ed8bab1385 100644 (file)
-/**********************************************************************\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