[d9b6a1c] | 1 | #ifndef __STACKWALKER_H__
|
---|
| 2 | #define __STACKWALKER_H__
|
---|
| 3 |
|
---|
| 4 | #if defined(_MSC_VER)
|
---|
| 5 |
|
---|
| 6 | /**********************************************************************
|
---|
| 7 | *
|
---|
| 8 | * StackWalker.h
|
---|
| 9 | *
|
---|
| 10 | *
|
---|
| 11 | *
|
---|
| 12 | * LICENSE (http://www.opensource.org/licenses/bsd-license.php)
|
---|
| 13 | *
|
---|
| 14 | * Copyright (c) 2005-2009, Jochen Kalmbach
|
---|
| 15 | * All rights reserved.
|
---|
| 16 | *
|
---|
| 17 | * Redistribution and use in source and binary forms, with or without modification,
|
---|
| 18 | * are permitted provided that the following conditions are met:
|
---|
| 19 | *
|
---|
| 20 | * Redistributions of source code must retain the above copyright notice,
|
---|
| 21 | * this list of conditions and the following disclaimer.
|
---|
| 22 | * Redistributions in binary form must reproduce the above copyright notice,
|
---|
| 23 | * this list of conditions and the following disclaimer in the documentation
|
---|
| 24 | * and/or other materials provided with the distribution.
|
---|
| 25 | * Neither the name of Jochen Kalmbach nor the names of its contributors may be
|
---|
| 26 | * used to endorse or promote products derived from this software without
|
---|
| 27 | * specific prior written permission.
|
---|
| 28 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
---|
| 29 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
---|
| 30 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
---|
| 31 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
---|
| 32 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
---|
| 33 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
---|
| 34 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
---|
| 35 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
---|
| 36 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
---|
| 37 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
---|
| 38 | *
|
---|
| 39 | * **********************************************************************/
|
---|
| 40 | // #pragma once is supported starting with _MSC_VER 1000,
|
---|
| 41 | // so we need not to check the version (because we only support _MSC_VER >= 1100)!
|
---|
| 42 | #pragma once
|
---|
| 43 |
|
---|
| 44 | #include <windows.h>
|
---|
| 45 |
|
---|
| 46 | #if _MSC_VER >= 1900
|
---|
| 47 | #pragma warning(disable : 4091)
|
---|
| 48 | #endif
|
---|
| 49 |
|
---|
| 50 | // special defines for VC5/6 (if no actual PSDK is installed):
|
---|
| 51 | #if _MSC_VER < 1300
|
---|
| 52 | typedef unsigned __int64 DWORD64, *PDWORD64;
|
---|
| 53 | #if defined(_WIN64)
|
---|
| 54 | typedef unsigned __int64 SIZE_T, *PSIZE_T;
|
---|
| 55 | #else
|
---|
| 56 | typedef unsigned long SIZE_T, *PSIZE_T;
|
---|
| 57 | #endif
|
---|
| 58 | #endif // _MSC_VER < 1300
|
---|
| 59 |
|
---|
| 60 | class StackWalkerInternal; // forward
|
---|
| 61 | class StackWalker
|
---|
| 62 | {
|
---|
| 63 | public:
|
---|
| 64 | typedef enum StackWalkOptions
|
---|
| 65 | {
|
---|
| 66 | // No addition info will be retrieved
|
---|
| 67 | // (only the address is available)
|
---|
| 68 | RetrieveNone = 0,
|
---|
| 69 |
|
---|
| 70 | // Try to get the symbol-name
|
---|
| 71 | RetrieveSymbol = 1,
|
---|
| 72 |
|
---|
| 73 | // Try to get the line for this symbol
|
---|
| 74 | RetrieveLine = 2,
|
---|
| 75 |
|
---|
| 76 | // Try to retrieve the module-infos
|
---|
| 77 | RetrieveModuleInfo = 4,
|
---|
| 78 |
|
---|
| 79 | // Also retrieve the version for the DLL/EXE
|
---|
| 80 | RetrieveFileVersion = 8,
|
---|
| 81 |
|
---|
| 82 | // Contains all the above
|
---|
| 83 | RetrieveVerbose = 0xF,
|
---|
| 84 |
|
---|
| 85 | // Generate a "good" symbol-search-path
|
---|
| 86 | SymBuildPath = 0x10,
|
---|
| 87 |
|
---|
| 88 | // Also use the public Microsoft-Symbol-Server
|
---|
| 89 | SymUseSymSrv = 0x20,
|
---|
| 90 |
|
---|
| 91 | // Contains all the above "Sym"-options
|
---|
| 92 | SymAll = 0x30,
|
---|
| 93 |
|
---|
| 94 | // Contains all options (default)
|
---|
| 95 | OptionsAll = 0x3F
|
---|
| 96 | } StackWalkOptions;
|
---|
| 97 |
|
---|
| 98 | StackWalker(int options = OptionsAll, // 'int' is by design, to combine the enum-flags
|
---|
| 99 | LPCSTR szSymPath = NULL,
|
---|
| 100 | DWORD dwProcessId = GetCurrentProcessId(),
|
---|
| 101 | HANDLE hProcess = GetCurrentProcess());
|
---|
| 102 | StackWalker(DWORD dwProcessId, HANDLE hProcess);
|
---|
| 103 | virtual ~StackWalker();
|
---|
| 104 |
|
---|
| 105 | typedef BOOL(__stdcall* PReadProcessMemoryRoutine)(
|
---|
| 106 | HANDLE hProcess,
|
---|
| 107 | DWORD64 qwBaseAddress,
|
---|
| 108 | PVOID lpBuffer,
|
---|
| 109 | DWORD nSize,
|
---|
| 110 | LPDWORD lpNumberOfBytesRead,
|
---|
| 111 | LPVOID pUserData // optional data, which was passed in "ShowCallstack"
|
---|
| 112 | );
|
---|
| 113 |
|
---|
| 114 | BOOL LoadModules();
|
---|
| 115 |
|
---|
| 116 | BOOL ShowCallstack(
|
---|
| 117 | HANDLE hThread = GetCurrentThread(),
|
---|
| 118 | const CONTEXT* context = NULL,
|
---|
| 119 | PReadProcessMemoryRoutine readMemoryFunction = NULL,
|
---|
| 120 | LPVOID pUserData = NULL // optional to identify some data in the 'readMemoryFunction'-callback
|
---|
| 121 | );
|
---|
| 122 |
|
---|
| 123 | BOOL ShowObject(LPVOID pObject);
|
---|
| 124 |
|
---|
| 125 | #if _MSC_VER >= 1300
|
---|
| 126 | // due to some reasons, the "STACKWALK_MAX_NAMELEN" must be declared as "public"
|
---|
| 127 | // in older compilers in order to use it... starting with VC7 we can declare it as "protected"
|
---|
| 128 | protected:
|
---|
| 129 | #endif
|
---|
| 130 | enum
|
---|
| 131 | {
|
---|
| 132 | STACKWALK_MAX_NAMELEN = 1024
|
---|
| 133 | }; // max name length for found symbols
|
---|
| 134 |
|
---|
| 135 | protected:
|
---|
| 136 | // Entry for each Callstack-Entry
|
---|
| 137 | typedef struct CallstackEntry
|
---|
| 138 | {
|
---|
| 139 | DWORD64 offset; // if 0, we have no valid entry
|
---|
| 140 | CHAR name[STACKWALK_MAX_NAMELEN];
|
---|
| 141 | CHAR undName[STACKWALK_MAX_NAMELEN];
|
---|
| 142 | CHAR undFullName[STACKWALK_MAX_NAMELEN];
|
---|
| 143 | DWORD64 offsetFromSmybol;
|
---|
| 144 | DWORD offsetFromLine;
|
---|
| 145 | DWORD lineNumber;
|
---|
| 146 | CHAR lineFileName[STACKWALK_MAX_NAMELEN];
|
---|
| 147 | DWORD symType;
|
---|
| 148 | LPCSTR symTypeString;
|
---|
| 149 | CHAR moduleName[STACKWALK_MAX_NAMELEN];
|
---|
| 150 | DWORD64 baseOfImage;
|
---|
| 151 | CHAR loadedImageName[STACKWALK_MAX_NAMELEN];
|
---|
| 152 | } CallstackEntry;
|
---|
| 153 |
|
---|
| 154 | typedef enum CallstackEntryType
|
---|
| 155 | {
|
---|
| 156 | firstEntry,
|
---|
| 157 | nextEntry,
|
---|
| 158 | lastEntry
|
---|
| 159 | } CallstackEntryType;
|
---|
| 160 |
|
---|
| 161 | virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName);
|
---|
| 162 | virtual void OnLoadModule(LPCSTR img,
|
---|
| 163 | LPCSTR mod,
|
---|
| 164 | DWORD64 baseAddr,
|
---|
| 165 | DWORD size,
|
---|
| 166 | DWORD result,
|
---|
| 167 | LPCSTR symType,
|
---|
| 168 | LPCSTR pdbName,
|
---|
| 169 | ULONGLONG fileVersion);
|
---|
| 170 | virtual void OnCallstackEntry(CallstackEntryType eType, CallstackEntry& entry);
|
---|
| 171 | virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr);
|
---|
| 172 | virtual void OnOutput(LPCSTR szText);
|
---|
| 173 |
|
---|
| 174 | StackWalkerInternal* m_sw;
|
---|
| 175 | HANDLE m_hProcess;
|
---|
| 176 | DWORD m_dwProcessId;
|
---|
| 177 | BOOL m_modulesLoaded;
|
---|
| 178 | LPSTR m_szSymPath;
|
---|
| 179 |
|
---|
| 180 | int m_options;
|
---|
| 181 | int m_MaxRecursionCount;
|
---|
| 182 |
|
---|
| 183 | static BOOL __stdcall myReadProcMem(HANDLE hProcess,
|
---|
| 184 | DWORD64 qwBaseAddress,
|
---|
| 185 | PVOID lpBuffer,
|
---|
| 186 | DWORD nSize,
|
---|
| 187 | LPDWORD lpNumberOfBytesRead);
|
---|
| 188 |
|
---|
| 189 | friend StackWalkerInternal;
|
---|
| 190 | }; // class StackWalker
|
---|
| 191 |
|
---|
| 192 | // The "ugly" assembler-implementation is needed for systems before XP
|
---|
| 193 | // If you have a new PSDK and you only compile for XP and later, then you can use
|
---|
| 194 | // the "RtlCaptureContext"
|
---|
| 195 | // Currently there is no define which determines the PSDK-Version...
|
---|
| 196 | // So we just use the compiler-version (and assumes that the PSDK is
|
---|
| 197 | // the one which was installed by the VS-IDE)
|
---|
| 198 |
|
---|
| 199 | // INFO: If you want, you can use the RtlCaptureContext if you only target XP and later...
|
---|
| 200 | // But I currently use it in x64/IA64 environments...
|
---|
| 201 | //#if defined(_M_IX86) && (_WIN32_WINNT <= 0x0500) && (_MSC_VER < 1400)
|
---|
| 202 |
|
---|
| 203 | #if defined(_M_IX86)
|
---|
| 204 | #ifdef CURRENT_THREAD_VIA_EXCEPTION
|
---|
| 205 | // TODO: The following is not a "good" implementation,
|
---|
| 206 | // because the callstack is only valid in the "__except" block...
|
---|
| 207 | #define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \
|
---|
| 208 | do \
|
---|
| 209 | { \
|
---|
| 210 | memset(&c, 0, sizeof(CONTEXT)); \
|
---|
| 211 | EXCEPTION_POINTERS* pExp = NULL; \
|
---|
| 212 | __try \
|
---|
| 213 | { \
|
---|
| 214 | throw 0; \
|
---|
| 215 | } \
|
---|
| 216 | __except (((pExp = GetExceptionInformation()) ? EXCEPTION_EXECUTE_HANDLER \
|
---|
| 217 | : EXCEPTION_EXECUTE_HANDLER)) \
|
---|
| 218 | { \
|
---|
| 219 | } \
|
---|
| 220 | if (pExp != NULL) \
|
---|
| 221 | memcpy(&c, pExp->ContextRecord, sizeof(CONTEXT)); \
|
---|
| 222 | c.ContextFlags = contextFlags; \
|
---|
| 223 | } while (0);
|
---|
| 224 | #else
|
---|
| 225 | // clang-format off
|
---|
| 226 | // The following should be enough for walking the callstack...
|
---|
| 227 | #define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \
|
---|
| 228 | do \
|
---|
| 229 | { \
|
---|
| 230 | memset(&c, 0, sizeof(CONTEXT)); \
|
---|
| 231 | c.ContextFlags = contextFlags; \
|
---|
| 232 | __asm call x \
|
---|
| 233 | __asm x: pop eax \
|
---|
| 234 | __asm mov c.Eip, eax \
|
---|
| 235 | __asm mov c.Ebp, ebp \
|
---|
| 236 | __asm mov c.Esp, esp \
|
---|
| 237 | } while (0)
|
---|
| 238 | // clang-format on
|
---|
| 239 | #endif
|
---|
| 240 |
|
---|
| 241 | #else
|
---|
| 242 |
|
---|
| 243 | // The following is defined for x86 (XP and higher), x64 and IA64:
|
---|
| 244 | #define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \
|
---|
| 245 | do \
|
---|
| 246 | { \
|
---|
| 247 | memset(&c, 0, sizeof(CONTEXT)); \
|
---|
| 248 | c.ContextFlags = contextFlags; \
|
---|
| 249 | RtlCaptureContext(&c); \
|
---|
| 250 | } while (0);
|
---|
| 251 | #endif
|
---|
| 252 |
|
---|
| 253 | #endif //defined(_MSC_VER)
|
---|
| 254 |
|
---|
| 255 | #endif // __STACKWALKER_H__
|
---|