Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

417 lines
9.1 KiB

  1. /*++
  2. Copyright (C) 1999-2001 Microsoft Corporation
  3. Module Name:
  4. Abstract:
  5. History:
  6. --*/
  7. //***************************************************************************
  8. //
  9. // ALLOCTRK.CPP
  10. //
  11. //***************************************************************************
  12. #pragma warning(disable: 4786)
  13. #include <windows.h>
  14. #include <stdio.h>
  15. #include "arena.h"
  16. #include "sync.h"
  17. #include "flexarry.h"
  18. #include <time.h>
  19. #include <stdio.h>
  20. #include <arrtempl.h>
  21. #include <sync.h>
  22. #include <malloc.h>
  23. #include <imagehlp.h>
  24. #include <map>
  25. #include "stackcom.h"
  26. #include "hookheap.h"
  27. #include "alloctrk.h"
  28. void* WINAPI HeapAllocHook(HANDLE hHeap, DWORD dwFlags, DWORD dwSize);
  29. BOOL WINAPI HeapFreeHook(HANDLE hHeap, DWORD dwFlags, void* pBlock);
  30. void* WINAPI HeapReallocHook(HANDLE hHeap, DWORD dwFlags, void* pBlock,
  31. DWORD dwNewSize);
  32. #define NUM_IGNORE_STACK_FRAMES 3
  33. #define MAX_SYMBOL_NAME_LEN 1024
  34. #pragma warning(disable: 4786)
  35. class CAllocationTracker
  36. {
  37. protected:
  38. typedef std::map<PStackRecord, PAllocRecord, CStackRecord::CLess>
  39. TMapByStack;
  40. typedef TMapByStack::iterator TByStackIterator;
  41. TMapByStack m_mapByStack;
  42. typedef std::map<void*, PAllocRecord> TMapByPointer;
  43. typedef TMapByPointer::iterator TByPointerIterator;
  44. TMapByPointer m_mapByPointer;
  45. CCritSec m_cs;
  46. DWORD m_dwTotalInternal;
  47. DWORD m_dwCurrentThread;
  48. DWORD m_dwCurrentId;
  49. HANDLE m_hThread;
  50. DWORD m_dwTotalExternal;
  51. DWORD m_dwTls;
  52. protected:
  53. void RecordInternalAlloc(DWORD dwSize) { m_dwTotalInternal += dwSize;}
  54. void RecordInternalFree(DWORD dwSize) {m_dwTotalInternal -= dwSize;}
  55. CAllocRecord* FindRecord(CStackRecord& Stack);
  56. CAllocRecord* FindRecord(void* p);
  57. static DWORD DumpThread(void* p);
  58. void DumpStatistics();
  59. void InnerDumpStatistics(FILE* f);
  60. public:
  61. CAllocationTracker();
  62. ~CAllocationTracker();
  63. void RecordAllocation(void* p, DWORD dwAlloc);
  64. void RecordDeallocation(void* p, DWORD dwAlloc);
  65. void RecordReallocation(void* pOld, DWORD dwOldSize, void* pNew,
  66. DWORD dwNewSize);
  67. static BOOL IsValidId(CAllocationId Id);
  68. void Start();
  69. void Stop();
  70. BOOL StartInternal();
  71. void EndInternal();
  72. };
  73. CAllocationTracker g_Tracker;
  74. #pragma warning(disable: 4786)
  75. void POLARITY StartTrackingAllocations()
  76. {
  77. g_Tracker.Start();
  78. }
  79. void POLARITY StopTrackingAllocations()
  80. {
  81. g_Tracker.Stop();
  82. }
  83. CAllocationTracker::CAllocationTracker()
  84. : m_dwTotalInternal(0), m_dwCurrentThread(0), m_dwCurrentId(0x80000000)
  85. {
  86. m_dwTls = TlsAlloc();
  87. m_hThread = NULL;
  88. }
  89. void CAllocationTracker::Start()
  90. {
  91. DWORD dwId;
  92. SymInitialize(GetCurrentProcess(), "c:\\winnt\\symbols\\dll;c:\\winnt\\system32\\wbem", TRUE);
  93. m_hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&DumpThread, this, 0, &dwId);
  94. HookHeap(HeapAllocHook, HeapFreeHook, HeapReallocHook);
  95. }
  96. void CAllocationTracker::Stop()
  97. {
  98. TerminateThread(m_hThread, 0);
  99. CloseHandle(m_hThread);
  100. m_hThread = NULL;
  101. }
  102. BOOL CAllocationTracker::IsValidId(CAllocationId Id)
  103. {
  104. return (Id == 0 || (Id & 0x80000000));
  105. }
  106. CAllocationTracker::~CAllocationTracker()
  107. {
  108. TlsFree(m_dwTls);
  109. }
  110. BOOL CAllocationTracker::StartInternal()
  111. {
  112. if(TlsGetValue(m_dwTls))
  113. return FALSE;
  114. else
  115. {
  116. TlsSetValue(m_dwTls, (void*)1);
  117. return TRUE;
  118. }
  119. }
  120. void CAllocationTracker::EndInternal()
  121. {
  122. TlsSetValue(m_dwTls, NULL);
  123. }
  124. void CAllocationTracker::RecordAllocation(void* p, DWORD dwAlloc)
  125. {
  126. if(m_hThread == NULL)
  127. return;
  128. if(!StartInternal())
  129. {
  130. RecordInternalAlloc(dwAlloc);
  131. return;
  132. }
  133. _Lockit l;
  134. m_dwTotalExternal += dwAlloc;
  135. CStackRecord Stack;
  136. Stack.Create(NUM_IGNORE_STACK_FRAMES, TRUE);
  137. CAllocRecord* pRecord = FindRecord(Stack);
  138. if(pRecord == NULL)
  139. {
  140. pRecord = new CAllocRecord(Stack);
  141. //m_setRecords.insert(pRecord);
  142. m_mapByStack[&pRecord->m_Stack] = pRecord;
  143. }
  144. pRecord->AddAlloc(p, dwAlloc);
  145. m_mapByPointer[p] = pRecord;
  146. EndInternal();
  147. }
  148. void CAllocationTracker::RecordReallocation(void* pOld, DWORD dwOldSize,
  149. void* pNew, DWORD dwNewSize)
  150. {
  151. RecordDeallocation(pOld, dwOldSize);
  152. RecordAllocation(pNew, dwNewSize);
  153. }
  154. void CAllocationTracker::RecordDeallocation(void* p, DWORD dwAlloc)
  155. {
  156. if(m_hThread == NULL)
  157. return;
  158. if(!StartInternal())
  159. {
  160. RecordInternalFree(dwAlloc);
  161. return;
  162. }
  163. _Lockit l;
  164. //CInCritSec ics(&m_cs);
  165. TlsSetValue(m_dwTls, (void*)1);
  166. m_dwTotalExternal -= dwAlloc;
  167. CAllocRecord* pRecord = FindRecord(p);
  168. if(pRecord == NULL)
  169. {
  170. // DebugBreak();
  171. EndInternal();
  172. return;
  173. }
  174. pRecord->RemoveAlloc(p, dwAlloc);
  175. if(pRecord->IsEmpty())
  176. {
  177. m_mapByStack.erase(&pRecord->m_Stack);
  178. m_mapByPointer.erase(p);
  179. //m_setRecords.erase(pRecord);
  180. delete pRecord;
  181. }
  182. EndInternal();
  183. }
  184. CAllocRecord* CAllocationTracker::FindRecord(CStackRecord& Stack)
  185. {
  186. TByStackIterator it = m_mapByStack.find(&Stack);
  187. if(it == m_mapByStack.end())
  188. return NULL;
  189. else
  190. return it->second;
  191. }
  192. CAllocRecord* CAllocationTracker::FindRecord(void* p)
  193. {
  194. TByPointerIterator it = m_mapByPointer.find(p);
  195. if(it == m_mapByPointer.end())
  196. return NULL;
  197. else
  198. return it->second;
  199. }
  200. void CAllocationTracker::DumpStatistics()
  201. {
  202. _Lockit l;
  203. FILE* f = fopen("c:\\memdump.bin", "wb");
  204. fwrite(&m_dwTotalInternal, sizeof(DWORD), 1, f);
  205. StartInternal();
  206. InnerDumpStatistics(f);
  207. EndInternal();
  208. fclose(f);
  209. }
  210. void CAllocationTracker::InnerDumpStatistics(FILE* f)
  211. {
  212. SymInitialize(GetCurrentProcess(), "c:\\winnt\\symbols\\dll;c:\\winnt\\system32\\wbem", TRUE);
  213. TByStackIterator it;
  214. for(it = m_mapByStack.begin(); it != m_mapByStack.end(); it++)
  215. {
  216. const CAllocRecord* pRecord = it->second;
  217. if(!pRecord->IsEmpty())
  218. pRecord->Dump(f);
  219. }
  220. DWORD dwZero = 0;
  221. fwrite(&dwZero, sizeof(DWORD), 1, f);
  222. std::map<DWORD, char> mapAddresses;
  223. for(it = m_mapByStack.begin(); it != m_mapByStack.end(); it++)
  224. {
  225. const CAllocRecord* pRecord = it->second;
  226. if(!pRecord->IsEmpty())
  227. {
  228. for(int j = 0; j < pRecord->m_Stack.GetNumItems(); j++)
  229. mapAddresses[(DWORD)pRecord->m_Stack.GetItem(j)] = 0;
  230. }
  231. else
  232. {
  233. DebugBreak();
  234. }
  235. }
  236. BYTE aBuffer[MAX_SYMBOL_NAME_LEN + sizeof(IMAGEHLP_SYMBOL)];
  237. IMAGEHLP_SYMBOL* psymbol = (IMAGEHLP_SYMBOL*)aBuffer;
  238. psymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
  239. psymbol->MaxNameLength = MAX_SYMBOL_NAME_LEN;
  240. IMAGEHLP_MODULE module;
  241. module.SizeOfStruct = sizeof(IMAGEHLP_MODULE);
  242. char szSymbol[2048];
  243. for(std::map<DWORD, char>::iterator it1 = mapAddresses.begin();
  244. it1 != mapAddresses.end(); it1++)
  245. {
  246. void* p = (void*)it1->first;
  247. fwrite(&p, sizeof(DWORD), 1, f);
  248. DWORD dwDisp;
  249. if(SymGetSymFromAddr(GetCurrentProcess(), (DWORD)p, &dwDisp, psymbol))
  250. {
  251. sprintf(szSymbol, "%s+%d(%p) ", psymbol->Name, dwDisp, p);
  252. }
  253. else
  254. {
  255. if(SymGetModuleInfo(GetCurrentProcess(), (DWORD)p, &module))
  256. {
  257. if(SymLoadModule(GetCurrentProcess(), NULL, module.ImageName, module.ModuleName,
  258. module.BaseOfImage, module.ImageSize))
  259. {
  260. if(SymGetSymFromAddr(GetCurrentProcess(), (DWORD)p, &dwDisp, psymbol))
  261. {
  262. sprintf(szSymbol, "%s+%d(%p) ", psymbol->Name, dwDisp, p);
  263. }
  264. else
  265. {
  266. sprintf(szSymbol, "[%s] (%p) [sym: %d (%d)] ", module.LoadedImageName, p,
  267. module.SymType, GetLastError());
  268. }
  269. }
  270. else
  271. {
  272. sprintf(szSymbol, "[%s] (%p) [sym: %d (%d)] ", module.LoadedImageName, p,
  273. module.SymType, GetLastError());
  274. }
  275. }
  276. else
  277. {
  278. sprintf(szSymbol, "%p (%d)", p, GetLastError());
  279. }
  280. }
  281. DWORD dwLen = strlen(szSymbol);
  282. fwrite(&dwLen, sizeof(DWORD), 1, f);
  283. fwrite(szSymbol, 1, dwLen, f);
  284. }
  285. SymCleanup(GetCurrentProcess());
  286. }
  287. DWORD CAllocationTracker::DumpThread(void* p)
  288. {
  289. CAllocationTracker* pThis = (CAllocationTracker*)p;
  290. char szEvent[100];
  291. sprintf(szEvent, "Dump Memory Event %d", GetCurrentProcessId());
  292. HANDLE hEvent = CreateEventA(NULL, FALSE, FALSE, szEvent);
  293. sprintf(szEvent, "Dump Memory Done Event %d", GetCurrentProcessId());
  294. HANDLE hEventDone = CreateEventA(NULL, FALSE, FALSE, szEvent);
  295. while(1)
  296. {
  297. WaitForSingleObject(hEvent, INFINITE);
  298. pThis->DumpStatistics();
  299. SetEvent(hEventDone);
  300. }
  301. return 0;
  302. }
  303. void* WINAPI HeapAllocHook(HANDLE hHeap, DWORD dwFlags, DWORD dwSize)
  304. {
  305. void* pBuffer = CallRealHeapAlloc(hHeap, dwFlags, dwSize);
  306. if(pBuffer)
  307. {
  308. g_Tracker.RecordAllocation(pBuffer, dwSize);
  309. }
  310. return pBuffer;
  311. }
  312. BOOL WINAPI HeapFreeHook(HANDLE hHeap, DWORD dwFlags, void* pBlock)
  313. {
  314. if(pBlock == NULL)
  315. return TRUE;
  316. g_Tracker.RecordDeallocation(pBlock,
  317. HeapSize(hHeap, 0, pBlock));
  318. return CallRealHeapFree(hHeap, dwFlags, pBlock);
  319. }
  320. void* WINAPI HeapReallocHook(HANDLE hHeap, DWORD dwFlags, void* pBlock,
  321. DWORD dwNewSize)
  322. {
  323. BOOL bStarted = g_Tracker.StartInternal();
  324. DWORD dwPrevSize = HeapSize(hHeap, 0, pBlock);
  325. void* pNewBlock = CallRealHeapRealloc(hHeap, dwFlags, pBlock, dwNewSize);
  326. if(pNewBlock == NULL)
  327. return NULL;
  328. if(bStarted)
  329. g_Tracker.EndInternal();
  330. g_Tracker.RecordReallocation(pBlock, dwPrevSize, pNewBlock, dwNewSize);
  331. return pNewBlock;
  332. }