📄 stackwalker.cpp
字号:
struct ModuleEntry
{
std::string imageName;
std::string moduleName;
DWORD baseAddress;
DWORD size;
};
typedef std::vector< ModuleEntry > ModuleList;
typedef ModuleList::iterator ModuleListIter;
// **************************************** 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 )
static BOOL GetModuleListTH32(ModuleList& modules, DWORD pid, FILE *fLogFile)
{
// 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 = 0;
MODULEENTRY32 me;
me.dwSize = sizeof(me);
BOOL keepGoing;
ModuleEntry e;
int i;
for (i = 0; i<lenof(dllname); 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 != 0 && pM32F != 0 && pM32N != 0 )
break; // found the functions!
FreeLibrary(hToolhelp);
hToolhelp = NULL;
}
if (hToolhelp == NULL)
return false;
hSnap = pCT32S( TH32CS_SNAPMODULE, pid );
if (hSnap == (HANDLE) -1)
return false;
keepGoing = !!pM32F( hSnap, &me );
while (keepGoing)
{
e.imageName = me.szExePath;
e.moduleName = me.szModule;
e.baseAddress = (DWORD) me.modBaseAddr;
e.size = me.modBaseSize;
modules.push_back( e );
keepGoing = !!pM32N( hSnap, &me );
}
CloseHandle(hSnap);
FreeLibrary(hToolhelp);
return modules.size() != 0;
} // GetModuleListTH32
// **************************************** PSAPI ************************
typedef struct _MODULEINFO {
LPVOID lpBaseOfDll;
DWORD SizeOfImage;
LPVOID EntryPoint;
} MODULEINFO, *LPMODULEINFO;
static BOOL GetModuleListPSAPI(ModuleList &modules, DWORD pid, HANDLE hProcess, FILE *fLogFile)
{
// 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 = 0;
char *tt = 0;
hPsapi = LoadLibrary( _T("psapi.dll") );
if ( hPsapi == 0 )
return false;
modules.clear();
pEPM = (tEPM) GetProcAddress( hPsapi, "EnumProcessModules" );
pGMFNE = (tGMFNE) GetProcAddress( hPsapi, "GetModuleFileNameExA" );
pGMBN = (tGMFNE) GetProcAddress( hPsapi, "GetModuleBaseNameA" );
pGMI = (tGMI) GetProcAddress( hPsapi, "GetModuleInformation" );
if ( pEPM == 0 || pGMFNE == 0 || pGMBN == 0 || pGMI == 0 )
{
// we couldn磘 find all functions
FreeLibrary( hPsapi );
return false;
}
hMods = (HMODULE*) malloc(sizeof(HMODULE) * (TTBUFLEN / sizeof HMODULE));
tt = (char*) malloc(sizeof(char) * TTBUFLEN);
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 );
e.baseAddress = (DWORD) mi.lpBaseOfDll;
e.size = mi.SizeOfImage;
// image file name
tt[0] = 0;
pGMFNE(hProcess, hMods[i], tt, TTBUFLEN );
e.imageName = tt;
// module name
tt[0] = 0;
pGMBN(hProcess, hMods[i], tt, TTBUFLEN );
e.moduleName = tt;
modules.push_back(e);
}
cleanup:
if (hPsapi)
FreeLibrary(hPsapi);
free(tt);
free(hMods);
return modules.size() != 0;
} // GetModuleListPSAPI
static BOOL GetModuleList(ModuleList& modules, DWORD pid, HANDLE hProcess, FILE *fLogFile)
{
// first try toolhelp32
if (GetModuleListTH32(modules, pid, fLogFile) )
return true;
// then try psapi
return GetModuleListPSAPI(modules, pid, hProcess, fLogFile);
} // GetModuleList
static void EnumAndLoadModuleSymbols( HANDLE hProcess, DWORD pid, FILE *fLogFile )
{
static ModuleList modules;
static ModuleListIter it;
char *img, *mod;
// fill in module list
GetModuleList(modules, pid, hProcess, fLogFile);
for ( it = modules.begin(); it != modules.end(); ++ it )
{
// SymLoadModule() wants writeable strings
img = strdup(it->imageName.c_str());
mod = strdup(it->moduleName.c_str());
pSLM( hProcess, 0, img, mod, it->baseAddress, it->size );
free(img);
free(mod);
std::string s;
}
} // EnumAndLoadModuleSymbols
static int InitStackWalk(void)
{
if (g_bInitialized != FALSE)
return 0; // already initialized
// 02-12-19: Now we only support dbghelp.dll!
// To use it on NT you have to install the redistrubutable for DBGHELP.DLL
g_hImagehlpDll = LoadLibrary( _T("dbghelp.dll") );
if ( g_hImagehlpDll == NULL )
{
printf( "LoadLibrary( \"dbghelp.dll\" ): GetLastError = %lu\n", gle );
g_bInitialized = FALSE;
return 1;
}
// now we only support the newer dbghlp.dll with the "64"-functions (StackWalk64, a.s.o.)
// If your dbghlp.dll does not support this, please download the redistributable from MS
// Normally from: http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=CD1FC4B2-0885-47F4-AF45-7FD5E14DB6C0
pSC = (tSC) GetProcAddress( g_hImagehlpDll, "SymCleanup" );
pSFTA = (tSFTA) GetProcAddress( g_hImagehlpDll, "SymFunctionTableAccess64" );
pSGLFA = (tSGLFA) GetProcAddress( g_hImagehlpDll, "SymGetLineFromAddr64" );
pSGMB = (tSGMB) GetProcAddress( g_hImagehlpDll, "SymGetModuleBase64" );
pSGMI = (tSGMI) GetProcAddress( g_hImagehlpDll, "SymGetModuleInfo64" );
pSGO = (tSGO) GetProcAddress( g_hImagehlpDll, "SymGetOptions" );
pSGSFA = (tSGSFA) GetProcAddress( g_hImagehlpDll, "SymGetSymFromAddr64" );
pSI = (tSI) GetProcAddress( g_hImagehlpDll, "SymInitialize" );
pSSO = (tSSO) GetProcAddress( g_hImagehlpDll, "SymSetOptions" );
pSW = (tSW) GetProcAddress( g_hImagehlpDll, "StackWalk64" );
pUDSN = (tUDSN) GetProcAddress( g_hImagehlpDll, "UnDecorateSymbolName" );
pSLM = (tSLM) GetProcAddress( g_hImagehlpDll, "SymLoadModule64" );
if ( pSC == NULL || pSFTA == NULL || pSGMB == NULL || pSGMI == NULL ||
pSGO == NULL || pSGSFA == NULL || pSI == NULL || pSSO == NULL ||
pSW == NULL || pUDSN == NULL || pSLM == NULL )
{
printf( "GetProcAddress(): some required function not found.\n" );
FreeLibrary( g_hImagehlpDll );
g_bInitialized = FALSE;
return 1;
}
g_bInitialized = TRUE;
InitializeCriticalSection(&g_csFileOpenClose);
return 0;
}
// This function if NOT multi-threading capable
// It should only be called from the main-Function!
int InitAllocCheckWN(eAllocCheckOutput eOutput, LPCTSTR pszFileName, ULONG ulShowStackAtAlloc) {
if (g_bInitialized) {
return 2; // already initialized!
}
if (ulShowStackAtAlloc <= 3)
g_ulShowStackAtAlloc = ulShowStackAtAlloc;
else
g_ulShowStackAtAlloc = 0;
if (pszFileName != NULL)
g_pszAllocLogName = _tcsdup(pszFileName);
else
g_pszAllocLogName = NULL;
g_CallstackOutputType = eOutput;
#ifdef _DEBUG
AllocHashInit();
#ifdef WITH_IMALLOC_SPY
HRESULT hr;
// erzeuge mein malloc-Spy object
LPMALLOCSPY pMallocSpy = new CMallocSpy(); // wird sp?er durch Release freigegeben
if (pMallocSpy != NULL)
{
// CoInitilize(); // ??? Ist dies notwendig ?
hr = CoRegisterMallocSpy(pMallocSpy);
if FAILED(hr)
{
_tprintf(_T("\nCoRegisterMallocSpay failed with %.8x"), hr);
}
}
#endif
// save the previous alloc hook
pfnOldCrtAllocHook = _CrtSetAllocHook(MyAllocHook);
#endif
return InitStackWalk();
} // InitAllocCheckWN
static TCHAR s_szExceptionLogFileName[_MAX_PATH] = _T("\\exceptions.log"); // default
static BOOL s_bUnhandledExeptionFilterSet = FALSE;
static LONG __stdcall CrashHandlerExceptionFilter(EXCEPTION_POINTERS* pExPtrs)
{
if (pExPtrs->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW)
{
static char MyStack[1024*128]; // be sure that we have enought space...
// it assumes that DS and SS are the same!!! (this is the case for Win32)
// change the stack only if the selectors are the same (this is the case for Win32)
//__asm push offset MyStack[1024*128];
//__asm pop esp;
__asm mov eax,offset MyStack[1024*128];
__asm mov esp,eax;
}
LONG lRet;
lRet = StackwalkFilter(pExPtrs, /*EXCEPTION_CONTINUE_SEARCH*/EXCEPTION_EXECUTE_HANDLER, s_szExceptionLogFileName);
TCHAR lString[500];
_stprintf(lString,
_T("*** Unhandled Exception!\n")
_T(" ExpCode: 0x%8.8X\n")
_T(" ExpFlags: %d\n")
_T(" ExpAddress: 0x%8.8X\n")
_T(" Please report!"),
pExPtrs->ExceptionRecord->ExceptionCode,
pExPtrs->ExceptionRecord->ExceptionFlags,
pExPtrs->ExceptionRecord->ExceptionAddress);
FatalAppExit((UINT)-1,lString);
return lRet;
}
int InitAllocCheck(eAllocCheckOutput eOutput, BOOL bSetUnhandledExeptionFilter, ULONG ulShowStackAtAlloc) // will create the filename by itself
{
TCHAR szModName[_MAX_PATH];
if (GetModuleFileName(NULL, szModName, sizeof(szModName)/sizeof(TCHAR)) != 0)
{
_tcscpy(s_szExceptionLogFileName, szModName);
if (eOutput == ACOutput_XML)
_tcscat(s_szExceptionLogFileName, _T(".exp.xml"));
else
_tcscat(s_szExceptionLogFileName, _T(".exp.log"));
if (eOutput == ACOutput_XML)
_tcscat(szModName, _T(".mem.xml-leaks"));
else
_tcscat(szModName, _T(".mem.log"));
}
else
{
if (eOutput == ACOutput_XML)
_tcscpy(szModName, _T("\\mem-leaks.xml-leaks")); // default
else
_tcscpy(szModName, _T("\\mem-leaks.log")); // default
}
if ((bSetUnhandledExeptionFilter != FALSE) && (s_bUnhandledExeptionFilterSet == FALSE) )
{
// set global exception handler (for handling all unhandled exceptions)
SetUnhandledExceptionFilter(CrashHandlerExceptionFilter);
s_bUnhandledExeptionFilterSet = TRUE;
}
return InitAllocCheckWN(eOutput, szModName, ulShowStackAtAlloc);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -