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.

471 lines
11 KiB

  1. // poolsnap.c
  2. // this program takes a snapshot of all the kernel pool tags.
  3. // and appends it to the logfile (arg)
  4. // pmon was model for this
  5. /* includes */
  6. #include <nt.h>
  7. #include <ntrtl.h>
  8. #include <nturtl.h>
  9. #include <windows.h>
  10. #include <assert.h>
  11. #include <stdlib.h>
  12. #include <stdio.h>
  13. #include <string.h>
  14. #include <ctype.h>
  15. #include <io.h>
  16. #include <srvfsctl.h>
  17. #include <search.h>
  18. #include "tags.c"
  19. //
  20. // declarations
  21. //
  22. int __cdecl ulcomp(const void *e1,const void *e2);
  23. NTSTATUS
  24. QueryPoolTagInformationIterative(
  25. PUCHAR *CurrentBuffer,
  26. size_t *CurrentBufferSize
  27. );
  28. //
  29. // definitions
  30. //
  31. #define NONPAGED 0
  32. #define PAGED 1
  33. #define BOTH 2
  34. // from poolmon
  35. // raw input
  36. PSYSTEM_POOLTAG_INFORMATION PoolInfo;
  37. //
  38. // the amount of memory to increase the size
  39. // of the buffer for NtQuerySystemInformation at each step
  40. //
  41. #define BUFFER_SIZE_STEP 65536
  42. //
  43. // the buffer used for NtQuerySystemInformation
  44. //
  45. PUCHAR CurrentBuffer = NULL;
  46. //
  47. // the size of the buffer used for NtQuerySystemInformation
  48. //
  49. size_t CurrentBufferSize = 0;
  50. //
  51. // formatted output
  52. //
  53. typedef struct _POOLMON_OUT {
  54. union {
  55. UCHAR Tag[4];
  56. ULONG TagUlong;
  57. };
  58. UCHAR NullByte;
  59. BOOL Changed;
  60. ULONG Type;
  61. SIZE_T Allocs;
  62. SIZE_T AllocsDiff;
  63. SIZE_T Frees;
  64. SIZE_T FreesDiff;
  65. SIZE_T Allocs_Frees;
  66. SIZE_T Used;
  67. SIZE_T UsedDiff;
  68. SIZE_T Each;
  69. } POOLMON_OUT, *PPOOLMON_OUT;
  70. PPOOLMON_OUT OutBuffer;
  71. PPOOLMON_OUT Out;
  72. UCHAR *PoolType[] = {
  73. "Nonp ",
  74. "Paged"};
  75. VOID Usage(VOID)
  76. {
  77. printf("poolsnap [-?] [-t] [<logfile>]\n");
  78. printf("poolsnap logs system pool usage to <logfile>\n");
  79. printf("-? Gives this help\n");
  80. printf("-t Output extra tagged information\n");
  81. printf("<logfile> = poolsnap.log by default\n");
  82. exit(-1);
  83. }
  84. /*
  85. * FUNCTION: Main
  86. *
  87. * ARGUMENTS: See Usage
  88. *
  89. * RETURNS: 0
  90. *
  91. */
  92. int __cdecl main(int argc, char* argv[])
  93. {
  94. NTSTATUS Status; // status from NT api
  95. FILE* LogFile= NULL; // log file handle
  96. DWORD x= 0; // counter
  97. SIZE_T NumberOfPoolTags;
  98. INT iCmdIndex; // index into argv
  99. BOOL bOutputTags= FALSE; // if true, output standard tags
  100. // get higher priority in case system is bogged down
  101. if ( GetPriorityClass(GetCurrentProcess()) == NORMAL_PRIORITY_CLASS) {
  102. SetPriorityClass(GetCurrentProcess(),HIGH_PRIORITY_CLASS);
  103. }
  104. //
  105. // parse command line arguments
  106. //
  107. for( iCmdIndex=1; iCmdIndex < argc; iCmdIndex++ ) {
  108. CHAR chr;
  109. chr= *argv[iCmdIndex];
  110. if( (chr=='-') || (chr=='/') ) {
  111. chr= argv[iCmdIndex][1];
  112. switch( chr ) {
  113. case '?':
  114. Usage();
  115. break;
  116. case 't': case 'T':
  117. bOutputTags= TRUE;
  118. break;
  119. default:
  120. printf("Invalid switch: %s\n",argv[iCmdIndex]);
  121. Usage();
  122. break;
  123. }
  124. }
  125. else {
  126. if( LogFile ) {
  127. printf("Error: more than one file specified: %s\n",argv[iCmdIndex]);
  128. return(0);
  129. }
  130. LogFile= fopen(argv[iCmdIndex],"a");
  131. if( !LogFile ) {
  132. printf("Error: Opening file %s\n",argv[iCmdIndex]);
  133. return(0);
  134. }
  135. }
  136. }
  137. //
  138. // if no file specified, use default name
  139. //
  140. if( !LogFile ) {
  141. if( (LogFile = fopen("poolsnap.log","a")) == NULL ) {
  142. printf("Error: opening file poolsnap.log\n");
  143. return(0);
  144. }
  145. }
  146. //
  147. // print file header once
  148. //
  149. if( _filelength(_fileno(LogFile)) == 0 ) {
  150. fprintf(LogFile," Tag Type Allocs Frees Diff Bytes Per Alloc\n");
  151. }
  152. fprintf(LogFile,"\n");
  153. if( bOutputTags ) {
  154. OutputStdTags(LogFile, "poolsnap" );
  155. }
  156. // grab all pool information
  157. // log line format, fixed column format
  158. Status = QueryPoolTagInformationIterative(
  159. &CurrentBuffer,
  160. &CurrentBufferSize
  161. );
  162. if (! NT_SUCCESS(Status)) {
  163. printf("Failed to query pool tags information (status %08X). \n", Status);
  164. printf("Please check if pool tags are enabled. \n");
  165. return (0);
  166. }
  167. PoolInfo = (PSYSTEM_POOLTAG_INFORMATION)CurrentBuffer;
  168. //
  169. // Allocate the output buffer.
  170. //
  171. OutBuffer = malloc (PoolInfo->Count * sizeof(POOLMON_OUT));
  172. if (OutBuffer == NULL) {
  173. printf ("Error: cannot allocate internal buffer of %p bytes \n",
  174. PoolInfo->Count * sizeof(POOLMON_OUT));
  175. return (0);
  176. }
  177. Out = OutBuffer;
  178. if( NT_SUCCESS(Status) ) {
  179. for (x = 0; x < (int)PoolInfo->Count; x++) {
  180. // get pool info from buffer
  181. // non-paged
  182. if (PoolInfo->TagInfo[x].NonPagedAllocs != 0) {
  183. Out->Allocs = PoolInfo->TagInfo[x].NonPagedAllocs;
  184. Out->Frees = PoolInfo->TagInfo[x].NonPagedFrees;
  185. Out->Used = PoolInfo->TagInfo[x].NonPagedUsed;
  186. Out->Allocs_Frees = PoolInfo->TagInfo[x].NonPagedAllocs -
  187. PoolInfo->TagInfo[x].NonPagedFrees;
  188. Out->TagUlong = PoolInfo->TagInfo[x].TagUlong;
  189. Out->Type = NONPAGED;
  190. Out->Changed = FALSE;
  191. Out->NullByte = '\0';
  192. Out->Each = Out->Used / (Out->Allocs_Frees?Out->Allocs_Frees:1);
  193. }
  194. // paged
  195. if (PoolInfo->TagInfo[x].PagedAllocs != 0) {
  196. Out->Allocs = PoolInfo->TagInfo[x].PagedAllocs;
  197. Out->Frees = PoolInfo->TagInfo[x].PagedFrees;
  198. Out->Used = PoolInfo->TagInfo[x].PagedUsed;
  199. Out->Allocs_Frees = PoolInfo->TagInfo[x].PagedAllocs -
  200. PoolInfo->TagInfo[x].PagedFrees;
  201. Out->TagUlong = PoolInfo->TagInfo[x].TagUlong;
  202. Out->Type = PAGED;
  203. Out->Changed = FALSE;
  204. Out->NullByte = '\0';
  205. Out->Each = Out->Used / (Out->Allocs_Frees?Out->Allocs_Frees:1);
  206. }
  207. Out += 1;
  208. }
  209. }
  210. else {
  211. fprintf(LogFile, "Query pooltags Failed %lx\n",Status);
  212. fprintf(LogFile, " Be sure to turn on 'enable pool tagging' in gflags and reboot.\n");
  213. if( bOutputTags ) {
  214. fprintf(LogFile, "!Error:Query pooltags failed %lx\n",Status);
  215. fprintf(LogFile, "!Error: Be sure to turn on 'enable pool tagging' in gflags and reboot.\n");
  216. }
  217. // If there is an operator around, wake him up, but keep moving
  218. Beep(1000,350); Beep(500,350); Beep(1000,350);
  219. exit(0);
  220. }
  221. //
  222. // sort by tag value which is big endian
  223. //
  224. NumberOfPoolTags = Out - OutBuffer;
  225. qsort((void *)OutBuffer,
  226. (size_t)NumberOfPoolTags,
  227. (size_t)sizeof(POOLMON_OUT),
  228. ulcomp);
  229. //
  230. // print in file
  231. //
  232. for (x = 0; x < (int)PoolInfo->Count; x++) {
  233. fprintf(LogFile,
  234. #ifdef _WIN64
  235. " %4s %5s %18I64d %18I64d %16I64d %14I64d %12I64d\n",
  236. #else
  237. " %4s %5s %9ld %9ld %8ld %7ld %6ld\n",
  238. #endif
  239. OutBuffer[x].Tag,
  240. PoolType[OutBuffer[x].Type],
  241. OutBuffer[x].Allocs,
  242. OutBuffer[x].Frees,
  243. OutBuffer[x].Allocs_Frees,
  244. OutBuffer[x].Used,
  245. OutBuffer[x].Each
  246. );
  247. }
  248. // close file
  249. fclose(LogFile);
  250. return 0;
  251. }
  252. // comparison function for qsort
  253. // Tags are big endian
  254. int __cdecl ulcomp(const void *e1,const void *e2)
  255. {
  256. ULONG u1;
  257. u1 = ((PUCHAR)e1)[0] - ((PUCHAR)e2)[0];
  258. if (u1 != 0) {
  259. return u1;
  260. }
  261. u1 = ((PUCHAR)e1)[1] - ((PUCHAR)e2)[1];
  262. if (u1 != 0) {
  263. return u1;
  264. }
  265. u1 = ((PUCHAR)e1)[2] - ((PUCHAR)e2)[2];
  266. if (u1 != 0) {
  267. return u1;
  268. }
  269. u1 = ((PUCHAR)e1)[3] - ((PUCHAR)e2)[3];
  270. return u1;
  271. }
  272. /*
  273. * FUNCTION:
  274. *
  275. * QueryPoolTagInformationIterative
  276. *
  277. * ARGUMENTS:
  278. *
  279. * CurrentBuffer - a pointer to the buffer currently used for
  280. * NtQuerySystemInformation( SystemPoolTagInformation ).
  281. * It will be allocated if NULL or its size grown
  282. * if necessary.
  283. *
  284. * CurrentBufferSize - a pointer to a variable that holds the current
  285. * size of the buffer.
  286. *
  287. *
  288. * RETURNS:
  289. *
  290. * NTSTATUS returned by NtQuerySystemInformation or
  291. * STATUS_INSUFFICIENT_RESOURCES if the buffer must grow and the
  292. * heap allocation for it fails.
  293. *
  294. */
  295. NTSTATUS
  296. QueryPoolTagInformationIterative(
  297. PUCHAR *CurrentBuffer,
  298. size_t *CurrentBufferSize
  299. )
  300. {
  301. size_t NewBufferSize;
  302. NTSTATUS ReturnedStatus = STATUS_SUCCESS;
  303. if( CurrentBuffer == NULL || CurrentBufferSize == NULL ) {
  304. return STATUS_INVALID_PARAMETER;
  305. }
  306. if( *CurrentBufferSize == 0 || *CurrentBuffer == NULL ) {
  307. //
  308. // there is no buffer allocated yet
  309. //
  310. NewBufferSize = sizeof( UCHAR ) * BUFFER_SIZE_STEP;
  311. *CurrentBuffer = (PUCHAR) malloc( NewBufferSize );
  312. if( *CurrentBuffer != NULL ) {
  313. *CurrentBufferSize = NewBufferSize;
  314. } else {
  315. //
  316. // insufficient memory
  317. //
  318. ReturnedStatus = STATUS_INSUFFICIENT_RESOURCES;
  319. }
  320. }
  321. //
  322. // iterate by buffer's size
  323. //
  324. while( *CurrentBuffer != NULL ) {
  325. ReturnedStatus = NtQuerySystemInformation (
  326. SystemPoolTagInformation,
  327. *CurrentBuffer,
  328. (ULONG)*CurrentBufferSize,
  329. NULL );
  330. if( ! NT_SUCCESS(ReturnedStatus) ) {
  331. //
  332. // free the current buffer
  333. //
  334. free( *CurrentBuffer );
  335. *CurrentBuffer = NULL;
  336. if (ReturnedStatus == STATUS_INFO_LENGTH_MISMATCH) {
  337. //
  338. // try with a greater buffer size
  339. //
  340. NewBufferSize = *CurrentBufferSize + BUFFER_SIZE_STEP;
  341. *CurrentBuffer = (PUCHAR) malloc( NewBufferSize );
  342. if( *CurrentBuffer != NULL ) {
  343. //
  344. // allocated new buffer
  345. //
  346. *CurrentBufferSize = NewBufferSize;
  347. } else {
  348. //
  349. // insufficient memory
  350. //
  351. ReturnedStatus = STATUS_INSUFFICIENT_RESOURCES;
  352. *CurrentBufferSize = 0;
  353. }
  354. } else {
  355. *CurrentBufferSize = 0;
  356. }
  357. } else {
  358. //
  359. // NtQuerySystemInformation returned success
  360. //
  361. break;
  362. }
  363. }
  364. return ReturnedStatus;
  365. }