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.

623 lines
18 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. pooldump.c
  5. Abstract:
  6. This module contains the implementation of the temporary routine
  7. to dump non-paged pool usage.
  8. Usage:
  9. Set TRACE_ALLOC to 1 in pool.c and rebuild the kernel.
  10. When pooldump is run, the colllected pool counts are returned
  11. and analyzed.
  12. Author:
  13. Lou Perazzoli (loup) 22-Aug-1991
  14. Envirnoment:
  15. User mode, debug version of the kernel.
  16. Revision History:
  17. --*/
  18. #include <assert.h>
  19. #include <stdio.h>
  20. #include <string.h>
  21. #include <memory.h>
  22. #include <nt.h>
  23. #include <ntrtl.h>
  24. #include <nturtl.h>
  25. #include <windows.h>
  26. #define DbgPrint printf
  27. //#define DBG_PROFILE 1
  28. NTSTATUS
  29. LoadSymbols (
  30. VOID
  31. );
  32. NTSTATUS
  33. LookupSymbolNameAndLocation (
  34. IN ULONG CodeAddress,
  35. OUT PSTRING SymbolName,
  36. OUT PULONG OffsetFromSymbol,
  37. OUT PULONG ImageIndex
  38. );
  39. #define PAGE_SIZE 4096
  40. typedef struct _IMAGE_BLOCK {
  41. ULONG ImageBase; //actual base where mapped locally.
  42. PIMAGE_DEBUG_INFO DebugInfo;
  43. ULONG CodeStart;
  44. ULONG CodeEnd;
  45. ULONG TextNumber;
  46. BOOLEAN KernelCode;
  47. UNICODE_STRING ImageName;
  48. } IMAGE_BLOCK;
  49. #define MAX_PROFILE_COUNT 30
  50. IMAGE_BLOCK ImageInformation[MAX_PROFILE_COUNT+1];
  51. ULONG NumberOfImages = 0;
  52. //
  53. // Define map data file if the produced data file should be
  54. // a mapped file (currently named "kernprof.dat").
  55. //
  56. // #define MAP_DATA_FILE
  57. //
  58. // Define map as image if the image to be profiled should be mapped
  59. // as an image rather than as data.
  60. //
  61. // #define MAP_AS_IMAGE
  62. #define MAX_POOL_ENTRIES 1024
  63. typedef struct _POOLUSAGE {
  64. ULONG Caller;
  65. ULONG Allocations;
  66. ULONG Frees;
  67. ULONG Usage;
  68. } POOLUSAGE;
  69. POOLUSAGE Buffer[MAX_POOL_ENTRIES];
  70. __cdecl main(
  71. int argc,
  72. char *argv[],
  73. char *envp[]
  74. )
  75. {
  76. NTSTATUS status;
  77. ULONG i, Offset;
  78. ULONG TotalAllocs = 0;
  79. ULONG TotalFrees = 0;
  80. ULONG TotalUsage = 0;
  81. ULONG Start;
  82. STRING SymbolName;
  83. UCHAR String[80];
  84. STRING OutString;
  85. ULONG ImageIndex;
  86. RtlZeroMemory (&Buffer, MAX_POOL_ENTRIES * sizeof (POOLUSAGE));
  87. SymbolName.MaximumLength = 80;
  88. SymbolName.Buffer = String;
  89. status = NtPartyByNumber (PARTY_DUMP_POOL_USAGE, &Buffer);
  90. if (!NT_SUCCESS (status)) {
  91. return(status);
  92. }
  93. LoadSymbols ();
  94. printf("Allocs Frees Used At\n");
  95. for (i =0; i < MAX_POOL_ENTRIES ; i++ ) {
  96. if (Buffer[i].Caller == 0) {
  97. break;
  98. }
  99. String[0] = 0;
  100. SymbolName.MaximumLength = 80;
  101. SymbolName.Length = 0;
  102. Offset = Buffer[i].Caller;
  103. LookupSymbolNameAndLocation (Buffer[i].Caller,
  104. &SymbolName,
  105. &Offset,
  106. &ImageIndex);
  107. RtlUnicodeStringToAnsiString(&OutString,
  108. &ImageInformation[ImageIndex].ImageName,
  109. TRUE);
  110. printf("%6ld %6ld %6ld %s + 0x%lx (%s)\n",
  111. Buffer[i].Allocations,
  112. Buffer[i].Frees,
  113. Buffer[i].Usage,
  114. SymbolName.Buffer,
  115. Offset,
  116. OutString.Buffer
  117. );
  118. RtlFreeAnsiString(&OutString);
  119. TotalAllocs += Buffer[i].Allocations;
  120. TotalFrees += Buffer[i].Frees;
  121. TotalUsage += Buffer[i].Usage;
  122. }
  123. printf("Total: allocations %ld Frees %ld Difference (A-F) %ld Usage %ld\n",
  124. TotalAllocs, TotalFrees, (TotalAllocs - TotalFrees), TotalUsage);
  125. return(status);
  126. }
  127. NTSTATUS
  128. LoadSymbols (
  129. VOID
  130. )
  131. /*++
  132. Routine Description:
  133. This routine initializes symbols for the kernel.
  134. Arguments:
  135. None.
  136. Return Value:
  137. Status of operations.
  138. --*/
  139. {
  140. IO_STATUS_BLOCK IoStatus;
  141. HANDLE FileHandle, KernelSection;
  142. OBJECT_ATTRIBUTES ObjectAttributes;
  143. PVOID ImageBase;
  144. ULONG ViewSize;
  145. ULONG CodeLength;
  146. NTSTATUS status;
  147. HANDLE CurrentProcessHandle;
  148. ULONG DebugSize;
  149. PVOID KernelBase;
  150. PIMAGE_DEBUG_DIRECTORY DebugDirectory;
  151. UCHAR StringBuf[250];
  152. UNICODE_STRING NameString;
  153. ULONG TotalOffset;
  154. CHAR ModuleInfo[8000];
  155. ULONG ReturnedLength;
  156. PSYSTEM_LOAD_MODULE_INFORMATION Module;
  157. ANSI_STRING String;
  158. STRING SysdiskA;
  159. STRING SysrootA;
  160. UNICODE_STRING Sysdisk;
  161. UNICODE_STRING Sysroot;
  162. PIMAGE_DEBUG_INFO KernelDebugInfo;
  163. CurrentProcessHandle = NtCurrentProcess();
  164. //
  165. // Locate system drivers.
  166. //
  167. status = NtQuerySystemInformation (
  168. SystemLoadModuleInformation,
  169. ModuleInfo,
  170. 8000,
  171. &ReturnedLength);
  172. if (!NT_SUCCESS(status)) {
  173. printf("query system info failed status - %lx\n",status);
  174. return(status);
  175. }
  176. RtlInitString (&SysdiskA,"\\SystemRoot");
  177. RtlAnsiStringToUnicodeString (&Sysdisk, (PANSI_STRING)&SysdiskA, TRUE);
  178. RtlInitString (&SysrootA,"\\SystemRoot\\Driver\\");
  179. RtlAnsiStringToUnicodeString (&Sysroot, (PANSI_STRING)&SysrootA, TRUE);
  180. NameString.Buffer = &StringBuf[0];
  181. NameString.Length = 0;
  182. NameString.MaximumLength = 250;
  183. Module = &ModuleInfo[0];
  184. TotalOffset = 0;
  185. while (TRUE) {
  186. #if DBG_PROFILE
  187. printf("module base %lx\n",Module->BaseAddress);
  188. printf("module dll buffer address %lx %lx %lx\n",
  189. Module->ModuleDllName.Buffer,
  190. Module->ModuleFileName.Buffer, Module);
  191. RtlUnicodeStringToAnsiString(&String, &Module->ModuleDllName, TRUE);
  192. printf("module dll name %s\n",String.Buffer);
  193. RtlUnicodeStringToAnsiString(&String, &Module->ModuleFileName, TRUE);
  194. printf("module file name %s\n",String.Buffer);
  195. #endif
  196. if ( Module->ModuleFileName.Buffer[0] == (WCHAR) '\\' ) {
  197. Module->ModuleFileName.Buffer++;
  198. Module->ModuleFileName.Length -= sizeof(WCHAR);
  199. Module->ModuleFileName.MaximumLength -= sizeof(WCHAR);
  200. while (Module->ModuleFileName.Buffer[0] != (WCHAR) '\\' ) {
  201. Module->ModuleFileName.Buffer++;
  202. Module->ModuleFileName.Length -= sizeof(WCHAR);
  203. Module->ModuleFileName.MaximumLength -= sizeof(WCHAR);
  204. }
  205. }
  206. NameString.Length = 0;
  207. status = RtlAppendStringToString (&NameString, (PSTRING)&Sysdisk);
  208. if (!NT_SUCCESS(status)) {
  209. printf("append string failed status - %lx\n",status);
  210. return(status);
  211. }
  212. status = RtlAppendStringToString (&NameString, (PSTRING)&Module->ModuleFileName);
  213. if (!NT_SUCCESS(status)) {
  214. printf("append string failed status - %lx\n",status);
  215. return(status);
  216. }
  217. InitializeObjectAttributes( &ObjectAttributes,
  218. &NameString,
  219. OBJ_CASE_INSENSITIVE,
  220. NULL,
  221. NULL );
  222. //
  223. // Open the file as readable and executable.
  224. //
  225. #if DBG_PROFILE
  226. RtlUnicodeStringToAnsiString(&String, &NameString, TRUE);
  227. printf("Opening file name %s\n",String.Buffer);
  228. #endif
  229. status = NtOpenFile ( &FileHandle,
  230. FILE_READ_DATA | FILE_EXECUTE,
  231. &ObjectAttributes,
  232. &IoStatus,
  233. FILE_SHARE_READ,
  234. 0L);
  235. if (!NT_SUCCESS(status)) {
  236. //
  237. // Try a different name - in SystemRoot\Driver directory.
  238. //
  239. NameString.Length = 0;
  240. status = RtlAppendStringToString (&NameString, &Sysroot);
  241. if (!NT_SUCCESS(status)) {
  242. printf("append string failed status - %lx\n",status);
  243. return(status);
  244. }
  245. status = RtlAppendStringToString (&NameString, &Module->ModuleFileName);
  246. if (!NT_SUCCESS(status)) {
  247. printf("append string failed status - %lx\n",status);
  248. return(status);
  249. }
  250. InitializeObjectAttributes( &ObjectAttributes,
  251. &NameString,
  252. OBJ_CASE_INSENSITIVE,
  253. NULL,
  254. NULL );
  255. //
  256. // Open the file as readable and executable.
  257. //
  258. #if DBG_PROFILE
  259. RtlUnicodeStringToAnsiString(&String, &NameString, TRUE);
  260. printf("Opening file name %s\n",String.Buffer);
  261. #endif
  262. status = NtOpenFile ( &FileHandle,
  263. FILE_READ_DATA,
  264. &ObjectAttributes,
  265. &IoStatus,
  266. FILE_SHARE_READ,
  267. 0L);
  268. if (!NT_SUCCESS(status)) {
  269. RtlUnicodeStringToAnsiString(&String, &NameString, TRUE);
  270. DbgPrint("open file %s failed status %lx\n",
  271. String.Buffer, status);
  272. return(status);
  273. }
  274. }
  275. InitializeObjectAttributes( &ObjectAttributes, NULL, 0, NULL, NULL );
  276. //
  277. // For normal images they would be mapped as an image, but
  278. // the kernel has no debug section (as yet) information, hence it
  279. // must be mapped as a file.
  280. //
  281. status = NtCreateSection (&KernelSection,
  282. SECTION_MAP_READ,
  283. &ObjectAttributes,
  284. 0,
  285. PAGE_READONLY,
  286. SEC_COMMIT,
  287. FileHandle);
  288. if (!NT_SUCCESS(status)) {
  289. DbgPrint("create image section failed status %lx\n", status);
  290. return(status);
  291. }
  292. ViewSize = 0;
  293. //
  294. // Map a view of the section into the address space.
  295. //
  296. KernelBase = NULL;
  297. status = NtMapViewOfSection (KernelSection,
  298. CurrentProcessHandle,
  299. &KernelBase,
  300. 0L,
  301. 0,
  302. NULL,
  303. &ViewSize,
  304. ViewUnmap,
  305. 0,
  306. PAGE_READONLY);
  307. if (!NT_SUCCESS(status)) {
  308. if (status != STATUS_IMAGE_NOT_AT_BASE) {
  309. DbgPrint("map section status %lx base %lx size %lx\n", status,
  310. (ULONG)KernelBase, ViewSize);
  311. }
  312. }
  313. ImageBase = Module->BaseAddress;
  314. DebugDirectory = (PIMAGE_DEBUG_DIRECTORY)RtlImageDirectoryEntryToData(
  315. KernelBase, FALSE, IMAGE_DIRECTORY_ENTRY_DEBUG, &DebugSize);
  316. //printf("Mapped base %lx Debug dir %lx\n", (ULONG)KernelBase, DebugDirectory);
  317. if (!DebugDirectory) {
  318. DbgPrint("InitializeKernelProfile : No debug directory\n");
  319. return STATUS_INVALID_IMAGE_FORMAT;
  320. }
  321. KernelDebugInfo = (PIMAGE_DEBUG_INFO)((ULONG)KernelBase + DebugDirectory->PointerToRawData);
  322. CodeLength = KernelDebugInfo->RvaToLastByteOfCode - KernelDebugInfo->RvaToFirstByteOfCode;
  323. ImageInformation[NumberOfImages].KernelCode = TRUE;
  324. ImageInformation[NumberOfImages].DebugInfo = KernelDebugInfo;
  325. ImageInformation[NumberOfImages].CodeStart = ((ULONG)ImageBase +
  326. KernelDebugInfo->RvaToFirstByteOfCode);
  327. ImageInformation[NumberOfImages].CodeEnd =
  328. ImageInformation[NumberOfImages].CodeStart + CodeLength;
  329. ImageInformation[NumberOfImages].TextNumber = 1;
  330. ImageInformation[NumberOfImages].ImageBase = ImageBase;
  331. ImageInformation[NumberOfImages].ImageName = Module->ModuleDllName;
  332. NumberOfImages += 1;
  333. if (NumberOfImages == MAX_PROFILE_COUNT) {
  334. return STATUS_SUCCESS;
  335. }
  336. if (Module->NextEntryOffset == 0) {
  337. break;
  338. }
  339. TotalOffset += Module->NextEntryOffset;
  340. Module = (PSYSTEM_LOAD_MODULE_INFORMATION)&ModuleInfo[TotalOffset];
  341. }
  342. return status;
  343. }
  344. NTSTATUS
  345. LookupSymbolNameAndLocation (
  346. IN ULONG CodeAddress,
  347. OUT PSTRING SymbolName,
  348. OUT PULONG OffsetFromSymbol,
  349. OUT PULONG ImageIndex
  350. )
  351. /*++
  352. Routine Description:
  353. Given a code address, this routine returns the nearest symbol
  354. name and the offset from the symbol to that name. If the
  355. nearest symbol is not within 100k of the location, no name
  356. is returned and the offset is the value of the CodeAddress.
  357. Arguments:
  358. CodeAddress - Supplies the address to lookup a symbol for.
  359. SymbolName - Returns the name of the symbol.
  360. OffsetFromSymbol - Returns the offset from the symbol to the
  361. code address.
  362. Return Value:
  363. Status of operations.
  364. --*/
  365. {
  366. ULONG j, nextSymbol, imageNumber;
  367. ULONG NewCodeAddress;
  368. IMAGE_SYMBOL PreviousSymbol;
  369. PIMAGE_DEBUG_INFO DebugInfo;
  370. PIMAGE_SYMBOL SymbolEntry;
  371. IMAGE_SYMBOL Symbol;
  372. PUCHAR StringTable;
  373. ULONG EightChar[3];
  374. BOOLEAN NoSymbols;
  375. for (imageNumber = 0; imageNumber < NumberOfImages; imageNumber++) {
  376. if ((CodeAddress >= ImageInformation[imageNumber].ImageBase) &&
  377. (CodeAddress <= ImageInformation[imageNumber].CodeEnd)) {
  378. break;
  379. }
  380. }
  381. *ImageIndex = imageNumber;
  382. if (imageNumber == NumberOfImages) {
  383. //
  384. // Address not found.
  385. //
  386. SymbolName->Length = 0;
  387. *OffsetFromSymbol = CodeAddress;
  388. return STATUS_SUCCESS;
  389. }
  390. NewCodeAddress = CodeAddress - ImageInformation[imageNumber].ImageBase;
  391. //
  392. // Locate debug section.
  393. //
  394. DebugInfo = ImageInformation[imageNumber].DebugInfo;
  395. //
  396. // Crack the symbol table.
  397. //
  398. SymbolEntry = (PIMAGE_SYMBOL)((ULONG)DebugInfo + DebugInfo->LvaToFirstSymbol);
  399. StringTable = (PUCHAR)((ULONG)DebugInfo + DebugInfo->LvaToFirstSymbol +
  400. DebugInfo->NumberOfSymbols * (ULONG)IMAGE_SIZEOF_SYMBOL);
  401. //
  402. // Find the "header" symbol (skipping all the section names)
  403. //
  404. nextSymbol = 0;
  405. // printf("number of symbols %ld\n", DebugInfo->NumberOfSymbols);
  406. for (j = 0; j < DebugInfo->NumberOfSymbols; j++) {
  407. EightChar[0] = SymbolEntry->N.Name.Short;
  408. EightChar[1] = SymbolEntry->N.Name.Long;
  409. if (!strcmp((PSZ)&EightChar[0], "header")) {
  410. nextSymbol = j;
  411. // printf("found header at %ld\n",j);
  412. break;
  413. }
  414. SymbolEntry = (PIMAGE_SYMBOL)((ULONG)SymbolEntry +
  415. IMAGE_SIZEOF_SYMBOL);
  416. }
  417. if (j >= DebugInfo->NumberOfSymbols) {
  418. SymbolEntry = (PIMAGE_SYMBOL)((ULONG)DebugInfo + DebugInfo->LvaToFirstSymbol);
  419. }
  420. NoSymbols = TRUE;
  421. //
  422. // Loop through all symbols in the symbol table. For each symbol,
  423. // if it is within the code section, subtract off the bias and
  424. // see if there are any hits within the profile buffer for
  425. // that symbol.
  426. //
  427. // printf("number of symbols %ld\n", DebugInfo->NumberOfSymbols);
  428. for (j = nextSymbol; j < DebugInfo->NumberOfSymbols; j++) {
  429. try {
  430. // printf("numberof aux symbols %ld\n",SymbolEntry->NumberOfAuxSymbols );
  431. while ( SymbolEntry->NumberOfAuxSymbols ) {
  432. j = j + 1 + SymbolEntry->NumberOfAuxSymbols;
  433. SymbolEntry = (PIMAGE_SYMBOL)((ULONG)SymbolEntry +
  434. IMAGE_SIZEOF_SYMBOL +
  435. SymbolEntry->NumberOfAuxSymbols*IMAGE_SIZEOF_SYMBOL);
  436. }
  437. RtlMoveMemory (&Symbol, SymbolEntry, IMAGE_SIZEOF_SYMBOL);
  438. }
  439. except(EXCEPTION_EXECUTE_HANDLER) {
  440. printf("breaking excpt\n");
  441. break;
  442. }
  443. // printf("value %lx number %lx start %lx\n",Symbol.Value,Symbol.SectionNumber,CodeAddress);
  444. if (Symbol.SectionNumber == (SHORT)1) {
  445. //
  446. // This symbol is within the code.
  447. //
  448. if (Symbol.Value < NewCodeAddress) {
  449. PreviousSymbol = Symbol;
  450. NoSymbols = FALSE;
  451. } else {
  452. break;
  453. }
  454. }
  455. SymbolEntry = (PIMAGE_SYMBOL)((ULONG)SymbolEntry +
  456. IMAGE_SIZEOF_SYMBOL);
  457. }
  458. if ((NoSymbols) || (NewCodeAddress - PreviousSymbol.Value) > 0x100000) {
  459. SymbolName->Length = 0;
  460. *OffsetFromSymbol = CodeAddress;
  461. } else {
  462. if (PreviousSymbol.N.Name.Short) {
  463. SymbolName->Length = 8;
  464. if (SymbolName->Length > SymbolName->MaximumLength) {
  465. SymbolName->Length = SymbolName->MaximumLength;
  466. }
  467. EightChar[0] = PreviousSymbol.N.Name.Short;
  468. EightChar[1] = PreviousSymbol.N.Name.Long;
  469. RtlMoveMemory (SymbolName->Buffer, EightChar, SymbolName->Length);
  470. } else {
  471. SymbolName->Length =
  472. strlen(&StringTable[PreviousSymbol.N.Name.Long] ) + 1;
  473. if (SymbolName->Length > SymbolName->MaximumLength) {
  474. SymbolName->Length = SymbolName->MaximumLength;
  475. }
  476. RtlMoveMemory (SymbolName->Buffer,
  477. &StringTable[PreviousSymbol.N.Name.Long],
  478. SymbolName->Length);
  479. SymbolName->Buffer[SymbolName->Length] = 0;
  480. }
  481. *OffsetFromSymbol = NewCodeAddress - PreviousSymbol.Value;
  482. }
  483. return STATUS_SUCCESS;
  484. }