之前一直找这个找不到,从git上找到了StackWalker类分享。
StackWalker.cpp
- #include "StackWalker.h"
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <tchar.h>
- #include <windows.h>
- #pragma comment(lib, "version.lib") // for "VerQueryValue"
- #pragma warning(disable : 4826)
-
-
- // 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);
-
- // clang-format off
- #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;
- // clang-format on
-
- #endif // _MSC_VER < 1300
- #pragma pack(pop)
-
- // Some missing defines (for VC5/6):
- #ifndef INVALID_FILE_ATTRIBUTES
- #define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
- #endif
-
- // secure-CRT_functions are only available starting with VC8
- #if _MSC_VER < 1400
- #define strcpy_s(dst, len, src) strcpy(dst, src)
- #define strncpy_s(dst, len, src, maxLen) strncpy(dst, len, src)
- #define strcat_s(dst, len, src) strcat(dst, src)
- #define _snprintf_s _snprintf
- #define _tcscat_s _tcscat
- #endif
-
- static void MyStrCpy(char* szDest, size_t nMaxDestSize, const char* szSrc)
- {
- if (nMaxDestSize <= 0)
- return;
- strncpy_s(szDest, nMaxDestSize, szSrc, _TRUNCATE);
- // INFO: _TRUNCATE will ensure that it is null-terminated;
- // but with older compilers (<1400) it uses "strncpy" and this does not!)
- szDest[nMaxDestSize - 1] = 0;
- } // MyStrCpy
-
- // Normally it should be enough to use 'CONTEXT_FULL' (better would be 'CONTEXT_ALL')
- #define USED_CONTEXT_FLAGS CONTEXT_FULL
-
- class StackWalkerInternal
- {
- public:
- StackWalkerInternal(StackWalker* parent, HANDLE hProcess)
- {
- m_parent = parent;
- m_hDbhHelp = NULL;
- pSC = NULL;
- m_hProcess = hProcess;
- m_szSymPath = NULL;
- pSFTA = NULL;
- pSGLFA = NULL;
- pSGMB = NULL;
- pSGMI = NULL;
- pSGO = NULL;
- pSGSFA = NULL;
- pSI = NULL;
- pSLM = NULL;
- pSSO = NULL;
- pSW = NULL;
- pUDSN = NULL;
- pSGSP = NULL;
- }
- ~StackWalkerInternal()
- {
- if (pSC != NULL)
- pSC(m_hProcess); // SymCleanup
- if (m_hDbhHelp != NULL)
- FreeLibrary(m_hDbhHelp);
- m_hDbhHelp = NULL;
- m_parent = NULL;
- if (m_szSymPath != NULL)
- free(m_szSymPath);
- m_szSymPath = NULL;
- }
- BOOL Init(LPCSTR szSymPath)
- {
- if (m_parent == NULL)
- return FALSE;
- // Dynamically load the Entry-Points for dbghelp.dll:
- // First try to load the newest one from
- TCHAR szTemp[4096];
- // But before we do this, we first check if the ".local" file exists
- if (GetModuleFileName(NULL, szTemp, 4096) > 0)
- {
- _tcscat_s(szTemp, _T(".local"));
- if (GetFileAttributes(szTemp) == INVALID_FILE_ATTRIBUTES)
- {
- // ".local" file does not exist, so we can try to load the dbghelp.dll from the "Debugging Tools for Windows"
- // Ok, first try the new path according to the architecture:
- #ifdef _M_IX86
- if ((m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0))
- {
- _tcscat_s(szTemp, _T("\\Debugging Tools for Windows (x86)\\dbghelp.dll"));
- // now check if the file exists:
- if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES)
- {
- m_hDbhHelp = LoadLibrary(szTemp);
- }
- }
- #elif _M_X64
- if ((m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0))
- {
- _tcscat_s(szTemp, _T("\\Debugging Tools for Windows (x64)\\dbghelp.dll"));
- // now check if the file exists:
- if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES)
- {
- m_hDbhHelp = LoadLibrary(szTemp);
- }
- }
- #elif _M_IA64
- if ((m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0))
- {
- _tcscat_s(szTemp, _T("\\Debugging Tools for Windows (ia64)\\dbghelp.dll"));
- // now check if the file exists:
- if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES)
- {
- m_hDbhHelp = LoadLibrary(szTemp);
- }
- }
- #endif
- // If still not found, try the old directories...
- if ((m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0))
- {
- _tcscat_s(szTemp, _T("\\Debugging Tools for Windows\\dbghelp.dll"));
- // now check if the file exists:
- if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES)
- {
- m_hDbhHelp = LoadLibrary(szTemp);
- }
- }
- #if defined _M_X64 || defined _M_IA64
- // Still not found? Then try to load the (old) 64-Bit version:
- if ((m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0))
- {
- _tcscat_s(szTemp, _T("\\Debugging Tools for Windows 64-Bit\\dbghelp.dll"));
- if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES)
- {
- m_hDbhHelp = LoadLibrary(szTemp);
- }
- }
- #endif
- }
- }
- if (m_hDbhHelp == NULL) // if not already loaded, try to load a default-one
- m_hDbhHelp = LoadLibrary(_T("dbghelp.dll"));
- if (m_hDbhHelp == NULL)
- return FALSE;
- pSI = (tSI)GetProcAddress(m_hDbhHelp, "SymInitialize");
- pSC = (tSC)GetProcAddress(m_hDbhHelp, "SymCleanup");
-
- pSW = (tSW)GetProcAddress(m_hDbhHelp, "StackWalk64");
- pSGO = (tSGO)GetProcAddress(m_hDbhHelp, "SymGetOptions");
- pSSO = (tSSO)GetProcAddress(m_hDbhHelp, "SymSetOptions");
-
- pSFTA = (tSFTA)GetProcAddress(m_hDbhHelp, "SymFunctionTableAccess64");
- pSGLFA = (tSGLFA)GetProcAddress(m_hDbhHelp, "SymGetLineFromAddr64");
- pSGMB = (tSGMB)GetProcAddress(m_hDbhHelp, "SymGetModuleBase64");
- pSGMI = (tSGMI)GetProcAddress(m_hDbhHelp, "SymGetModuleInfo64");
- pSGSFA = (tSGSFA)GetProcAddress(m_hDbhHelp, "SymGetSymFromAddr64");
- pUDSN = (tUDSN)GetProcAddress(m_hDbhHelp, "UnDecorateSymbolName");
- pSLM = (tSLM)GetProcAddress(m_hDbhHelp, "SymLoadModule64");
- pSGSP = (tSGSP)GetProcAddress(m_hDbhHelp, "SymGetSearchPath");
-
- if (pSC == NULL || pSFTA == NULL || pSGMB == NULL || pSGMI == NULL || pSGO == NULL ||
- pSGSFA == NULL || pSI == NULL || pSSO == NULL || pSW == NULL || pUDSN == NULL ||
- pSLM == NULL)
- {
- FreeLibrary(m_hDbhHelp);
- m_hDbhHelp = NULL;
- pSC = NULL;
- return FALSE;
- }
-
- // SymInitialize
- if (szSymPath != NULL)
- m_szSymPath = _strdup(szSymPath);
- if (this->pSI(m_hProcess, m_szSymPath, FALSE) == FALSE)
- this->m_parent->OnDbgHelpErr("SymInitialize", GetLastError(), 0);
-
- DWORD symOptions = this->pSGO(); // SymGetOptions
- symOptions |= SYMOPT_LOAD_LINES;
- symOptions |= SYMOPT_FAIL_CRITICAL_ERRORS;
- //symOptions |= SYMOPT_NO_PROMPTS;
- // SymSetOptions
- symOptions = this->pSSO(symOptions);
-
- char buf[StackWalker::STACKWALK_MAX_NAMELEN] = {0};
- if (this->pSGSP != NULL)
- {
- if (this->pSGSP(m_hProcess, buf, StackWalker::STACKWALK_MAX_NAMELEN) == FALSE)
- this->m_parent->OnDbgHelpErr("SymGetSearchPath", GetLastError(), 0);
- }
- char szUserName[1024] = {0};
- DWORD dwSize = 1024;
- GetUserNameA(szUserName, &dwSize);
- this->m_parent->OnSymInit(buf, symOptions, szUserName);
-
- return TRUE;
- }
-
- StackWalker* m_parent;
-
- HMODULE m_hDbhHelp;
- HANDLE m_hProcess;
- LPSTR m_szSymPath;
-
- #pragma pack(push, 8)
- typedef struct IMAGEHLP_MODULE64_V3
- {
- 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
- // new elements: 07-Jun-2002
- CHAR LoadedPdbName[256]; // pdb file name
- DWORD CVSig; // Signature of the CV record in the debug directories
- CHAR CVData[MAX_PATH * 3]; // Contents of the CV record
- DWORD PdbSig; // Signature of PDB
- GUID PdbSig70; // Signature of PDB (VC 7 and up)
- DWORD PdbAge; // DBI age of pdb
- BOOL PdbUnmatched; // loaded an unmatched pdb
- BOOL DbgUnmatched; // loaded an unmatched dbg
- BOOL LineNumbers; // we have line number information
- BOOL GlobalSymbols; // we have internal symbol information
- BOOL TypeInfo; // we have type information
- // new elements: 17-Dec-2003
- BOOL SourceIndexed; // pdb supports source server
- BOOL Publics; // contains public symbols
- };
-
- typedef struct IMAGEHLP_MODULE64_V2
- {
- 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
- };
- #pragma pack(pop)
-
- // SymCleanup()
- typedef BOOL(__stdcall* tSC)(IN HANDLE hProcess);
- tSC pSC;
-
- // SymFunctionTableAccess64()
- typedef PVOID(__stdcall* tSFTA)(HANDLE hProcess, DWORD64 AddrBase);
- tSFTA pSFTA;
-
- // SymGetLineFromAddr64()
- typedef BOOL(__stdcall* tSGLFA)(IN HANDLE hProcess,
- IN DWORD64 dwAddr,
- OUT PDWORD pdwDisplacement,
- OUT PIMAGEHLP_LINE64 Line);
- tSGLFA pSGLFA;
-
- // SymGetModuleBase64()
- typedef DWORD64(__stdcall* tSGMB)(IN HANDLE hProcess, IN DWORD64 dwAddr);
- tSGMB pSGMB;
-
- // SymGetModuleInfo64()
- typedef BOOL(__stdcall* tSGMI)(IN HANDLE hProcess,
- IN DWORD64 dwAddr,
- OUT IMAGEHLP_MODULE64_V3* ModuleInfo);
- tSGMI pSGMI;
-
- // SymGetOptions()
- typedef DWORD(__stdcall* tSGO)(VOID);
- tSGO pSGO;
-
- // SymGetSymFromAddr64()
- typedef BOOL(__stdcall* tSGSFA)(IN HANDLE hProcess,
- IN DWORD64 dwAddr,
- OUT PDWORD64 pdwDisplacement,
- OUT PIMAGEHLP_SYMBOL64 Symbol);
- tSGSFA pSGSFA;
-
- // SymInitialize()
- typedef BOOL(__stdcall* tSI)(IN HANDLE hProcess, IN PSTR UserSearchPath, IN BOOL fInvadeProcess);
- tSI pSI;
-
- // SymLoadModule64()
- typedef DWORD64(__stdcall* tSLM)(IN HANDLE hProcess,
- IN HANDLE hFile,
- IN PSTR ImageName,
- IN PSTR ModuleName,
- IN DWORD64 BaseOfDll,
- IN DWORD SizeOfDll);
- tSLM pSLM;
-
- // SymSetOptions()
- typedef DWORD(__stdcall* tSSO)(IN DWORD SymOptions);
- tSSO pSSO;
-
- // StackWalk64()
- typedef BOOL(__stdcall* tSW)(DWORD MachineType,
- HANDLE hProcess,
- HANDLE hThread,
- LPSTACKFRAME64 StackFrame,
- PVOID ContextRecord,
- PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
- PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
- PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
- PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress);
- tSW pSW;
-
- // UnDecorateSymbolName()
- typedef DWORD(__stdcall WINAPI* tUDSN)(PCSTR DecoratedName,
- PSTR UnDecoratedName,
- DWORD UndecoratedLength,
- DWORD Flags);
- tUDSN pUDSN;
-
- typedef BOOL(__stdcall WINAPI* tSGSP)(HANDLE hProcess, PSTR SearchPath, DWORD SearchPathLength);
- tSGSP pSGSP;
-
- private:
- // **************************************** ToolHelp32 ************************
- #define MAX_MODULE_NAME32 255
- #define TH32CS_SNAPMODULE 0x00000008
- #pragma pack(push, 8)
- typedef struct tagMODULEENTRY32
- {
- DWORD dwSize;
- DWORD th32ModuleID; // This module
- DWORD th32ProcessID; // owning process
- DWORD GlblcntUsage; // Global usage count on the module
- DWORD ProccntUsage; // Module usage count in th32ProcessID's context
- BYTE* modBaseAddr; // Base address of module in th32ProcessID's context
- DWORD modBaseSize; // Size in bytes of module starting at modBaseAddr
- HMODULE hModule; // The hModule of this module in th32ProcessID's context
- char szModule[MAX_MODULE_NAME32 + 1];
- char szExePath[MAX_PATH];
- } MODULEENTRY32;
- typedef MODULEENTRY32* PMODULEENTRY32;
- typedef MODULEENTRY32* LPMODULEENTRY32;
- #pragma pack(pop)
-
- BOOL GetModuleListTH32(HANDLE hProcess, DWORD pid)
- {
- // CreateToolhelp32Snapshot()
- typedef HANDLE(__stdcall * tCT32S)(DWORD dwFlags, DWORD th32ProcessID);
- // Module32First()
- typedef BOOL(__stdcall * tM32F)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
- // Module32Next()
- typedef BOOL(__stdcall * tM32N)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
-
- // try both dlls...
- const TCHAR* dllname[] = {_T("kernel32.dll"), _T("tlhelp32.dll")};
- HINSTANCE hToolhelp = NULL;
- tCT32S pCT32S = NULL;
- tM32F pM32F = NULL;
- tM32N pM32N = NULL;
-
- HANDLE hSnap;
- MODULEENTRY32 me;
- me.dwSize = sizeof(me);
- BOOL keepGoing;
- size_t i;
-
- for (i = 0; i < (sizeof(dllname) / sizeof(dllname[0])); i++)
- {
- hToolhelp = LoadLibrary(dllname[i]);
- if (hToolhelp == NULL)
- continue;
- pCT32S = (tCT32S)GetProcAddress(hToolhelp, "CreateToolhelp32Snapshot");
- pM32F = (tM32F)GetProcAddress(hToolhelp, "Module32First");
- pM32N = (tM32N)GetProcAddress(hToolhelp, "Module32Next");
- if ((pCT32S != NULL) && (pM32F != NULL) && (pM32N != NULL))
- break; // found the functions!
- FreeLibrary(hToolhelp);
- hToolhelp = NULL;
- }
-
- if (hToolhelp == NULL)
- return FALSE;
-
- hSnap = pCT32S(TH32CS_SNAPMODULE, pid);
- if (hSnap == (HANDLE)-1)
- {
- FreeLibrary(hToolhelp);
- return FALSE;
- }
-
- keepGoing = !!pM32F(hSnap, &me);
- int cnt = 0;
- while (keepGoing)
- {
- this->LoadModule(hProcess, me.szExePath, me.szModule, (DWORD64)me.modBaseAddr,
- me.modBaseSize);
- cnt++;
- keepGoing = !!pM32N(hSnap, &me);
- }
- CloseHandle(hSnap);
- FreeLibrary(hToolhelp);
- if (cnt <= 0)
- return FALSE;
- return TRUE;
- } // GetModuleListTH32
-
- // **************************************** PSAPI ************************
- typedef struct _MODULEINFO
- {
- LPVOID lpBaseOfDll;
- DWORD SizeOfImage;
- LPVOID EntryPoint;
- } MODULEINFO, *LPMODULEINFO;
-
- BOOL GetModuleListPSAPI(HANDLE hProcess)
- {
- // EnumProcessModules()
- typedef BOOL(__stdcall * tEPM)(HANDLE hProcess, HMODULE * lphModule, DWORD cb,
- LPDWORD lpcbNeeded);
- // GetModuleFileNameEx()
- typedef DWORD(__stdcall * tGMFNE)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename,
- DWORD nSize);
- // GetModuleBaseName()
- typedef DWORD(__stdcall * tGMBN)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename,
- DWORD nSize);
- // GetModuleInformation()
- typedef BOOL(__stdcall * tGMI)(HANDLE hProcess, HMODULE hModule, LPMODULEINFO pmi, DWORD nSize);
-
- HINSTANCE hPsapi;
- tEPM pEPM;
- tGMFNE pGMFNE;
- tGMBN pGMBN;
- tGMI pGMI;
-
- DWORD i;
- //ModuleEntry e;
- DWORD cbNeeded;
- MODULEINFO mi;
- HMODULE* hMods = NULL;
- char* tt = NULL;
- char* tt2 = NULL;
- const SIZE_T TTBUFLEN = 8096;
- int cnt = 0;
-
- hPsapi = LoadLibrary(_T("psapi.dll"));
- if (hPsapi == NULL)
- return FALSE;
-
- pEPM = (tEPM)GetProcAddress(hPsapi, "EnumProcessModules");
- pGMFNE = (tGMFNE)GetProcAddress(hPsapi, "GetModuleFileNameExA");
- pGMBN = (tGMFNE)GetProcAddress(hPsapi, "GetModuleBaseNameA");
- pGMI = (tGMI)GetProcAddress(hPsapi, "GetModuleInformation");
- if ((pEPM == NULL) || (pGMFNE == NULL) || (pGMBN == NULL) || (pGMI == NULL))
- {
- // we couldn't find all functions
- FreeLibrary(hPsapi);
- return FALSE;
- }
-
- hMods = (HMODULE*)malloc(sizeof(HMODULE) * (TTBUFLEN / sizeof(HMODULE)));
- tt = (char*)malloc(sizeof(char) * TTBUFLEN);
- tt2 = (char*)malloc(sizeof(char) * TTBUFLEN);
- if ((hMods == NULL) || (tt == NULL) || (tt2 == NULL))
- goto cleanup;
-
- if (!pEPM(hProcess, hMods, TTBUFLEN, &cbNeeded))
- {
- //_ftprintf(fLogFile, _T("%lu: EPM failed, GetLastError = %lu\n"), g_dwShowCount, gle );
- goto cleanup;
- }
-
- if (cbNeeded > TTBUFLEN)
- {
- //_ftprintf(fLogFile, _T("%lu: More than %lu module handles. Huh?\n"), g_dwShowCount, lenof( hMods ) );
- goto cleanup;
- }
-
- for (i = 0; i < cbNeeded / sizeof(hMods[0]); i++)
- {
- // base address, size
- pGMI(hProcess, hMods[i], &mi, sizeof(mi));
- // image file name
- tt[0] = 0;
- pGMFNE(hProcess, hMods[i], tt, TTBUFLEN);
- // module name
- tt2[0] = 0;
- pGMBN(hProcess, hMods[i], tt2, TTBUFLEN);
-
- DWORD dwRes = this->LoadModule(hProcess, tt, tt2, (DWORD64)mi.lpBaseOfDll, mi.SizeOfImage);
- if (dwRes != ERROR_SUCCESS)
- this->m_parent->OnDbgHelpErr("LoadModule", dwRes, 0);
- cnt++;
- }
-
- cleanup:
- if (hPsapi != NULL)
- FreeLibrary(hPsapi);
- if (tt2 != NULL)
- free(tt2);
- if (tt != NULL)
- free(tt);
- if (hMods != NULL)
- free(hMods);
-
- return cnt != 0;
- } // GetModuleListPSAPI
-
- DWORD LoadModule(HANDLE hProcess, LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size)
- {
- CHAR* szImg = _strdup(img);
- CHAR* szMod = _strdup(mod);
- DWORD result = ERROR_SUCCESS;
- if ((szImg == NULL) || (szMod == NULL))
- result = ERROR_NOT_ENOUGH_MEMORY;
- else
- {
- if (pSLM(hProcess, 0, szImg, szMod, baseAddr, size) == 0)
- result = GetLastError();
- }
- ULONGLONG fileVersion = 0;
- if ((m_parent != NULL) && (szImg != NULL))
- {
- // try to retrieve the file-version:
- if ((this->m_parent->m_options & StackWalker::RetrieveFileVersion) != 0)
- {
- VS_FIXEDFILEINFO* fInfo = NULL;
- DWORD dwHandle;
- DWORD dwSize = GetFileVersionInfoSizeA(szImg, &dwHandle);
- if (dwSize > 0)
- {
- LPVOID vData = malloc(dwSize);
- if (vData != NULL)
- {
- if (GetFileVersionInfoA(szImg, dwHandle, dwSize, vData) != 0)
- {
- UINT len;
- TCHAR szSubBlock[] = _T("\\");
- if (VerQueryValue(vData, szSubBlock, (LPVOID*)&fInfo, &len) == 0)
- fInfo = NULL;
- else
- {
- fileVersion =
- ((ULONGLONG)fInfo->dwFileVersionLS) + ((ULONGLONG)fInfo->dwFileVersionMS << 32);
- }
- }
- free(vData);
- }
- }
- }
-
- // Retrieve some additional-infos about the module
- IMAGEHLP_MODULE64_V3 Module;
- const char* szSymType = "-unknown-";
- if (this->GetModuleInfo(hProcess, baseAddr, &Module) != FALSE)
- {
- switch (Module.SymType)
- {
- case SymNone:
- szSymType = "-nosymbols-";
- break;
- case SymCoff: // 1
- szSymType = "COFF";
- break;
- case SymCv: // 2
- szSymType = "CV";
- break;
- case SymPdb: // 3
- szSymType = "PDB";
- break;
- case SymExport: // 4
- szSymType = "-exported-";
- break;
- case SymDeferred: // 5
- szSymType = "-deferred-";
- break;
- case SymSym: // 6
- szSymType = "SYM";
- break;
- case 7: // SymDia:
- szSymType = "DIA";
- break;
- case 8: //SymVirtual:
- szSymType = "Virtual";
- break;
- }
- }
- LPCSTR pdbName = Module.LoadedImageName;
- if (Module.LoadedPdbName[0] != 0)
- pdbName = Module.LoadedPdbName;
- this->m_parent->OnLoadModule(img, mod, baseAddr, size, result, szSymType, pdbName,
- fileVersion);
- }
- if (szImg != NULL)
- free(szImg);
- if (szMod != NULL)
- free(szMod);
- return result;
- }
-
- public:
- BOOL LoadModules(HANDLE hProcess, DWORD dwProcessId)
- {
- // first try toolhelp32
- if (GetModuleListTH32(hProcess, dwProcessId))
- return true;
- // then try psapi
- return GetModuleListPSAPI(hProcess);
- }
-
- BOOL GetModuleInfo(HANDLE hProcess, DWORD64 baseAddr, IMAGEHLP_MODULE64_V3* pModuleInfo)
- {
- memset(pModuleInfo, 0, sizeof(IMAGEHLP_MODULE64_V3));
- if (this->pSGMI == NULL)
- {
- SetLastError(ERROR_DLL_INIT_FAILED);
- return FALSE;
- }
- // First try to use the larger ModuleInfo-Structure
- pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V3);
- void* pData = malloc(
- 4096); // reserve enough memory, so the bug in v6.3.5.1 does not lead to memory-overwrites...
- if (pData == NULL)
- {
- SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- return FALSE;
- }
- memcpy(pData, pModuleInfo, sizeof(IMAGEHLP_MODULE64_V3));
- static bool s_useV3Version = true;
- if (s_useV3Version)
- {
- if (this->pSGMI(hProcess, baseAddr, (IMAGEHLP_MODULE64_V3*)pData) != FALSE)
- {
- // only copy as much memory as is reserved...
- memcpy(pModuleInfo, pData, sizeof(IMAGEHLP_MODULE64_V3));
- pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V3);
- free(pData);
- return TRUE;
- }
- s_useV3Version = false; // to prevent unnecessary calls with the larger struct...
- }
-
- // could not retrieve the bigger structure, try with the smaller one (as defined in VC7.1)...
- pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2);
- memcpy(pData, pModuleInfo, sizeof(IMAGEHLP_MODULE64_V2));
- if (this->pSGMI(hProcess, baseAddr, (IMAGEHLP_MODULE64_V3*)pData) != FALSE)
- {
- // only copy as much memory as is reserved...
- memcpy(pModuleInfo, pData, sizeof(IMAGEHLP_MODULE64_V2));
- pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2);
- free(pData);
- return TRUE;
- }
- free(pData);
- SetLastError(ERROR_DLL_INIT_FAILED);
- return FALSE;
- }
- };
-
- // #############################################################
- StackWalker::StackWalker(DWORD dwProcessId, HANDLE hProcess)
- {
- this->m_options = OptionsAll;
- this->m_modulesLoaded = FALSE;
- this->m_hProcess = hProcess;
- this->m_sw = new StackWalkerInternal(this, this->m_hProcess);
- this->m_dwProcessId = dwProcessId;
- this->m_szSymPath = NULL;
- this->m_MaxRecursionCount = 1000;
- }
- StackWalker::StackWalker(int options, LPCSTR szSymPath, DWORD dwProcessId, HANDLE hProcess)
- {
- this->m_options = options;
- this->m_modulesLoaded = FALSE;
- this->m_hProcess = hProcess;
- this->m_sw = new StackWalkerInternal(this, this->m_hProcess);
- this->m_dwProcessId = dwProcessId;
- if (szSymPath != NULL)
- {
- this->m_szSymPath = _strdup(szSymPath);
- this->m_options |= SymBuildPath;
- }
- else
- this->m_szSymPath = NULL;
- this->m_MaxRecursionCount = 1000;
- }
-
- StackWalker::~StackWalker()
- {
- if (m_szSymPath != NULL)
- free(m_szSymPath);
- m_szSymPath = NULL;
- if (this->m_sw != NULL)
- delete this->m_sw;
- this->m_sw = NULL;
- }
-
- BOOL StackWalker::LoadModules()
- {
- if (this->m_sw == NULL)
- {
- SetLastError(ERROR_DLL_INIT_FAILED);
- return FALSE;
- }
- if (m_modulesLoaded != FALSE)
- return TRUE;
-
- // Build the sym-path:
- char* szSymPath = NULL;
- if ((this->m_options & SymBuildPath) != 0)
- {
- const size_t nSymPathLen = 4096;
- szSymPath = (char*)malloc(nSymPathLen);
- if (szSymPath == NULL)
- {
- SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- return FALSE;
- }
- szSymPath[0] = 0;
- // Now first add the (optional) provided sympath:
- if (this->m_szSymPath != NULL)
- {
- strcat_s(szSymPath, nSymPathLen, this->m_szSymPath);
- strcat_s(szSymPath, nSymPathLen, ";");
- }
-
- strcat_s(szSymPath, nSymPathLen, ".;");
-
- const size_t nTempLen = 1024;
- char szTemp[nTempLen];
- // Now add the current directory:
- if (GetCurrentDirectoryA(nTempLen, szTemp) > 0)
- {
- szTemp[nTempLen - 1] = 0;
- strcat_s(szSymPath, nSymPathLen, szTemp);
- strcat_s(szSymPath, nSymPathLen, ";");
- }
-
- // Now add the path for the main-module:
- if (GetModuleFileNameA(NULL, szTemp, nTempLen) > 0)
- {
- szTemp[nTempLen - 1] = 0;
- for (char* p = (szTemp + strlen(szTemp) - 1); p >= szTemp; --p)
- {
- // locate the rightmost path separator
- if ((*p == '\\') || (*p == '/') || (*p == ':'))
- {
- *p = 0;
- break;
- }
- } // for (search for path separator...)
- if (strlen(szTemp) > 0)
- {
- strcat_s(szSymPath, nSymPathLen, szTemp);
- strcat_s(szSymPath, nSymPathLen, ";");
- }
- }
- if (GetEnvironmentVariableA("_NT_SYMBOL_PATH", szTemp, nTempLen) > 0)
- {
- szTemp[nTempLen - 1] = 0;
- strcat_s(szSymPath, nSymPathLen, szTemp);
- strcat_s(szSymPath, nSymPathLen, ";");
- }
- if (GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", szTemp, nTempLen) > 0)
- {
- szTemp[nTempLen - 1] = 0;
- strcat_s(szSymPath, nSymPathLen, szTemp);
- strcat_s(szSymPath, nSymPathLen, ";");
- }
- if (GetEnvironmentVariableA("SYSTEMROOT", szTemp, nTempLen) > 0)
- {
- szTemp[nTempLen - 1] = 0;
- strcat_s(szSymPath, nSymPathLen, szTemp);
- strcat_s(szSymPath, nSymPathLen, ";");
- // also add the "system32"-directory:
- strcat_s(szTemp, nTempLen, "\\system32");
- strcat_s(szSymPath, nSymPathLen, szTemp);
- strcat_s(szSymPath, nSymPathLen, ";");
- }
-
- if ((this->m_options & SymUseSymSrv) != 0)
- {
- if (GetEnvironmentVariableA("SYSTEMDRIVE", szTemp, nTempLen) > 0)
- {
- szTemp[nTempLen - 1] = 0;
- strcat_s(szSymPath, nSymPathLen, "SRV*");
- strcat_s(szSymPath, nSymPathLen, szTemp);
- strcat_s(szSymPath, nSymPathLen, "\\websymbols");
- strcat_s(szSymPath, nSymPathLen, "*https://msdl.microsoft.com/download/symbols;");
- }
- else
- strcat_s(szSymPath, nSymPathLen,
- "SRV*c:\\websymbols*https://msdl.microsoft.com/download/symbols;");
- }
- } // if SymBuildPath
-
- // First Init the whole stuff...
- BOOL bRet = this->m_sw->Init(szSymPath);
- if (szSymPath != NULL)
- free(szSymPath);
- szSymPath = NULL;
- if (bRet == FALSE)
- {
- this->OnDbgHelpErr("Error while initializing dbghelp.dll", 0, 0);
- SetLastError(ERROR_DLL_INIT_FAILED);
- return FALSE;
- }
-
- bRet = this->m_sw->LoadModules(this->m_hProcess, this->m_dwProcessId);
- if (bRet != FALSE)
- m_modulesLoaded = TRUE;
- return bRet;
- }
-
- // The following is used to pass the "userData"-Pointer to the user-provided readMemoryFunction
- // This has to be done due to a problem with the "hProcess"-parameter in x64...
- // Because this class is in no case multi-threading-enabled (because of the limitations
- // of dbghelp.dll) it is "safe" to use a static-variable
- static StackWalker::PReadProcessMemoryRoutine s_readMemoryFunction = NULL;
- static LPVOID s_readMemoryFunction_UserData = NULL;
-
- BOOL StackWalker::ShowCallstack(HANDLE hThread,
- const CONTEXT* context,
- PReadProcessMemoryRoutine readMemoryFunction,
- LPVOID pUserData)
- {
- CONTEXT c;
- CallstackEntry csEntry;
- IMAGEHLP_SYMBOL64* pSym = NULL;
- StackWalkerInternal::IMAGEHLP_MODULE64_V3 Module;
- IMAGEHLP_LINE64 Line;
- int frameNum;
- bool bLastEntryCalled = true;
- int curRecursionCount = 0;
-
- if (m_modulesLoaded == FALSE)
- this->LoadModules(); // ignore the result...
-
- if (this->m_sw->m_hDbhHelp == NULL)
- {
- SetLastError(ERROR_DLL_INIT_FAILED);
- return FALSE;
- }
-
- s_readMemoryFunction = readMemoryFunction;
- s_readMemoryFunction_UserData = pUserData;
-
- if (context == NULL)
- {
- // If no context is provided, capture the context
- // See: https://stackwalker.codeplex.com/discussions/446958
- #if _WIN32_WINNT <= 0x0501
- // If we need to support XP, we need to use the "old way", because "GetThreadId" is not available!
- if (hThread == GetCurrentThread())
- #else
- if (GetThreadId(hThread) == GetCurrentThreadId())
- #endif
- {
- GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, USED_CONTEXT_FLAGS);
- }
- else
- {
- SuspendThread(hThread);
- memset(&c, 0, sizeof(CONTEXT));
- c.ContextFlags = USED_CONTEXT_FLAGS;
-
- // TODO: Detect if you want to get a thread context of a different process, which is running a different processor architecture...
- // This does only work if we are x64 and the target process is x64 or x86;
- // It cannot work, if this process is x64 and the target process is x64... this is not supported...
- // See also: http://www.howzatt.demon.co.uk/articles/DebuggingInWin64.html
- if (GetThreadContext(hThread, &c) == FALSE)
- {
- ResumeThread(hThread);
- return FALSE;
- }
- }
- }
- else
- c = *context;
-
- // init STACKFRAME for first call
- STACKFRAME64 s; // in/out stackframe
- memset(&s, 0, sizeof(s));
- DWORD imageType;
- #ifdef _M_IX86
- // normally, call ImageNtHeader() and use machine info from PE header
- imageType = IMAGE_FILE_MACHINE_I386;
- s.AddrPC.Offset = c.Eip;
- s.AddrPC.Mode = AddrModeFlat;
- s.AddrFrame.Offset = c.Ebp;
- s.AddrFrame.Mode = AddrModeFlat;
- s.AddrStack.Offset = c.Esp;
- s.AddrStack.Mode = AddrModeFlat;
- #elif _M_X64
- imageType = IMAGE_FILE_MACHINE_AMD64;
- s.AddrPC.Offset = c.Rip;
- s.AddrPC.Mode = AddrModeFlat;
- s.AddrFrame.Offset = c.Rsp;
- s.AddrFrame.Mode = AddrModeFlat;
- s.AddrStack.Offset = c.Rsp;
- s.AddrStack.Mode = AddrModeFlat;
- #elif _M_IA64
- imageType = IMAGE_FILE_MACHINE_IA64;
- s.AddrPC.Offset = c.StIIP;
- s.AddrPC.Mode = AddrModeFlat;
- s.AddrFrame.Offset = c.IntSp;
- s.AddrFrame.Mode = AddrModeFlat;
- s.AddrBStore.Offset = c.RsBSP;
- s.AddrBStore.Mode = AddrModeFlat;
- s.AddrStack.Offset = c.IntSp;
- s.AddrStack.Mode = AddrModeFlat;
- #else
- #error "Platform not supported!"
- #endif
-
- pSym = (IMAGEHLP_SYMBOL64*)malloc(sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN);
- if (!pSym)
- goto cleanup; // not enough memory...
- memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN);
- pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
- pSym->MaxNameLength = STACKWALK_MAX_NAMELEN;
-
- memset(&Line, 0, sizeof(Line));
- Line.SizeOfStruct = sizeof(Line);
-
- memset(&Module, 0, sizeof(Module));
- Module.SizeOfStruct = sizeof(Module);
-
- for (frameNum = 0;; ++frameNum)
- {
- // get next stack frame (StackWalk64(), SymFunctionTableAccess64(), SymGetModuleBase64())
- // if this returns ERROR_INVALID_ADDRESS (487) or ERROR_NOACCESS (998), you can
- // assume that either you are done, or that the stack is so hosed that the next
- // deeper frame could not be found.
- // CONTEXT need not to be supplied if imageTyp is IMAGE_FILE_MACHINE_I386!
- if (!this->m_sw->pSW(imageType, this->m_hProcess, hThread, &s, &c, myReadProcMem,
- this->m_sw->pSFTA, this->m_sw->pSGMB, NULL))
- {
- // INFO: "StackWalk64" does not set "GetLastError"...
- this->OnDbgHelpErr("StackWalk64", 0, s.AddrPC.Offset);
- break;
- }
-
- csEntry.offset = s.AddrPC.Offset;
- csEntry.name[0] = 0;
- csEntry.undName[0] = 0;
- csEntry.undFullName[0] = 0;
- csEntry.offsetFromSmybol = 0;
- csEntry.offsetFromLine = 0;
- csEntry.lineFileName[0] = 0;
- csEntry.lineNumber = 0;
- csEntry.loadedImageName[0] = 0;
- csEntry.moduleName[0] = 0;
- if (s.AddrPC.Offset == s.AddrReturn.Offset)
- {
- if ((this->m_MaxRecursionCount > 0) && (curRecursionCount > m_MaxRecursionCount))
- {
- this->OnDbgHelpErr("StackWalk64-Endless-Callstack!", 0, s.AddrPC.Offset);
- break;
- }
- curRecursionCount++;
- }
- else
- curRecursionCount = 0;
- if (s.AddrPC.Offset != 0)
- {
- // we seem to have a valid PC
- // show procedure info (SymGetSymFromAddr64())
- if (this->m_sw->pSGSFA(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromSmybol),
- pSym) != FALSE)
- {
- MyStrCpy(csEntry.name, STACKWALK_MAX_NAMELEN, pSym->Name);
- // UnDecorateSymbolName()
- this->m_sw->pUDSN(pSym->Name, csEntry.undName, STACKWALK_MAX_NAMELEN, UNDNAME_NAME_ONLY);
- this->m_sw->pUDSN(pSym->Name, csEntry.undFullName, STACKWALK_MAX_NAMELEN, UNDNAME_COMPLETE);
- }
- else
- {
- this->OnDbgHelpErr("SymGetSymFromAddr64", GetLastError(), s.AddrPC.Offset);
- }
-
- // show line number info, NT5.0-method (SymGetLineFromAddr64())
- if (this->m_sw->pSGLFA != NULL)
- { // yes, we have SymGetLineFromAddr64()
- if (this->m_sw->pSGLFA(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromLine),
- &Line) != FALSE)
- {
- csEntry.lineNumber = Line.LineNumber;
- MyStrCpy(csEntry.lineFileName, STACKWALK_MAX_NAMELEN, Line.FileName);
- }
- else
- {
- this->OnDbgHelpErr("SymGetLineFromAddr64", GetLastError(), s.AddrPC.Offset);
- }
- } // yes, we have SymGetLineFromAddr64()
-
- // show module info (SymGetModuleInfo64())
- if (this->m_sw->GetModuleInfo(this->m_hProcess, s.AddrPC.Offset, &Module) != FALSE)
- { // got module info OK
- switch (Module.SymType)
- {
- case SymNone:
- csEntry.symTypeString = "-nosymbols-";
- break;
- case SymCoff:
- csEntry.symTypeString = "COFF";
- break;
- case SymCv:
- csEntry.symTypeString = "CV";
- break;
- case SymPdb:
- csEntry.symTypeString = "PDB";
- break;
- case SymExport:
- csEntry.symTypeString = "-exported-";
- break;
- case SymDeferred:
- csEntry.symTypeString = "-deferred-";
- break;
- case SymSym:
- csEntry.symTypeString = "SYM";
- break;
- #if API_VERSION_NUMBER >= 9
- case SymDia:
- csEntry.symTypeString = "DIA";
- break;
- #endif
- case 8: //SymVirtual:
- csEntry.symTypeString = "Virtual";
- break;
- default:
- //_snprintf( ty, sizeof(ty), "symtype=%ld", (long) Module.SymType );
- csEntry.symTypeString = NULL;
- break;
- }
-
- MyStrCpy(csEntry.moduleName, STACKWALK_MAX_NAMELEN, Module.ModuleName);
- csEntry.baseOfImage = Module.BaseOfImage;
- MyStrCpy(csEntry.loadedImageName, STACKWALK_MAX_NAMELEN, Module.LoadedImageName);
- } // got module info OK
- else
- {
- this->OnDbgHelpErr("SymGetModuleInfo64", GetLastError(), s.AddrPC.Offset);
- }
- } // we seem to have a valid PC
-
- CallstackEntryType et = nextEntry;
- if (frameNum == 0)
- et = firstEntry;
- bLastEntryCalled = false;
- this->OnCallstackEntry(et, csEntry);
-
- if (s.AddrReturn.Offset == 0)
- {
- bLastEntryCalled = true;
- this->OnCallstackEntry(lastEntry, csEntry);
- SetLastError(ERROR_SUCCESS);
- break;
- }
- } // for ( frameNum )
-
- cleanup:
- if (pSym)
- free(pSym);
-
- if (bLastEntryCalled == false)
- this->OnCallstackEntry(lastEntry, csEntry);
-
- if (context == NULL)
- ResumeThread(hThread);
-
- return TRUE;
- }
-
- BOOL StackWalker::ShowObject(LPVOID pObject)
- {
- // Load modules if not done yet
- if (m_modulesLoaded == FALSE)
- this->LoadModules(); // ignore the result...
-
- // Verify that the DebugHelp.dll was actually found
- if (this->m_sw->m_hDbhHelp == NULL)
- {
- SetLastError(ERROR_DLL_INIT_FAILED);
- return FALSE;
- }
-
- // SymGetSymFromAddr64() is required
- if (this->m_sw->pSGSFA == NULL)
- return FALSE;
-
- // Show object info (SymGetSymFromAddr64())
- DWORD64 dwAddress = DWORD64(pObject);
- DWORD64 dwDisplacement = 0;
- const SIZE_T symSize = sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN;
- IMAGEHLP_SYMBOL64* pSym = (IMAGEHLP_SYMBOL64*) malloc(symSize);
- if (!pSym)
- return FALSE;
- memset(pSym, 0, symSize);
- pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
- pSym->MaxNameLength = STACKWALK_MAX_NAMELEN;
- if (this->m_sw->pSGSFA(this->m_hProcess, dwAddress, &dwDisplacement, pSym) == FALSE)
- {
- this->OnDbgHelpErr("SymGetSymFromAddr64", GetLastError(), dwAddress);
- return FALSE;
- }
- // Object name output
- this->OnOutput(pSym->Name);
-
- free(pSym);
- return TRUE;
- };
-
- BOOL __stdcall StackWalker::myReadProcMem(HANDLE hProcess,
- DWORD64 qwBaseAddress,
- PVOID lpBuffer,
- DWORD nSize,
- LPDWORD lpNumberOfBytesRead)
- {
- if (s_readMemoryFunction == NULL)
- {
- SIZE_T st;
- BOOL bRet = ReadProcessMemory(hProcess, (LPVOID)qwBaseAddress, lpBuffer, nSize, &st);
- *lpNumberOfBytesRead = (DWORD)st;
- //printf("ReadMemory: hProcess: %p, baseAddr: %p, buffer: %p, size: %d, read: %d, result: %d\n", hProcess, (LPVOID) qwBaseAddress, lpBuffer, nSize, (DWORD) st, (DWORD) bRet);
- return bRet;
- }
- else
- {
- return s_readMemoryFunction(hProcess, qwBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead,
- s_readMemoryFunction_UserData);
- }
- }
-
- void StackWalker::OnLoadModule(LPCSTR img,
- LPCSTR mod,
- DWORD64 baseAddr,
- DWORD size,
- DWORD result,
- LPCSTR symType,
- LPCSTR pdbName,
- ULONGLONG fileVersion)
- {
- CHAR buffer[STACKWALK_MAX_NAMELEN];
- size_t maxLen = STACKWALK_MAX_NAMELEN;
- #if _MSC_VER >= 1400
- maxLen = _TRUNCATE;
- #endif
- if (fileVersion == 0)
- _snprintf_s(buffer, maxLen, "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s'\n",
- img, mod, (LPVOID)baseAddr, size, result, symType, pdbName);
- else
- {
- DWORD v4 = (DWORD)(fileVersion & 0xFFFF);
- DWORD v3 = (DWORD)((fileVersion >> 16) & 0xFFFF);
- DWORD v2 = (DWORD)((fileVersion >> 32) & 0xFFFF);
- DWORD v1 = (DWORD)((fileVersion >> 48) & 0xFFFF);
- _snprintf_s(
- buffer, maxLen,
- "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s', fileVersion: %d.%d.%d.%d\n",
- img, mod, (LPVOID)baseAddr, size, result, symType, pdbName, v1, v2, v3, v4);
- }
- buffer[STACKWALK_MAX_NAMELEN - 1] = 0; // be sure it is NULL terminated
- OnOutput(buffer);
- }
-
- void StackWalker::OnCallstackEntry(CallstackEntryType eType, CallstackEntry& entry)
- {
- CHAR buffer[STACKWALK_MAX_NAMELEN];
- size_t maxLen = STACKWALK_MAX_NAMELEN;
- #if _MSC_VER >= 1400
- maxLen = _TRUNCATE;
- #endif
- if ((eType != lastEntry) && (entry.offset != 0))
- {
- if (entry.name[0] == 0)
- MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, "(function-name not available)");
- if (entry.undName[0] != 0)
- MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, entry.undName);
- if (entry.undFullName[0] != 0)
- MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, entry.undFullName);
- if (entry.lineFileName[0] == 0)
- {
- MyStrCpy(entry.lineFileName, STACKWALK_MAX_NAMELEN, "(filename not available)");
- if (entry.moduleName[0] == 0)
- MyStrCpy(entry.moduleName, STACKWALK_MAX_NAMELEN, "(module-name not available)");
- _snprintf_s(buffer, maxLen, "%p (%s): %s: %s\n", (LPVOID)entry.offset, entry.moduleName,
- entry.lineFileName, entry.name);
- }
- else
- _snprintf_s(buffer, maxLen, "%s (%d): %s\n", entry.lineFileName, entry.lineNumber,
- entry.name);
- buffer[STACKWALK_MAX_NAMELEN - 1] = 0;
- OnOutput(buffer);
- }
- }
-
- void StackWalker::OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr)
- {
- CHAR buffer[STACKWALK_MAX_NAMELEN];
- size_t maxLen = STACKWALK_MAX_NAMELEN;
- #if _MSC_VER >= 1400
- maxLen = _TRUNCATE;
- #endif
- _snprintf_s(buffer, maxLen, "ERROR: %s, GetLastError: %d (Address: %p)\n", szFuncName, gle,
- (LPVOID)addr);
- buffer[STACKWALK_MAX_NAMELEN - 1] = 0;
- OnOutput(buffer);
- }
-
- void StackWalker::OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName)
- {
- CHAR buffer[STACKWALK_MAX_NAMELEN];
- size_t maxLen = STACKWALK_MAX_NAMELEN;
- #if _MSC_VER >= 1400
- maxLen = _TRUNCATE;
- #endif
- _snprintf_s(buffer, maxLen, "SymInit: Symbol-SearchPath: '%s', symOptions: %d, UserName: '%s'\n",
- szSearchPath, symOptions, szUserName);
- buffer[STACKWALK_MAX_NAMELEN - 1] = 0;
- OnOutput(buffer);
- // Also display the OS-version
- #if _MSC_VER <= 1200
- OSVERSIONINFOA ver;
- ZeroMemory(&ver, sizeof(OSVERSIONINFOA));
- ver.dwOSVersionInfoSize = sizeof(ver);
- if (GetVersionExA(&ver) != FALSE)
- {
- _snprintf_s(buffer, maxLen, "OS-Version: %d.%d.%d (%s)\n", ver.dwMajorVersion,
- ver.dwMinorVersion, ver.dwBuildNumber, ver.szCSDVersion);
- buffer[STACKWALK_MAX_NAMELEN - 1] = 0;
- OnOutput(buffer);
- }
- #else
- OSVERSIONINFOEXA ver;
- ZeroMemory(&ver, sizeof(OSVERSIONINFOEXA));
- ver.dwOSVersionInfoSize = sizeof(ver);
- #if _MSC_VER >= 1900
- #pragma warning(push)
- #pragma warning(disable : 4996)
- #endif
- if (GetVersionExA((OSVERSIONINFOA*)&ver) != FALSE)
- {
- _snprintf_s(buffer, maxLen, "OS-Version: %d.%d.%d (%s) 0x%x-0x%x\n", ver.dwMajorVersion,
- ver.dwMinorVersion, ver.dwBuildNumber, ver.szCSDVersion, ver.wSuiteMask,
- ver.wProductType);
- buffer[STACKWALK_MAX_NAMELEN - 1] = 0;
- OnOutput(buffer);
- }
- #if _MSC_VER >= 1900
- #pragma warning(pop)
- #endif
- #endif
- }
-
- void StackWalker::OnOutput(LPCSTR buffer)
- {
- OutputDebugStringA(buffer);
- }
StackWalker.h
- #ifndef __STACKWALKER_H__
- #define __STACKWALKER_H__
-
- #if defined(_MSC_VER)
-
- #pragma once
-
- #include <windows.h>
-
- #if _MSC_VER >= 1900
- #pragma warning(disable : 4091)
- #endif
-
- // 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 StackWalkerInternal; // forward
- class StackWalker
- {
- public:
- typedef enum StackWalkOptions
- {
- // No addition info will be retrieved
- // (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 above
- RetrieveVerbose = 0xF,
-
- // Generate a "good" symbol-search-path
- SymBuildPath = 0x10,
-
- // Also use the public Microsoft-Symbol-Server
- SymUseSymSrv = 0x20,
-
- // Contains all the above "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
- );
-
- BOOL ShowObject(LPVOID pObject);
-
- #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
- } CallstackEntryType;
-
- 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;
-
- 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_STACKWALKER_CODEPLEX(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
- // clang-format off
- // The following should be enough for walking the callstack...
- #define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(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)
- // clang-format on
- #endif
-
- #else
-
- // The following is defined for x86 (XP and higher), x64 and IA64:
- #define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \
- do \
- { \
- memset(&c, 0, sizeof(CONTEXT)); \
- c.ContextFlags = contextFlags; \
- RtlCaptureContext(&c); \
- } while (0);
- #endif
-
- #endif //defined(_MSC_VER)
-
- #endif // __STACKWALKER_H__
基本用法:
StackWalkerToConsole sw;
sw.ShowCallstack();
备注:如果需要具体拿到字符串数据,用子类,重写OnOutput函数即可
用到dbghelp.lib和dbghelp.dll文件,生成minidump文件,直接看代码:
- #include <iostream>
- #include <windows.h>
- #include <dbghelp.h>
-
- #pragma comment(lib, "dbghelp.lib")
-
- static LONG WINAPI pfnUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)
- {
- if (IsDebuggerPresent())
- {
- return EXCEPTION_CONTINUE_SEARCH;
- }
-
- typedef BOOL(WINAPI* MiniDumpWriteDumpT)(
- HANDLE,
- DWORD,
- HANDLE,
- MINIDUMP_TYPE,
- PMINIDUMP_EXCEPTION_INFORMATION,
- PMINIDUMP_USER_STREAM_INFORMATION,
- PMINIDUMP_CALLBACK_INFORMATION);
-
- HMODULE hDbgHelp = LoadLibrary("dbghelp.dll");
- if (NULL == hDbgHelp)
- {
- return EXCEPTION_CONTINUE_EXECUTION;
- }
-
- SYSTEMTIME stSysTime;
- memset(&stSysTime, 0, sizeof(SYSTEMTIME));
- GetLocalTime(&stSysTime);
-
- TCHAR szFile[MAX_PATH] = { 0 }; //根据字符集,有时候可能为WCHAR
- wsprintf(szFile, "%0.4d-%0.2d-%0.2d-%0.2d-%0.2d-%0.2d-%0.3d.dmp",\
- stSysTime.wYear, stSysTime.wMonth, stSysTime.wDay, stSysTime.wHour,\
- stSysTime.wMinute, stSysTime.wSecond, stSysTime.wMilliseconds);
-
- HANDLE hFile = CreateFile(szFile, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ,\
- 0, CREATE_ALWAYS, 0, 0);
- if (INVALID_HANDLE_VALUE != hFile)
- {
- MINIDUMP_EXCEPTION_INFORMATION objExInfo;
- objExInfo.ThreadId = ::GetCurrentThreadId();
- objExInfo.ExceptionPointers = pExceptionInfo;
- objExInfo.ClientPointers = NULL;
-
- BOOL bOk = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile,\
- MiniDumpWithDataSegs, (pExceptionInfo ? &objExInfo : NULL), NULL, NULL);
- CloseHandle(hFile);
- }
-
- FreeLibrary(hDbgHelp);
-
- return EXCEPTION_EXECUTE_HANDLER;
- }
-
- int main(int argc, char** argv)
- {
- SetUnhandledExceptionFilter(pfnUnhandledExceptionFilter);
- int* pTest = NULL;
- *pTest = 1;
-
- char* pFileName = "./test.txt";
- WCHAR wszFileName[MAX_PATH] = { 0 };
- MultiByteToWideChar(CP_ACP, 0, pFileName, strlen(pFileName) + 1, wszFileName, sizeof(wszFileName) / sizeof(wszFileName[0]));
-
- getchar();
- return 0;
- }
另外一种做法:
- #include <iostream>
- #include <windows.h>
- #include <dbghelp.h>
-
- #pragma comment(lib, "dbghelp.lib")
-
- static LONG WINAPI pfnUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)
- {
- if (IsDebuggerPresent())
- {
- return EXCEPTION_CONTINUE_SEARCH;
- }
-
- typedef BOOL(WINAPI* MiniDumpWriteDumpT)(
- HANDLE,
- DWORD,
- HANDLE,
- MINIDUMP_TYPE,
- PMINIDUMP_EXCEPTION_INFORMATION,
- PMINIDUMP_USER_STREAM_INFORMATION,
- PMINIDUMP_CALLBACK_INFORMATION);
-
- HMODULE hDbgHelp = LoadLibrary("dbghelp.dll");
- if (NULL == hDbgHelp)
- {
- return EXCEPTION_CONTINUE_EXECUTION;
- }
-
- MiniDumpWriteDumpT pfnMinidumpWriteDump = NULL;
- pfnMinidumpWriteDump = (MiniDumpWriteDumpT)GetProcAddress(hDbgHelp, "MiniDumpWriteDump");
- if (NULL == pfnMinidumpWriteDump)
- {
- FreeLibrary(hDbgHelp);
- return EXCEPTION_CONTINUE_EXECUTION;
- }
-
- SYSTEMTIME stSysTime;
- memset(&stSysTime, 0, sizeof(SYSTEMTIME));
- GetLocalTime(&stSysTime);
-
- TCHAR szFile[MAX_PATH] = { 0 }; //根据字符集,有时候可能为WCHAR
- wsprintf(szFile, "%0.4d-%0.2d-%0.2d-%0.2d-%0.2d-%0.2d-%0.3d.dmp",\
- stSysTime.wYear, stSysTime.wMonth, stSysTime.wDay, stSysTime.wHour,\
- stSysTime.wMinute, stSysTime.wSecond, stSysTime.wMilliseconds);
-
- HANDLE hFile = CreateFile(szFile, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ,\
- 0, CREATE_ALWAYS, 0, 0);
- if (INVALID_HANDLE_VALUE != hFile)
- {
- MINIDUMP_EXCEPTION_INFORMATION objExInfo;
- objExInfo.ThreadId = ::GetCurrentThreadId();
- objExInfo.ExceptionPointers = pExceptionInfo;
- objExInfo.ClientPointers = NULL;
-
- BOOL bOk = pfnMinidumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile,\
- MiniDumpWithDataSegs, (pExceptionInfo ? &objExInfo : NULL), NULL, NULL);
- CloseHandle(hFile);
- }
-
- FreeLibrary(hDbgHelp);
-
- return EXCEPTION_EXECUTE_HANDLER;
- }
我试图做的就是打印调用给定行的方法堆栈。我从/sf/answers/398963841/答案中得到了代码。稍微重构它以显示问题所在。
- #include <windows.h>
- #include <iostream>
- #include <imagehlp.h>
- #include <dbghelp.h>
-
- void printStack( void ) {
- HMODULE dbghelp_lib = LoadLibrary("dbghelp.dll");
- if (NULL == dbghelp_lib) {
- printf("dbghelp.dll failed");
- }
- HANDLE process = GetCurrentProcess();
- if (!SymInitialize( process, NULL, TRUE )) {
- printf("SymInitialize failed: %d\n", GetLastError());
- abort();
- } else SetLastError(0);
- void * stack[100];
- ULONG FramesToSkip = 0;
- ULONG FramesToCapture = 32;
- unsigned short frames = CaptureStackBackTrace( FramesToSkip, FramesToCapture, stack, NULL );
- SYMBOL_INFO * symbol;
- symbol = ( SYMBOL_INFO * )calloc( sizeof( SYMBOL_INFO ) + 256 * sizeof( char ), 1 );
- symbol->MaxNameLen = 255;
- symbol->SizeOfStruct = sizeof( SYMBOL_INFO );
- for(unsigned int i = 0; i < frames; i++ ) {
- if(!SymFromAddr( process, ( DWORD )( stack[ i ] ), 0, symbol )) {
- printf("SymFromAddr failed: %d\n", GetLastError());
- }
- printf( "%i: %s - 0x%0X\n", frames - i - 1, symbol->Name, symbol->Address );
- }
- free( symbol );
- }
-
- void testfunc() {
- printStack();
- }
-
- int main() {
- testfunc();
- }
它返回:
- SymFromAddr failed: 487
- 3: - 0x0
- SymFromAddr failed: 487
- 2: - 0x0
- SymFromAddr failed: 487
- 1: - 0x0
- 0: RegisterWaitForInputIdle - 0x7C81702E
- #include "stdafx.h"
- #include <process.h>
- #include <iostream>
- #include <Windows.h>
- #include "dbghelp.h"
-
- using namespace std;
-
- #define TRACE_MAX_STACK_FRAMES 1024
- #define TRACE_MAX_FUNCTION_NAME_LENGTH 1024
-
- int printStackTrace()
- {
- void *stack[TRACE_MAX_STACK_FRAMES];
- HANDLE process = GetCurrentProcess();
- SymInitialize(process, NULL, TRUE);
- WORD numberOfFrames = CaptureStackBackTrace(0, TRACE_MAX_STACK_FRAMES, stack, NULL);
- SYMBOL_INFO *symbol = (SYMBOL_INFO *)malloc(sizeof(SYMBOL_INFO)+(TRACE_MAX_FUNCTION_NAME_LENGTH - 1) * sizeof(TCHAR));
- symbol->MaxNameLen = TRACE_MAX_FUNCTION_NAME_LENGTH;
- symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
- DWORD displacement;
- IMAGEHLP_LINE64 *line = (IMAGEHLP_LINE64 *)malloc(sizeof(IMAGEHLP_LINE64));
- line->SizeOfStruct = sizeof(IMAGEHLP_LINE64);
- for (int i = 0; i < numberOfFrames; i++)
- {
- DWORD64 address = (DWORD64)(stack[i]);
- SymFromAddr(process, address, NULL, symbol);
- if (SymGetLineFromAddr64(process, address, &displacement, line))
- {
- printf("\tat %s in %s: line: %lu: address: 0x%0X\n", symbol->Name, line->FileName, line->LineNumber, symbol->Address);
- }
- else
- {
- printf("\tSymGetLineFromAddr64 returned error code %lu.\n", GetLastError());
- printf("\tat %s, address 0x%0X.\n", symbol->Name, symbol->Address);
- }
- }
- return 0;
- }
-
- void function2()
- {
- int a = 0;
- int b = 0;
- throw new exception;
- }
-
- void function1()
- {
- int a = 0;
- function2();
- }
-
- void function0()
- {
- function1();
- }
-
- static void threadFunction(void *param)
- {
- try
- {
- function0();
- }
- catch (...)
- {
- printStackTrace();
- }
- }
-
- int _tmain(int argc, _TCHAR* argv[])
- {
- _beginthread(threadFunction, 0, NULL);
- printf("Press any key to exit.\n");
- cin.get();
- return 0;
- }
它的作用是,它记录了一个堆栈跟踪,但问题是它记录的堆栈跟踪没有给我我想要的行号.我想让它记录抛出异常的地方的行号,在调用堆栈上和上面,就像在C#中一样.但它现在实际上做了什么,它输出如下:
- at printStackTrace in c:\users\<yourusername>\documents\visual studio 2013\pr
- ojects\stacktracing\stacktracing\stacktracing.cpp: line: 17: address: 0x10485C0
- at threadFunction in c:\users\<yourusername>\documents\visual studio 2013\pro
- jects\stacktracing\stacktracing\stacktracing.cpp: line: 68: address: 0x10457C0
- SymGetLineFromAddr64 returned error code 487.
- at beginthread, address 0xF9431E0.
- SymGetLineFromAddr64 returned error code 487.
- at endthread, address 0xF9433E0.
- SymGetLineFromAddr64 returned error code 487.
- at BaseThreadInitThunk, address 0x7590494F.
- SymGetLineFromAddr64 returned error code 487.
- at RtlInitializeExceptionChain, address 0x7713986A.
- SymGetLineFromAddr64 returned error code 487.
- at RtlInitializeExceptionChain, address 0x7713986A.
我再次面临的问题是,line: 68此跟踪对应于调用方法的行printStackTrace();,而我希望它给出行号45,它对应于抛出异常的行:throw new exception;然后继续向上堆栈.
如何在抛出此异常以获得正确的堆栈跟踪时,如何实现此类行为并完全进入此线程?
PS上面的代码是使用MSVC++在Windows 8.1 x64机器上启用unicode的控制台应用程序运行的,应用程序在调试模式下作为Win32应用程序运行.
什么是PDB 文件?
通常我们在生成PE 文件的时候都会随带生成一个对应的pdb 文件,这个文件的含义是什么呢?我们在msdn上找到如下解释
https://msdn.microsoft.com/zh-cn/library/aa292304(v=vs.71).aspx
PDB(程序数据库 )文件保存着调试和项目状态信息,使用这些信息可以对程序的调试配置进行增量链接。
如果使用生成文件创建 C/C++ 应用程序,并指定 /ZI 或 /Zi 而不指定 /Fd 时,则最终将生成两个 PDB 文件:
VCx0.PDB(其中 x 表示 Visual C++ 的版本。如vs2010 对应的pdb 文件为vc100.pdb)该文件存储各个 OBJ 文件的所有调试信息并与项目生成文件驻留在同一个目录中(通常是对应的 “项目名\Debug或者Release” 目录)。
————————————————
版权声明:本文为CSDN博主「kiki商」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_18218335/article/details/73555860