📄 stackwalker.cpp
字号:
#endif
static void AllocHashInit(void) {
memset(AllocHashTable, 0, sizeof(AllocHashTable));
AllocHashEntries = 0;
AllocHashCollisions = 0;
AllocHashFreed = 0;
AllocHashCurrentCount = 0;
AllocHashMaxUsed = 0;
AllocHashMaxCollisions = 0;
AllocHashCurrentCollisions = 0;
#ifdef WITH_IMALLOC_SPY
memset(IMallocHashTable, 0, sizeof(IMallocHashTable));
IMallocHashEntries = 0;
IMallocHashCollisions = 0;
IMallocHashFreed = 0;
IMallocHashCurrentCount = 0;
IMallocHashMaxUsed = 0;
IMallocHashMaxCollisions = 0;
IMallocHashCurrentCollisions = 0;
#endif
return;
} // AllocHashInit
// AllocHashDeinit
// Returns the number of bytes, that are not freed (leaks)
static ULONG AllocHashDeinit(void) {
ULONG ulRet = 0;
BOOL bAppend = g_CallstackOutputType != ACOutput_XML;
AllocCheckFileOpen(bAppend); // open global log-file
if (g_CallstackOutputType == ACOutput_XML)
{
_ftprintf(g_fFile, _T("<MEMREPORT "));
WriteDateTime(g_fFile, TRUE);
_ftprintf(g_fFile, _T(">\n"));
}
else
{
_ftprintf(g_fFile, _T("\n##### Memory Report ########################################\n"));
WriteDateTime(g_fFile);
_ftprintf(g_fFile, _T("\n"));
}
#ifndef HASH_ENTRY_REMOVE_AT_FREE
// output the used memory
if (g_CallstackOutputType != ACOutput_XML)
_ftprintf(g_fFile, _T("##### Memory used: #########################################\n"));
AllocHashOut(g_fFile);
#endif
// output the Memoty leaks
if (g_CallstackOutputType != ACOutput_XML)
_ftprintf(g_fFile, _T("\n##### Leaks: ###############################################\n"));
ulRet = AllocHashOutLeaks(g_fFile);
if (g_CallstackOutputType == ACOutput_Advanced)
{
// output some statistics from the hash-table
_ftprintf(g_fFile, _T("***** Hash-Table statistics:\n"));
_ftprintf(g_fFile, _T(" Table-Size: %i\n"), ALLOC_HASH_ENTRIES);
_ftprintf(g_fFile, _T(" Inserts: %i\n"), AllocHashEntries);
_ftprintf(g_fFile, _T(" Freed: %i\n"), AllocHashFreed);
_ftprintf(g_fFile, _T(" Sum Collisions: %i\n"), AllocHashCollisions);
_ftprintf(g_fFile, _T("\n"));
_ftprintf(g_fFile, _T(" Max used: %i\n"), AllocHashMaxUsed);
_ftprintf(g_fFile, _T(" Max Collisions: %i\n"), AllocHashMaxCollisions);
}
// Free Hash-Table
ULONG ulTemp;
AllocHashEntryType *pHashEntry = NULL;
AllocHashEntryType *pHashEntryOld = NULL;
// Now, free my own memory
for(ulTemp = 0; ulTemp < ALLOC_HASH_ENTRIES; ulTemp++) {
pHashEntry = &AllocHashTable[ulTemp];
while(pHashEntry != NULL) {
pHashEntryOld = pHashEntry;
pHashEntry = pHashEntry->Next;
if (pHashEntryOld != &AllocHashTable[ulTemp]) {
// now free the dynamically allocated memory
free(pHashEntryOld);
}
} // while
} // for
// empty the hash-table
memset(AllocHashTable, 0, sizeof(AllocHashTable));
#ifdef WITH_IMALLOC_SPY
// output the Memoty leaks
if (g_CallstackOutputType != ACOutput_XML)
_ftprintf(g_fFile, _T("\n##### COM-Leaks: ###############################################\n"));
ulRet = IMallocHashOutLeaks(g_fFile);
if (g_CallstackOutputType == ACOutput_Advanced)
{
// output some statistics from the hash-table
_ftprintf(g_fFile, _T("***** Hash-Table statistics:\n"));
_ftprintf(g_fFile, _T(" Table-Size: %i\n"), ALLOC_HASH_ENTRIES);
_ftprintf(g_fFile, _T(" Inserts: %i\n"), IMallocHashEntries);
_ftprintf(g_fFile, _T(" Freed: %i\n"), IMallocHashFreed);
_ftprintf(g_fFile, _T(" Sum Collisions: %i\n"), IMallocHashCollisions);
_ftprintf(g_fFile, _T("\n"));
_ftprintf(g_fFile, _T(" Max used: %i\n"), IMallocHashMaxUsed);
_ftprintf(g_fFile, _T(" Max Collisions: %i\n"), IMallocHashMaxCollisions);
}
// Free Hash-Table
//ULONG ulTemp;
IMallocHashEntryType *pIMHashEntry, *pIMHashEntryOld;
// Gehe jeden Eintrag durch und gebe ihn frei
for(ulTemp = 0; ulTemp < ALLOC_HASH_ENTRIES; ulTemp++) {
pIMHashEntry = &IMallocHashTable[ulTemp];
while(pHashEntry != NULL) {
pIMHashEntryOld = pIMHashEntry;
pIMHashEntry = pIMHashEntry->Next;
if (pIMHashEntryOld != &IMallocHashTable[ulTemp]) {
// es ist dynamischer Speicher, gebe ihn also frei:
_free_dbg(pIMHashEntryOld, _CRT_BLOCK);
}
} // while
} // for
// L?che die gesamte Hash-Tabelle
memset(IMallocHashTable, 0, sizeof(IMallocHashTable));
#endif
if (g_CallstackOutputType == ACOutput_XML)
_ftprintf(g_fFile, _T("</MEMREPORT>\n"));
return ulRet;
} // AllocHashDeinit
// AllocHashFunction
// The has-function (very simple)
static inline ULONG AllocHashFunction(long lRequestID) {
// I couldn磘 find any better and faster
return lRequestID % ALLOC_HASH_ENTRIES;
} // AllocHashFunction
// AllocHashInsert
// lRequestID: Key-Word (RequestID from AllocHook)
// pContext: Context-Record, for retrieving Callstack (EIP and EBP is only needed)
// nDataSize: How many bytes
static void AllocHashInsert(long lRequestID, CONTEXT &Context, size_t nDataSize) {
ULONG HashIdx;
AllocHashEntryType *pHashEntry;
// change statistical data
AllocHashEntries++;
AllocHashCurrentCount++;
if (AllocHashCurrentCount > AllocHashMaxUsed)
AllocHashMaxUsed = AllocHashCurrentCount;
// generate hash-value
HashIdx = AllocHashFunction(lRequestID);
pHashEntry = &AllocHashTable[HashIdx];
if (pHashEntry->lRequestID == 0) {
// Entry is empty...
}
else {
// Entry is not empy! make a list of entries for this hash value...
// change statistical data
// if this happens often, you should increase the hah size or change the heash-function;
// to fasten the allocation time
AllocHashCollisions++;
AllocHashCurrentCollisions++;
if (AllocHashCurrentCollisions > AllocHashMaxCollisions)
AllocHashMaxCollisions = AllocHashCurrentCollisions;
while(pHashEntry->Next != NULL) {
pHashEntry = pHashEntry->Next;
}
pHashEntry->Next = (AllocHashEntryType*) calloc(sizeof(AllocHashEntryType), 1);
pHashEntry = pHashEntry->Next;
}
pHashEntry->lRequestID = lRequestID; // Key-Word
pHashEntry->nDataSize = nDataSize;
pHashEntry->Next = NULL;
// Get EIP and save it in the record
pHashEntry->dwEIPOffset = Context.Eip;
if (ReadProcessMemory(GetCurrentProcess(), (LPCVOID) Context.Eip, &(pHashEntry->pcEIPAddr), MAX_EIP_LEN_BUF, &(pHashEntry->dwEIPLen)) == 0) {
// Could not read memory... remove everything...
memset(pHashEntry->pcEIPAddr, 0, MAX_EIP_LEN_BUF);
pHashEntry->dwEIPLen = 0;
pHashEntry->dwEIPOffset = 0;
}
// Get ESP and save it in the record
pHashEntry->dwESPOffset = Context.Ebp;
if (ReadProcessMemory(GetCurrentProcess(), (LPCVOID) Context.Ebp, &(pHashEntry->pcESPAddr), MAX_ESP_LEN_BUF, &(pHashEntry->dwESPLen)) == 0) {
// Could not read memory... remove everything...
memset(pHashEntry->pcESPAddr, 0, MAX_ESP_LEN_BUF);
pHashEntry->dwESPLen = 0;
pHashEntry->dwESPOffset = 0;
// Check if I tried to read too much...
if (GetLastError() == ERROR_PARTIAL_COPY)
{
// ask how many I can read:
MEMORY_BASIC_INFORMATION MemBuffer;
DWORD dwRet = VirtualQuery((LPCVOID) Context.Ebp, &MemBuffer, sizeof(MemBuffer));
if (dwRet > 0)
{
// calculate the length
DWORD len = ((DWORD) MemBuffer.BaseAddress + MemBuffer.RegionSize) - Context.Ebp;
if ( (len > 0) && (len < MAX_ESP_LEN_BUF) )
{
// try to read it again (with the shorter length)
if (ReadProcessMemory(GetCurrentProcess(), (LPCVOID) Context.Ebp, &(pHashEntry->pcESPAddr), len, &(pHashEntry->dwESPLen)) == 0)
{
// ok, now everything goes wrong... remove it...
memset(pHashEntry->pcESPAddr, 0, MAX_ESP_LEN_BUF);
pHashEntry->dwESPLen = 0;
pHashEntry->dwESPOffset = 0;
}
else
{
pHashEntry->dwESPOffset = Context.Ebp;
}
}
} // VirtualQuery was successfully
} // ERROR_PARTIAL_COPY
}
}
// AllocHashFind
// If ALLOC_ENTRY_NOT_FOUND is returned, the Key was not found!
// If the Key was found, a pointer to the entry is returned
static AllocHashEntryType *AllocHashFind(long lRequestID) {
ULONG HashIdx;
AllocHashEntryType *pHashEntry;
// get the Hash-Value
HashIdx = AllocHashFunction(lRequestID);
// Just do some simple checks:
_ASSERTE(HashIdx < ALLOC_HASH_ENTRIES);
pHashEntry = &AllocHashTable[HashIdx];
while(pHashEntry != NULL) {
if (pHashEntry->lRequestID == lRequestID) {
return pHashEntry;
}
pHashEntry = pHashEntry->Next;
}
// entry was not found!
return (AllocHashEntryType*) ALLOC_ENTRY_NOT_FOUND;
} // AllocHashFind
// AllocHashRemove
// Return: FALSE (0) : Key was found and removed/marked
// TRUE (!=0): Key was not found
static BOOL AllocHashRemove(long lRequestID) {
ULONG HashIdx;
AllocHashEntryType *pHashEntry, *pHashEntryLast;
// get the Hash-Value
HashIdx = AllocHashFunction(lRequestID);
// Just do some simple checks:
_ASSERTE(HashIdx < ALLOC_HASH_ENTRIES);
pHashEntryLast = NULL;
pHashEntry = &AllocHashTable[HashIdx];
while(pHashEntry != NULL) {
if (pHashEntry->lRequestID == lRequestID) {
#ifdef HASH_ENTRY_REMOVE_AT_FREE
AllocHashFreed++;
AllocHashCurrentCount--;
// release my memory
if (pHashEntryLast == NULL) {
// It is an entry in the table, so do not release this memory
if (pHashEntry->Next == NULL) {
// It was the last entry, so empty the table entry
memset(&AllocHashTable[HashIdx], 0, sizeof(AllocHashTable[HashIdx]));
}
else {
// There are some more entries, so shorten the list
AllocHashEntryType *pTmp = pHashEntry->Next;
*pHashEntry = *(pHashEntry->Next);
free(pTmp);
}
return TRUE;
}
else {
// now, I am in an dynamic allocated entry
// it was a collision, so decrease the current collision count
AllocHashCurrentCollisions--;
pHashEntryLast->Next = pHashEntry->Next;
free(pHashEntry);
return TRUE;
}
#else
// increase the Remove-Count and let the objet stay in memory
pHashEntry->cRemovedFlag++;
return TRUE;
#endif
}
pHashEntryLast = pHashEntry;
pHashEntry = pHashEntry->Next;
}
// if we are here, we could not find the RequestID
return FALSE;
}
// ReadProcMemoryFromHash
// Callback-Funtion for StackWalk for my own CallStack from the Hash-Table-Entries
static BOOL __stdcall ReadProcMemoryFromHash(HANDLE hRequestID, DWORD64 lpBaseAddress, PVOID lpBuffer, DWORD nSize, PDWORD lpNumberOfBytesRead) {
// Try to find the RequestID
AllocHashEntryType *pHashEntry;
*lpNumberOfBytesRead = 0;
pHashEntry = AllocHashFind((LONG) hRequestID);
if (pHashEntry == (AllocHashEntryType*) ALLOC_ENTRY_NOT_FOUND) {
// Not found, so I cannot return any memory
*lpNumberOfBytesRead = 0;
return FALSE;
}
if ( ((DWORD) lpBaseAddress >= pHashEntry->dwESPOffset) && ((DWORD) lpBaseAddress <= (pHashEntry->dwESPOffset+pHashEntry->dwESPLen)) ) {
// Memory is located in ESP:
// Calculate the offset
DWORD dwOffset = (DWORD) lpBaseAddress - pHashEntry->dwESPOffset;
DWORD dwSize = __min(nSize, MAX_ESP_LEN_BUF-dwOffset);
memcpy(lpBuffer, &(pHashEntry->pcESPAddr[dwOffset]), dwSize);
*lpNumberOfBytesRead = dwSize;
if (dwSize != nSize)
return FALSE;
}
if ( ((DWORD) lpBaseAddress >= pHashEntry->dwEIPOffset) && ((DWORD) lpBaseAddress <= (pHashEntry->dwEIPOffset+pHashEntry->dwEIPLen)) ) {
// Memory is located in EIP:
// Calculate the offset
DWORD dwOffset = (DWORD) lpBaseAddress - pHashEntry->dwEIPOffset;
DWORD dwSize = __min(nSize, MAX_ESP_LEN_BUF-dwOffset);
memcpy(lpBuffer, &(pHashEntry->pcEIPAddr[dwOffset]), dwSize);
*lpNumberOfBytesRead = dwSize;
if (dwSize != nSize)
return FALSE;
}
if (*lpNumberOfBytesRead == 0) // Memory could not be found
return FALSE;
return TRUE;
}
// AllocHashOutLeaks
// Write all Memory (with callstack) which was not freed yet
// Returns the number of bytes, that are not freed (leaks)
ULONG AllocHashOutLeaks(FILE *fFile) {
ULONG ulTemp;
AllocHashEntryType *pHashEntry;
ULONG ulCount = 0;
ULONG ulLeaksByte = 0;
// Move throu every entry
for(ulTemp = 0; ulTemp < ALLOC_HASH_ENTRIES; ulTemp++) {
pHashEntry = &AllocHashTable[ulTemp];
if (pHashEntry->lRequestID != 0) {
while(pHashEntry != NULL) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -