Leaked source code of windows server 2003
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.

447 lines
14 KiB

  1. /*++
  2. Copyright (c) 1992-2000 Microsoft Corporation
  3. Module Name:
  4. dpa.c
  5. Abstract:
  6. Module to dump pool allocations
  7. Environment:
  8. User Mode.
  9. Revision History:
  10. Code taken from userkdx.dll ( windows\core\ntuser\kdexts\userexts.c )
  11. Kshitiz K. Sharma (kksharma) 1/11/2002
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. #define RECORD_STACK_TRACE_SIZE 6
  16. #define POOL_ALLOC_TRACE_SIZE 8
  17. /*
  18. * Pool allocation flags
  19. */
  20. #define POOL_HEAVY_ALLOCS 0x00000001 // use HeavyAllocPool
  21. #define POOL_CAPTURE_STACK 0x00000002 // stack traces are captured
  22. #define POOL_FAIL_ALLOCS 0x00000004 // fail pool allocations
  23. #define POOL_FAIL_BY_INDEX 0x00000008 // fail allocations by index
  24. #define POOL_TAIL_CHECK 0x00000010 // append tail string
  25. #define POOL_KEEP_FREE_RECORD 0x00000020 // keep a list with last x frees
  26. #define POOL_KEEP_FAIL_RECORD 0x00000040 // keep a list with last x failed a
  27. #define POOL_BREAK_FOR_LEAKS 0x00000080 // break on pool leaks (remote sess
  28. enum DumpPolllAllocOptions {
  29. DpaCurrentAllocStats = 1,
  30. DpaAllCurrentAllocs = 2,
  31. DpaIncludeStack = 4,
  32. DpaFailedAllocs = 8,
  33. DpaFreePool = 0x10,
  34. DpaContainsPointer = 0x20,
  35. };
  36. VOID PrintStackTrace(
  37. ULONG64 pStackTrace,
  38. int tracesCount)
  39. {
  40. int traceInd;
  41. ULONG64 dwOffset, pSymbol;
  42. CHAR symbol[MAX_PATH];
  43. DWORD dwPointerSize = DBG_PTR_SIZE;
  44. for (traceInd = 0; traceInd < tracesCount; traceInd++) {
  45. ReadPointer(pStackTrace, &pSymbol);
  46. if (pSymbol == 0) {
  47. break;
  48. }
  49. GetSymbol(pSymbol, symbol, &dwOffset);
  50. if (*symbol) {
  51. dprintf("\t%s", symbol);
  52. if (dwOffset) {
  53. dprintf("+%p\n", dwOffset);
  54. } else {
  55. dprintf("\n");
  56. }
  57. }
  58. pStackTrace += dwPointerSize;
  59. }
  60. dprintf("\n");
  61. }
  62. void
  63. DisplayDpaUsage(void)
  64. {
  65. dprintf("dpa -cvsfrp - Dump pool allocations\n"
  66. " dpa -c - dump current pool allocations statistics\n"
  67. " dpa -v - dump all the current pool allocations\n"
  68. " dpa -vs - include stack traces\n"
  69. " dpa -f - dump failed allocations\n"
  70. " dpa -r - dump free pool\n"
  71. " dpa -p <ptr> - dump the allocation containing pointer 'ptr'\n");
  72. }
  73. BOOL
  74. GetDpaArgs(
  75. PCHAR Args,
  76. PULONG pOptions,
  77. PULONG64 pAllocPtr
  78. )
  79. {
  80. *pOptions = 0;
  81. *pAllocPtr = 0;
  82. if (!Args)
  83. {
  84. return FALSE;
  85. }
  86. while (*Args)
  87. {
  88. if (*Args == '-' || *Args == '/')
  89. {
  90. ++Args;
  91. switch (*Args)
  92. {
  93. case 'c':
  94. *pOptions |= DpaCurrentAllocStats;
  95. break;
  96. case 'f':
  97. *pOptions |= DpaFailedAllocs;
  98. break;
  99. case 'p':
  100. *pOptions |= DpaContainsPointer;
  101. ++Args;
  102. GetExpressionEx(Args, pAllocPtr, &Args);
  103. break;
  104. case 'r':
  105. *pOptions |= DpaFreePool;
  106. break;
  107. case 'v':
  108. if (*(Args+1) == 's')
  109. {
  110. *pOptions |= DpaIncludeStack;
  111. } else
  112. {
  113. *pOptions |= DpaAllCurrentAllocs;
  114. }
  115. break;
  116. default:
  117. dprintf("Unknown Arg %c.\n", *Args ? *Args : ' ');
  118. return FALSE;
  119. }
  120. }
  121. if (*Args)
  122. {
  123. ++Args;
  124. }
  125. }
  126. return TRUE;
  127. }
  128. /***************************************************************************\
  129. * dpa - dump pool allocations
  130. *
  131. * Dump pool allocations.
  132. *
  133. * 12-27-96 CLupu Created
  134. \***************************************************************************/
  135. BOOL
  136. DumpPoolAllocs(
  137. ULONG opts,
  138. ULONG64 param1
  139. )
  140. {
  141. HRESULT Hr = S_OK;
  142. try {
  143. ULONG64 pAllocList;
  144. DWORD dwPoolFlags;
  145. DWORD dwSize = GetTypeSize("win32k!tagWin32PoolHead");
  146. BOOL bIncludeStackTrace = FALSE;
  147. dwPoolFlags = GetUlongValue( "win32k!gdwPoolFlags" );
  148. if (!(dwPoolFlags & POOL_HEAVY_ALLOCS)) {
  149. dprintf("win32k.sys doesn't have pool instrumentation !\n");
  150. return FALSE;
  151. }
  152. if (opts & DpaIncludeStack) {
  153. if (dwPoolFlags & POOL_CAPTURE_STACK) {
  154. bIncludeStackTrace = TRUE;
  155. } else {
  156. dprintf("win32k.sys doesn't have stack traces enabled for pool allocations\n");
  157. }
  158. }
  159. pAllocList = GetExpression( "win32k!gAllocList" );
  160. if (!pAllocList) {
  161. dprintf("Could not get Win32AllocStats structure win32k!gAllocList\n");
  162. return FALSE;
  163. }
  164. InitTypeRead(pAllocList, win32k!tagWin32AllocStats);
  165. if (opts & DpaCurrentAllocStats) {
  166. dprintf("- pool instrumentation enabled for win32k.sys\n");
  167. if (dwPoolFlags & POOL_CAPTURE_STACK) {
  168. dprintf("- stack traces enabled for pool allocations\n");
  169. } else {
  170. dprintf("- stack traces disabled for pool allocations\n");
  171. }
  172. if (dwPoolFlags & POOL_KEEP_FAIL_RECORD) {
  173. dprintf("- records of failed allocations enabled\n");
  174. } else {
  175. dprintf("- records of failed allocations disabled\n");
  176. }
  177. if (dwPoolFlags & POOL_KEEP_FREE_RECORD) {
  178. dprintf("- records of free pool enabled\n");
  179. } else {
  180. dprintf("- records of free pool disabled\n");
  181. }
  182. dprintf("\n");
  183. dprintf(" CrtM CrtA MaxM MaxA Head\n");
  184. dprintf("------------|------------|------------|------------|------------|\n");
  185. InitTypeRead(pAllocList, win32k!tagWin32AllocStats);
  186. dprintf(" 0x%08x 0x%08x 0x%08x 0x%08x 0x%I64x\n",
  187. (ULONG)ReadField(dwCrtMem),
  188. (ULONG)ReadField(dwCrtAlloc),
  189. (ULONG)ReadField(dwMaxMem),
  190. (ULONG)ReadField(dwMaxAlloc),
  191. ReadField(pHead));
  192. return TRUE;
  193. }
  194. InitTypeRead(pAllocList, win32k!tagWin32AllocStats);
  195. if (opts & DpaFailedAllocs) {
  196. DWORD dwFailRecordCrtIndex, dwFailRecordTotalFailures;
  197. DWORD dwFailRecords, Ind, dwFailuresToDump;
  198. ULONG64 pFailRecord, pFailRecordOrg;
  199. if (!(dwPoolFlags & POOL_KEEP_FAIL_RECORD)) {
  200. dprintf("win32k.sys doesn't have records of failed allocations!\n");
  201. return TRUE;
  202. }
  203. dwFailRecordTotalFailures = GetUlongValue( "win32k!gdwFailRecordTotalFailures");
  204. if (dwFailRecordTotalFailures == 0) {
  205. dprintf("No allocation failure in win32k.sys!\n");
  206. return TRUE;
  207. }
  208. dwFailRecordCrtIndex = GetUlongValue( "win32k!gdwFailRecordCrtIndex");
  209. dwFailRecords = GetUlongValue( "win32k!gdwFailRecords");
  210. if (dwFailRecordTotalFailures < dwFailRecords) {
  211. dwFailuresToDump = dwFailRecordTotalFailures;
  212. } else {
  213. dwFailuresToDump = dwFailRecords;
  214. }
  215. pFailRecord = GetPointerValue( "win32k!gparrFailRecord");
  216. if (!pFailRecord) {
  217. dprintf("\nCouldn't get gparrFailRecord!\n");
  218. return FALSE;
  219. }
  220. pFailRecordOrg = pFailRecord;
  221. dprintf("\nFailures to dump : %d\n\n", dwFailuresToDump);
  222. for (Ind = 0; Ind < dwFailuresToDump; Ind++) {
  223. DWORD tag[2] = {0, 0};
  224. if (dwFailRecordCrtIndex == 0) {
  225. dwFailRecordCrtIndex = dwFailRecords - 1;
  226. } else {
  227. dwFailRecordCrtIndex--;
  228. }
  229. pFailRecord = pFailRecordOrg + dwFailRecordCrtIndex;
  230. InitTypeRead(pFailRecord, win32k!tagPOOLRECORD);
  231. tag[0] = (DWORD)(DWORD_PTR)ReadField(ExtraData);
  232. dprintf("Allocation for tag '%s' size 0x%x failed\n",
  233. tag,
  234. (ULONG)ReadField(size));
  235. PrintStackTrace(ReadField(pTrace), RECORD_STACK_TRACE_SIZE);
  236. if (CheckControlC())
  237. {
  238. return FALSE;
  239. }
  240. }
  241. }
  242. InitTypeRead(pAllocList, win32k!tagWin32AllocStats);
  243. if (opts & DpaFreePool) {
  244. DWORD dwFreeRecordCrtIndex, dwFreeRecordTotalFrees;
  245. DWORD dwFreeRecords, Ind, dwFreesToDump;
  246. ULONG64 pFreeRecord, pFreeRecordOrg;
  247. if (!(dwPoolFlags & POOL_KEEP_FREE_RECORD)) {
  248. dprintf("win32k.sys doesn't have records of free pool !\n");
  249. return FALSE;
  250. }
  251. dwFreeRecordTotalFrees = GetUlongValue( "win32k!gdwFreeRecordTotalFrees" );
  252. if (dwFreeRecordTotalFrees == 0) {
  253. dprintf("No free pool in win32k.sys !\n");
  254. return FALSE;
  255. }
  256. dwFreeRecordCrtIndex = GetUlongValue( "win32k!gdwFreeRecordCrtIndex" );
  257. dwFreeRecords = GetUlongValue( "win32k!gdwFreeRecords" );
  258. if (dwFreeRecordTotalFrees < dwFreeRecords) {
  259. dwFreesToDump = dwFreeRecordTotalFrees;
  260. } else {
  261. dwFreesToDump = dwFreeRecords;
  262. }
  263. pFreeRecord = GetPointerValue( "win32k!gparrFreeRecord" );
  264. if (!pFreeRecord) {
  265. dprintf("\nCouldn't get gparrFreeRecord!\n");
  266. return FALSE;
  267. }
  268. pFreeRecordOrg = pFreeRecord;
  269. dprintf("\nFrees to dump : %d\n\n", dwFreesToDump);
  270. for (Ind = 0; Ind < dwFreesToDump; Ind++) {
  271. if (dwFreeRecordCrtIndex == 0) {
  272. dwFreeRecordCrtIndex = dwFreeRecords - 1;
  273. } else {
  274. dwFreeRecordCrtIndex--;
  275. }
  276. pFreeRecord = pFreeRecordOrg + dwFreeRecordCrtIndex;
  277. /*
  278. * Dump
  279. */
  280. InitTypeRead(pFreeRecord, win32k!tagPOOLRECORD);
  281. dprintf("Free pool for p %#p size 0x%x\n",
  282. ReadField(ExtraData),
  283. (ULONG)ReadField(size));
  284. PrintStackTrace(ReadField(pTrace), RECORD_STACK_TRACE_SIZE);
  285. }
  286. }
  287. InitTypeRead(pAllocList, win32k!tagWin32AllocStats);
  288. if (opts & DpaAllCurrentAllocs) {
  289. ULONG64 ph = ReadField(pHead);
  290. while (ph != 0) {
  291. InitTypeRead(ph, win32k!tagWin32PoolHead);
  292. dprintf("p %#p pHead %#p size %x\n",
  293. ph + dwSize, ph, (ULONG)ReadField(size));
  294. if (bIncludeStackTrace) {
  295. ULONG64 dwOffset;
  296. CHAR symbol[MAX_PATH];
  297. int ind;
  298. ULONG64 trace;
  299. ULONG64 pTrace;
  300. pTrace = ReadField(pTrace);
  301. for (ind = 0; ind < POOL_ALLOC_TRACE_SIZE; ind++) {
  302. ReadPointer(pTrace, &trace);
  303. if (trace == 0) {
  304. break;
  305. }
  306. GetSymbol(trace, symbol, &dwOffset);
  307. if (*symbol) {
  308. dprintf("\t%s", symbol);
  309. if (dwOffset != 0) {
  310. dprintf("+0x%I64x", dwOffset);
  311. }
  312. dprintf("\n");
  313. }
  314. ++pTrace;
  315. }
  316. dprintf("\n");
  317. }
  318. ph = (ULONG_PTR)ReadField(pNext);
  319. if (CheckControlC())
  320. {
  321. return FALSE;
  322. }
  323. }
  324. return TRUE;
  325. }
  326. InitTypeRead(pAllocList, win32k!tagWin32AllocStats);
  327. if (opts & DpaContainsPointer) {
  328. ULONG64 ph;
  329. dwSize = GetTypeSize("win32k!tagWin32PoolHead");
  330. if (param1 == 0) {
  331. return TRUE;
  332. }
  333. ph = ReadField(pHead);
  334. while (ph != 0) {
  335. if ((param1 - ph) >= ((ULONG)ReadField(size) + dwSize)) {
  336. dprintf("p %#p pHead %#p size %x\n",
  337. ph + 1, ph, (ULONG)ReadField(size));
  338. PrintStackTrace(ReadField(pTrace), RECORD_STACK_TRACE_SIZE);
  339. return TRUE;
  340. }
  341. ph = ReadField(pNext);
  342. }
  343. return TRUE;
  344. }
  345. } except (Hr) {
  346. dprintf("Unhandled exception %lx in DumpPoolAllocs\n", Hr);
  347. }
  348. return TRUE;
  349. }
  350. DECLARE_API( dpa )
  351. {
  352. ULONG opts;
  353. ULONG64 param1;
  354. INIT_API();
  355. if (!GetDpaArgs((PCHAR)args, &opts, &param1))
  356. {
  357. DisplayDpaUsage();
  358. Status = E_FAIL;
  359. } else
  360. {
  361. DumpPoolAllocs(opts, param1);
  362. }
  363. EXIT_API();
  364. return Status;
  365. }