| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350 |
- /**********************************************************************
- *
- * StackWalker.h
- *
- *
- *
- * LICENSE (http://www.opensource.org/licenses/bsd-license.php)
- *
- * Copyright (c) 2005-2009, Jochen Kalmbach
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * Neither the name of Jochen Kalmbach nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * **********************************************************************/
- // #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
- // If VC7 and later, then use the shipped 'dbghelp.h'-file
- #pragma pack(push,8)
- #if _MSC_VER >= 1300
- #include <dbghelp.h>
- #else
- // inline the important dbghelp.h-declarations...
- typedef enum {
- SymNone = 0,
- SymCoff,
- SymCv,
- SymPdb,
- SymExport,
- SymDeferred,
- SymSym,
- SymDia,
- SymVirtual,
- NumSymTypes
- } SYM_TYPE;
- typedef struct _IMAGEHLP_LINE64 {
- DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_LINE64)
- PVOID Key; // internal
- DWORD LineNumber; // line number in file
- PCHAR FileName; // full filename
- DWORD64 Address; // first instruction of line
- } IMAGEHLP_LINE64, *PIMAGEHLP_LINE64;
- typedef struct _IMAGEHLP_MODULE64 {
- DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64)
- DWORD64 BaseOfImage; // base load address of module
- DWORD ImageSize; // virtual size of the loaded module
- DWORD TimeDateStamp; // date/time stamp from pe header
- DWORD CheckSum; // checksum from the pe header
- DWORD NumSyms; // number of symbols in the symbol table
- SYM_TYPE SymType; // type of symbols loaded
- CHAR ModuleName[32]; // module name
- CHAR ImageName[256]; // image name
- CHAR LoadedImageName[256]; // symbol file name
- } IMAGEHLP_MODULE64, *PIMAGEHLP_MODULE64;
- typedef struct _IMAGEHLP_SYMBOL64 {
- DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_SYMBOL64)
- DWORD64 Address; // virtual address including dll base address
- DWORD Size; // estimated size of symbol, can be zero
- DWORD Flags; // info about the symbols, see the SYMF defines
- DWORD MaxNameLength; // maximum size of symbol name in 'Name'
- CHAR Name[1]; // symbol name (null terminated string)
- } IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64;
- typedef enum {
- AddrMode1616,
- AddrMode1632,
- AddrModeReal,
- AddrModeFlat
- } ADDRESS_MODE;
- typedef struct _tagADDRESS64 {
- DWORD64 Offset;
- WORD Segment;
- ADDRESS_MODE Mode;
- } ADDRESS64, *LPADDRESS64;
- typedef struct _KDHELP64 {
- DWORD64 Thread;
- DWORD ThCallbackStack;
- DWORD ThCallbackBStore;
- DWORD NextCallback;
- DWORD FramePointer;
- DWORD64 KiCallUserMode;
- DWORD64 KeUserCallbackDispatcher;
- DWORD64 SystemRangeStart;
- DWORD64 Reserved[8];
- } KDHELP64, *PKDHELP64;
- typedef struct _tagSTACKFRAME64 {
- ADDRESS64 AddrPC; // program counter
- ADDRESS64 AddrReturn; // return address
- ADDRESS64 AddrFrame; // frame pointer
- ADDRESS64 AddrStack; // stack pointer
- ADDRESS64 AddrBStore; // backing store pointer
- PVOID FuncTableEntry; // pointer to pdata/fpo or NULL
- DWORD64 Params[4]; // possible arguments to the function
- BOOL Far; // WOW far call
- BOOL Virtual; // is this a virtual frame?
- DWORD64 Reserved[3];
- KDHELP64 KdHelp;
- } STACKFRAME64, *LPSTACKFRAME64;
- typedef
- BOOL
- (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)(
- HANDLE hProcess,
- DWORD64 qwBaseAddress,
- PVOID lpBuffer,
- DWORD nSize,
- LPDWORD lpNumberOfBytesRead
- );
- typedef
- PVOID
- (__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)(
- HANDLE hProcess,
- DWORD64 AddrBase
- );
- typedef
- DWORD64
- (__stdcall *PGET_MODULE_BASE_ROUTINE64)(
- HANDLE hProcess,
- DWORD64 Address
- );
- typedef
- DWORD64
- (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)(
- HANDLE hProcess,
- HANDLE hThread,
- LPADDRESS64 lpaddr
- );
- #define SYMOPT_CASE_INSENSITIVE 0x00000001
- #define SYMOPT_UNDNAME 0x00000002
- #define SYMOPT_DEFERRED_LOADS 0x00000004
- #define SYMOPT_NO_CPP 0x00000008
- #define SYMOPT_LOAD_LINES 0x00000010
- #define SYMOPT_OMAP_FIND_NEAREST 0x00000020
- #define SYMOPT_LOAD_ANYTHING 0x00000040
- #define SYMOPT_IGNORE_CVREC 0x00000080
- #define SYMOPT_NO_UNQUALIFIED_LOADS 0x00000100
- #define SYMOPT_FAIL_CRITICAL_ERRORS 0x00000200
- #define SYMOPT_EXACT_SYMBOLS 0x00000400
- #define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS 0x00000800
- #define SYMOPT_IGNORE_NT_SYMPATH 0x00001000
- #define SYMOPT_INCLUDE_32BIT_MODULES 0x00002000
- #define SYMOPT_PUBLICS_ONLY 0x00004000
- #define SYMOPT_NO_PUBLICS 0x00008000
- #define SYMOPT_AUTO_PUBLICS 0x00010000
- #define SYMOPT_NO_IMAGE_SEARCH 0x00020000
- #define SYMOPT_SECURE 0x00040000
- #define SYMOPT_DEBUG 0x80000000
- #define UNDNAME_COMPLETE (0x0000) // Enable full undecoration
- #define UNDNAME_NAME_ONLY (0x1000) // Crack only the name for primary declaration;
- #endif // _MSC_VER < 1300
- #pragma pack(pop)
- class StackWalkerInternal; // forward
- class StackWalker
- {
- public:
- bool fast;
- 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;
- StackWalker(
- int options = OptionsAll, // 'int' is by design, to combine the enum-flags
- LPCSTR szSymPath = NULL,
- DWORD dwProcessId = GetCurrentProcessId(),
- HANDLE hProcess = GetCurrentProcess()
- );
- StackWalker(DWORD dwProcessId, HANDLE hProcess);
- virtual ~StackWalker();
- 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 = 512 }; // 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;
- 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);
- StackWalkerInternal *m_sw;
- HANDLE m_hProcess;
- DWORD m_dwProcessId;
- BOOL m_modulesLoaded;
- LPSTR m_szSymPath;
- Byte pSym_temp[SIZEI(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN];
- int m_options;
- int m_MaxRecursionCount;
- static BOOL __stdcall myReadProcMem(HANDLE hProcess, DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead);
- friend StackWalkerInternal;
- }; // class StackWalker
- // 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
|