00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #pragma once
00014
00015 #include <windows.h>
00016
00017
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;
00028 class StackWalker
00029 {
00030 public:
00031 typedef enum StackWalkOptions
00032 {
00033
00034
00035 RetrieveNone = 0,
00036
00037
00038 RetrieveSymbol = 1,
00039
00040
00041 RetrieveLine = 2,
00042
00043
00044 RetrieveModuleInfo = 4,
00045
00046
00047 RetrieveFileVersion = 8,
00048
00049
00050 RetrieveVerbose = 0xF,
00051
00052
00053 SymBuildPath = 0x10,
00054
00055
00056 SymUseSymSrv = 0x20,
00057
00058
00059 SymAll = 0x30,
00060
00061
00062 OptionsAll = 0x3F
00063 } StackWalkOptions;
00064
00065 StackWalker(
00066 int options = OptionsAll,
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
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
00090 );
00091
00092 #if _MSC_VER >= 1300
00093
00094
00095 protected:
00096 #endif
00097 enum { STACKWALK_MAX_NAMELEN = 1024 };
00098
00099 protected:
00100
00101 typedef struct CallstackEntry
00102 {
00103 DWORD64 offset;
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
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151 #if defined(_M_IX86)
00152 #ifdef CURRENT_THREAD_VIA_EXCEPTION
00153
00154
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
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
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