|
|
/*++
Copyright (C) 1999-2001 Microsoft Corporation
Module Name:
Abstract:
History:
--*/
//***************************************************************************
//
// ALLOCTRK.CPP
//
//***************************************************************************
#pragma warning(disable: 4786)
#include <windows.h>
#include <stdio.h>
#include "arena.h"
#include "sync.h"
#include "flexarry.h"
#include <time.h>
#include <stdio.h>
#include <arrtempl.h>
#include <sync.h>
#include <malloc.h>
#include <imagehlp.h>
#include <map>
#include "stackcom.h"
#include "hookheap.h"
#include "alloctrk.h"
void* WINAPI HeapAllocHook(HANDLE hHeap, DWORD dwFlags, DWORD dwSize); BOOL WINAPI HeapFreeHook(HANDLE hHeap, DWORD dwFlags, void* pBlock); void* WINAPI HeapReallocHook(HANDLE hHeap, DWORD dwFlags, void* pBlock, DWORD dwNewSize);
#define NUM_IGNORE_STACK_FRAMES 3
#define MAX_SYMBOL_NAME_LEN 1024
#pragma warning(disable: 4786)
class CAllocationTracker { protected: typedef std::map<PStackRecord, PAllocRecord, CStackRecord::CLess> TMapByStack; typedef TMapByStack::iterator TByStackIterator; TMapByStack m_mapByStack;
typedef std::map<void*, PAllocRecord> TMapByPointer; typedef TMapByPointer::iterator TByPointerIterator; TMapByPointer m_mapByPointer;
CCritSec m_cs; DWORD m_dwTotalInternal; DWORD m_dwCurrentThread; DWORD m_dwCurrentId; HANDLE m_hThread; DWORD m_dwTotalExternal; DWORD m_dwTls;
protected: void RecordInternalAlloc(DWORD dwSize) { m_dwTotalInternal += dwSize;} void RecordInternalFree(DWORD dwSize) {m_dwTotalInternal -= dwSize;}
CAllocRecord* FindRecord(CStackRecord& Stack); CAllocRecord* FindRecord(void* p); static DWORD DumpThread(void* p);
void DumpStatistics(); void InnerDumpStatistics(FILE* f);
public: CAllocationTracker(); ~CAllocationTracker(); void RecordAllocation(void* p, DWORD dwAlloc); void RecordDeallocation(void* p, DWORD dwAlloc); void RecordReallocation(void* pOld, DWORD dwOldSize, void* pNew, DWORD dwNewSize);
static BOOL IsValidId(CAllocationId Id); void Start(); void Stop();
BOOL StartInternal(); void EndInternal(); };
CAllocationTracker g_Tracker; #pragma warning(disable: 4786)
void POLARITY StartTrackingAllocations() { g_Tracker.Start(); }
void POLARITY StopTrackingAllocations() { g_Tracker.Stop(); }
CAllocationTracker::CAllocationTracker() : m_dwTotalInternal(0), m_dwCurrentThread(0), m_dwCurrentId(0x80000000) { m_dwTls = TlsAlloc(); m_hThread = NULL; }
void CAllocationTracker::Start() { DWORD dwId; SymInitialize(GetCurrentProcess(), "c:\\winnt\\symbols\\dll;c:\\winnt\\system32\\wbem", TRUE); m_hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&DumpThread, this, 0, &dwId); HookHeap(HeapAllocHook, HeapFreeHook, HeapReallocHook); }
void CAllocationTracker::Stop() { TerminateThread(m_hThread, 0); CloseHandle(m_hThread); m_hThread = NULL; }
BOOL CAllocationTracker::IsValidId(CAllocationId Id) { return (Id == 0 || (Id & 0x80000000)); }
CAllocationTracker::~CAllocationTracker() { TlsFree(m_dwTls); }
BOOL CAllocationTracker::StartInternal() { if(TlsGetValue(m_dwTls)) return FALSE; else { TlsSetValue(m_dwTls, (void*)1); return TRUE; } }
void CAllocationTracker::EndInternal() { TlsSetValue(m_dwTls, NULL); }
void CAllocationTracker::RecordAllocation(void* p, DWORD dwAlloc) { if(m_hThread == NULL) return;
if(!StartInternal()) { RecordInternalAlloc(dwAlloc); return; }
_Lockit l; m_dwTotalExternal += dwAlloc;
CStackRecord Stack; Stack.Create(NUM_IGNORE_STACK_FRAMES, TRUE);
CAllocRecord* pRecord = FindRecord(Stack); if(pRecord == NULL) { pRecord = new CAllocRecord(Stack); //m_setRecords.insert(pRecord);
m_mapByStack[&pRecord->m_Stack] = pRecord; }
pRecord->AddAlloc(p, dwAlloc); m_mapByPointer[p] = pRecord; EndInternal(); }
void CAllocationTracker::RecordReallocation(void* pOld, DWORD dwOldSize, void* pNew, DWORD dwNewSize) { RecordDeallocation(pOld, dwOldSize); RecordAllocation(pNew, dwNewSize); }
void CAllocationTracker::RecordDeallocation(void* p, DWORD dwAlloc) { if(m_hThread == NULL) return;
if(!StartInternal()) { RecordInternalFree(dwAlloc); return; }
_Lockit l; //CInCritSec ics(&m_cs);
TlsSetValue(m_dwTls, (void*)1); m_dwTotalExternal -= dwAlloc;
CAllocRecord* pRecord = FindRecord(p); if(pRecord == NULL) { // DebugBreak();
EndInternal(); return; }
pRecord->RemoveAlloc(p, dwAlloc);
if(pRecord->IsEmpty()) { m_mapByStack.erase(&pRecord->m_Stack); m_mapByPointer.erase(p); //m_setRecords.erase(pRecord);
delete pRecord; }
EndInternal(); }
CAllocRecord* CAllocationTracker::FindRecord(CStackRecord& Stack) { TByStackIterator it = m_mapByStack.find(&Stack); if(it == m_mapByStack.end()) return NULL; else return it->second; } CAllocRecord* CAllocationTracker::FindRecord(void* p) { TByPointerIterator it = m_mapByPointer.find(p); if(it == m_mapByPointer.end()) return NULL; else return it->second; }
void CAllocationTracker::DumpStatistics() { _Lockit l; FILE* f = fopen("c:\\memdump.bin", "wb");
fwrite(&m_dwTotalInternal, sizeof(DWORD), 1, f);
StartInternal(); InnerDumpStatistics(f); EndInternal(); fclose(f); }
void CAllocationTracker::InnerDumpStatistics(FILE* f) { SymInitialize(GetCurrentProcess(), "c:\\winnt\\symbols\\dll;c:\\winnt\\system32\\wbem", TRUE);
TByStackIterator it; for(it = m_mapByStack.begin(); it != m_mapByStack.end(); it++) { const CAllocRecord* pRecord = it->second; if(!pRecord->IsEmpty()) pRecord->Dump(f); } DWORD dwZero = 0; fwrite(&dwZero, sizeof(DWORD), 1, f);
std::map<DWORD, char> mapAddresses; for(it = m_mapByStack.begin(); it != m_mapByStack.end(); it++) { const CAllocRecord* pRecord = it->second; if(!pRecord->IsEmpty()) { for(int j = 0; j < pRecord->m_Stack.GetNumItems(); j++) mapAddresses[(DWORD)pRecord->m_Stack.GetItem(j)] = 0; } else { DebugBreak(); } }
BYTE aBuffer[MAX_SYMBOL_NAME_LEN + sizeof(IMAGEHLP_SYMBOL)]; IMAGEHLP_SYMBOL* psymbol = (IMAGEHLP_SYMBOL*)aBuffer; psymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL); psymbol->MaxNameLength = MAX_SYMBOL_NAME_LEN;
IMAGEHLP_MODULE module; module.SizeOfStruct = sizeof(IMAGEHLP_MODULE);
char szSymbol[2048];
for(std::map<DWORD, char>::iterator it1 = mapAddresses.begin(); it1 != mapAddresses.end(); it1++) { void* p = (void*)it1->first; fwrite(&p, sizeof(DWORD), 1, f);
DWORD dwDisp; if(SymGetSymFromAddr(GetCurrentProcess(), (DWORD)p, &dwDisp, psymbol)) { sprintf(szSymbol, "%s+%d(%p) ", psymbol->Name, dwDisp, p); } else { if(SymGetModuleInfo(GetCurrentProcess(), (DWORD)p, &module)) { if(SymLoadModule(GetCurrentProcess(), NULL, module.ImageName, module.ModuleName, module.BaseOfImage, module.ImageSize)) { if(SymGetSymFromAddr(GetCurrentProcess(), (DWORD)p, &dwDisp, psymbol)) { sprintf(szSymbol, "%s+%d(%p) ", psymbol->Name, dwDisp, p); } else { sprintf(szSymbol, "[%s] (%p) [sym: %d (%d)] ", module.LoadedImageName, p, module.SymType, GetLastError()); } } else { sprintf(szSymbol, "[%s] (%p) [sym: %d (%d)] ", module.LoadedImageName, p, module.SymType, GetLastError()); } } else { sprintf(szSymbol, "%p (%d)", p, GetLastError()); } }
DWORD dwLen = strlen(szSymbol); fwrite(&dwLen, sizeof(DWORD), 1, f); fwrite(szSymbol, 1, dwLen, f); }
SymCleanup(GetCurrentProcess()); }
DWORD CAllocationTracker::DumpThread(void* p) { CAllocationTracker* pThis = (CAllocationTracker*)p;
char szEvent[100]; sprintf(szEvent, "Dump Memory Event %d", GetCurrentProcessId()); HANDLE hEvent = CreateEventA(NULL, FALSE, FALSE, szEvent);
sprintf(szEvent, "Dump Memory Done Event %d", GetCurrentProcessId()); HANDLE hEventDone = CreateEventA(NULL, FALSE, FALSE, szEvent); while(1) { WaitForSingleObject(hEvent, INFINITE); pThis->DumpStatistics(); SetEvent(hEventDone); } return 0; }
void* WINAPI HeapAllocHook(HANDLE hHeap, DWORD dwFlags, DWORD dwSize) { void* pBuffer = CallRealHeapAlloc(hHeap, dwFlags, dwSize); if(pBuffer) { g_Tracker.RecordAllocation(pBuffer, dwSize); } return pBuffer; }
BOOL WINAPI HeapFreeHook(HANDLE hHeap, DWORD dwFlags, void* pBlock) { if(pBlock == NULL) return TRUE;
g_Tracker.RecordDeallocation(pBlock, HeapSize(hHeap, 0, pBlock));
return CallRealHeapFree(hHeap, dwFlags, pBlock); } void* WINAPI HeapReallocHook(HANDLE hHeap, DWORD dwFlags, void* pBlock, DWORD dwNewSize) { BOOL bStarted = g_Tracker.StartInternal();
DWORD dwPrevSize = HeapSize(hHeap, 0, pBlock); void* pNewBlock = CallRealHeapRealloc(hHeap, dwFlags, pBlock, dwNewSize); if(pNewBlock == NULL) return NULL;
if(bStarted) g_Tracker.EndInternal(); g_Tracker.RecordReallocation(pBlock, dwPrevSize, pNewBlock, dwNewSize); return pNewBlock; }
|