My Project
D:/source/c++/Programme/sally/sally/sallyAPI/StackWalker.h
Go to the documentation of this file.
00001 /**********************************************************************
00002  * 
00003  * StackWalker.h
00004  *
00005  *
00006  * History:
00007  *  2005-07-27   v1    - First public release on http://www.codeproject.com/
00008  *  (for additional changes see History in 'StackWalker.cpp'!
00009  *
00010  **********************************************************************/
00011 // #pragma once is supported starting with _MCS_VER 1000, 
00012 // so we need not to check the version (because we only support _MSC_VER >= 1100)!
00013 #pragma once
00014 
00015 #include "Define.h"
00016 
00017 // special defines for VC5/6 (if no actual PSDK is installed):
00018 #if _MSC_VER < 1300
00019 typedef unsigned __int64 DWORD64, *PDWORD64;
00020 #if defined(_WIN64)
00021 typedef unsigned __int64 SIZE_T, *PSIZE_T;
00022 #else
00023 typedef unsigned long SIZE_T, *PSIZE_T;
00024 #endif
00025 #endif  // _MSC_VER < 1300
00026 
00027 class StackWalkerInternal;  // forward
00028 class DLL_API_SALLY StackWalker
00029 {
00030 public:
00031   typedef enum StackWalkOptions
00032   {
00033     // No addition info will be retrived 
00034     // (only the address is available)
00035     RetrieveNone = 0,
00036     
00037     // Try to get the symbol-name
00038     RetrieveSymbol = 1,
00039     
00040     // Try to get the line for this symbol
00041     RetrieveLine = 2,
00042     
00043     // Try to retrieve the module-infos
00044     RetrieveModuleInfo = 4,
00045     
00046     // Also retrieve the version for the DLL/EXE
00047     RetrieveFileVersion = 8,
00048     
00049     // Contains all the abouve
00050     RetrieveVerbose = 0xF,
00051     
00052     // Generate a "good" symbol-search-path
00053     SymBuildPath = 0x10,
00054     
00055     // Also use the public Microsoft-Symbol-Server
00056     SymUseSymSrv = 0x20,
00057     
00058     // Contains all the abouve "Sym"-options
00059     SymAll = 0x30,
00060     
00061     // Contains all options (default)
00062     OptionsAll = 0x3F
00063   } StackWalkOptions;
00064 
00065   StackWalker(
00066     int options = OptionsAll, // 'int' is by design, to combine the enum-flags
00067     LPCSTR szSymPath = NULL, 
00068     DWORD dwProcessId = GetCurrentProcessId(), 
00069     HANDLE hProcess = GetCurrentProcess()
00070     );
00071   StackWalker(DWORD dwProcessId, HANDLE hProcess);
00072   virtual ~StackWalker();
00073 
00074   typedef BOOL (__stdcall *PReadProcessMemoryRoutine)(
00075     HANDLE      hProcess,
00076     DWORD64     qwBaseAddress,
00077     PVOID       lpBuffer,
00078     DWORD       nSize,
00079     LPDWORD     lpNumberOfBytesRead,
00080     LPVOID      pUserData  // optional data, which was passed in "ShowCallstack"
00081     );
00082 
00083   BOOL LoadModules();
00084 
00085   BOOL ShowCallstack(
00086     HANDLE hThread = GetCurrentThread(), 
00087     const CONTEXT *context = NULL, 
00088     PReadProcessMemoryRoutine readMemoryFunction = NULL,
00089     LPVOID pUserData = NULL  // optional to identify some data in the 'readMemoryFunction'-callback
00090     );
00091 
00092 #if _MSC_VER >= 1300
00093 // due to some reasons, the "STACKWALK_MAX_NAMELEN" must be declared as "public" 
00094 // in older compilers in order to use it... starting with VC7 we can declare it as "protected"
00095 protected:
00096 #endif
00097         enum { STACKWALK_MAX_NAMELEN = 1024 }; // max name length for found symbols
00098 
00099 protected:
00100   // Entry for each Callstack-Entry
00101   typedef struct CallstackEntry
00102   {
00103     DWORD64 offset;  // if 0, we have no valid entry
00104     CHAR name[STACKWALK_MAX_NAMELEN];
00105     CHAR undName[STACKWALK_MAX_NAMELEN];
00106     CHAR undFullName[STACKWALK_MAX_NAMELEN];
00107     DWORD64 offsetFromSmybol;
00108     DWORD offsetFromLine;
00109     DWORD lineNumber;
00110     CHAR lineFileName[STACKWALK_MAX_NAMELEN];
00111     DWORD symType;
00112     LPCSTR symTypeString;
00113     CHAR moduleName[STACKWALK_MAX_NAMELEN];
00114     DWORD64 baseOfImage;
00115     CHAR loadedImageName[STACKWALK_MAX_NAMELEN];
00116   } CallstackEntry;
00117 
00118   typedef enum CallstackEntryType {firstEntry, nextEntry, lastEntry};
00119 
00120   virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName);
00121   virtual void OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion);
00122   virtual void OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry);
00123   virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr);
00124   virtual void OnOutput(LPCSTR szText);
00125 
00126   StackWalkerInternal *m_sw;
00127   HANDLE m_hProcess;
00128   DWORD m_dwProcessId;
00129   BOOL m_modulesLoaded;
00130   LPSTR m_szSymPath;
00131 
00132   int m_options;
00133 
00134   static BOOL __stdcall myReadProcMem(HANDLE hProcess, DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead);
00135 
00136   friend StackWalkerInternal;
00137 };
00138 
00139 
00140 // The "ugly" assembler-implementation is needed for systems before XP
00141 // If you have a new PSDK and you only compile for XP and later, then you can use 
00142 // the "RtlCaptureContext"
00143 // Currently there is no define which determines the PSDK-Version... 
00144 // So we just use the compiler-version (and assumes that the PSDK is 
00145 // the one which was installed by the VS-IDE)
00146 
00147 // INFO: If you want, you can use the RtlCaptureContext if you only target XP and later...
00148 //       But I currently use it in x64/IA64 environments...
00149 //#if defined(_M_IX86) && (_WIN32_WINNT <= 0x0500) && (_MSC_VER < 1400)
00150 
00151 #if defined(_M_IX86)
00152 #ifdef CURRENT_THREAD_VIA_EXCEPTION
00153 // TODO: The following is not a "good" implementation, 
00154 // because the callstack is only valid in the "__except" block...
00155 #define GET_CURRENT_CONTEXT(c, contextFlags) \
00156   do { \
00157     memset(&c, 0, sizeof(CONTEXT)); \
00158     EXCEPTION_POINTERS *pExp = NULL; \
00159     __try { \
00160       throw 0; \
00161     } __except( ( (pExp = GetExceptionInformation()) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_EXECUTE_HANDLER)) {} \
00162     if (pExp != NULL) \
00163       memcpy(&c, pExp->ContextRecord, sizeof(CONTEXT)); \
00164       c.ContextFlags = contextFlags; \
00165   } while(0);
00166 #else
00167 // The following should be enough for walking the callstack...
00168 #define GET_CURRENT_CONTEXT(c, contextFlags) \
00169   do { \
00170     memset(&c, 0, sizeof(CONTEXT)); \
00171     c.ContextFlags = contextFlags; \
00172     __asm    call x \
00173     __asm x: pop eax \
00174     __asm    mov c.Eip, eax \
00175     __asm    mov c.Ebp, ebp \
00176     __asm    mov c.Esp, esp \
00177   } while(0);
00178 #endif
00179 
00180 #else
00181 
00182 // The following is defined for x86 (XP and higher), x64 and IA64:
00183 #define GET_CURRENT_CONTEXT(c, contextFlags) \
00184   do { \
00185     memset(&c, 0, sizeof(CONTEXT)); \
00186     c.ContextFlags = contextFlags; \
00187     RtlCaptureContext(&c); \
00188 } while(0);
00189 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines