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.

3160 lines
93 KiB

  1. #include <assert.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <ctype.h>
  6. #include <memory.h>
  7. #include <ntos.h>
  8. #include <nturtl.h>
  9. #include <windows.h>
  10. #include <dbghelp.h>
  11. //
  12. // Include umdh stuff
  13. //
  14. #define _PART_OF_DH_ 1
  15. #include "..\umdh\database.c"
  16. #include "..\umdh\miscellaneous.c"
  17. #include "..\umdh\symbols.c"
  18. #include "..\umdh\umdh.c"
  19. #include "..\umdh\dhcmp.c"
  20. #include "..\umdh\heapwalk.c"
  21. #define MAXDWORD 0xffffffff //this is the max value for a DWORD
  22. //
  23. // the amount of memory to increase the size
  24. // of the buffer for NtQuerySystemInformation at each step
  25. //
  26. #define BUFFER_SIZE_STEP 65536
  27. //
  28. // Globals
  29. //
  30. BOOL fVerbose;
  31. BOOL fDumpModules;
  32. BOOL fDumpBackTraces;
  33. BOOL fIgnoreBackTraces;
  34. BOOL fDumpHeapSummaries;
  35. BOOL fDumpHeapTags;
  36. BOOL fDumpHeapEntries;
  37. BOOL fDumpHeapHogs;
  38. BOOL fDumpLocks;
  39. BOOL fDumpSystemObjects;
  40. BOOL fDumpSystemProcesses;
  41. BOOL fDumpKernelModeInformation;
  42. ULONG BufferSize ;
  43. BOOL fRepetitive; // Are we in repetitive mode
  44. DWORD dwTimeInterval; // what is the repetitive time interval
  45. DWORD dwCurrentIteration; // how many iterations have we done in repetitive mode
  46. CHAR SavedFileName[ MAX_PATH ]; // what would the file name be if we didnt iterate
  47. HANDLE hCtrlCEvent; // The ctrl-c event - only for repetitive mode
  48. ULONG_PTR ProcessId; // -1=win32.sys, 0= kernel, +n= Process ID
  49. HANDLE OutputFile;
  50. CHAR DumpLine[512];
  51. CHAR OutputFileName[ MAX_PATH ];
  52. //
  53. // Prototypes
  54. //
  55. // (this is local even though it looks like it should be in ntos\rtl)
  56. PRTL_DEBUG_INFORMATION
  57. RtlQuerySystemDebugInformation(
  58. ULONG Flags
  59. );
  60. BOOLEAN
  61. ComputeSymbolicBackTraces(
  62. PRTL_PROCESS_BACKTRACES BackTraces1
  63. );
  64. BOOLEAN
  65. LoadSymbolsForModules(
  66. PRTL_PROCESS_MODULES Modules
  67. );
  68. VOID
  69. DumpModules(
  70. PRTL_PROCESS_MODULES Modules
  71. );
  72. VOID
  73. DumpBackTraces( VOID );
  74. VOID
  75. DumpHeaps(
  76. PRTL_PROCESS_HEAPS Heaps,
  77. BOOL fDumpSummary,
  78. BOOL fDumpHogs,
  79. BOOL fDumpTags,
  80. BOOL fDumpEntries
  81. );
  82. VOID
  83. DumpLocks(
  84. PRTL_PROCESS_LOCKS Locks
  85. );
  86. VOID
  87. DumpSystemProcesses( VOID );
  88. VOID
  89. DumpObjects( VOID );
  90. VOID
  91. DumpHandles( VOID );
  92. ULONG
  93. GetDhSymbolicNameForAddress(
  94. IN HANDLE UniqueProcess,
  95. IN ULONG_PTR Address,
  96. OUT LPSTR Name,
  97. IN ULONG MaxNameLength
  98. );
  99. ////////////////////////////////////////////////////////////////////////////////////////////
  100. //
  101. // CtrlCHandler
  102. //
  103. // Function:
  104. //
  105. // This function is made the control-c handleris the -r option is used. This
  106. // allows a final snap to be taken when you are done without waiting for the next
  107. // iteration of the loop.
  108. BOOL
  109. CtrlCHandler(DWORD nCtrlType)
  110. {
  111. if (nCtrlType == CTRL_C_EVENT) {
  112. if (hCtrlCEvent) {
  113. SetEvent(hCtrlCEvent);
  114. return TRUE;
  115. }
  116. }
  117. return FALSE;
  118. }
  119. ////////////////////////////////////////////////////////////////////////////////////////////
  120. //
  121. // AdjustFileName
  122. //
  123. // Function:
  124. //
  125. // Adds the iteration number to the OutputFileName and increments the value
  126. // if fRepetitive has been set. Otherwise it returns
  127. //
  128. VOID
  129. AdjustFileName(VOID)
  130. {
  131. CHAR *pPeriod = NULL;
  132. if ((!fRepetitive)||(!strcmp(SavedFileName, "(stdout)"))||(dwCurrentIteration <= 0))
  133. return;
  134. pPeriod = strrchr(SavedFileName, '.');
  135. if (pPeriod) {
  136. pPeriod[0] = '\0';
  137. sprintf(OutputFileName, "%s_%u.%s", SavedFileName, dwCurrentIteration, (pPeriod+1));
  138. pPeriod[0] = '.';
  139. }
  140. else
  141. sprintf(OutputFileName, "%s_%u.dmp", SavedFileName, dwCurrentIteration, pPeriod);
  142. dwCurrentIteration++;
  143. }
  144. ////////////////////////////////////////////////////////////////////////////////////////////
  145. //
  146. // DumpOutputString
  147. //
  148. // Function:
  149. //
  150. // Writes 'DumpLine' to 'OutputFile' converting newlines to End-Of-Line sequences.
  151. // Closes OutputFile if there are any errors.
  152. //
  153. VOID
  154. DumpOutputString( VOID )
  155. {
  156. ULONG d;
  157. PCHAR s, s1;
  158. if (OutputFile == NULL) {
  159. return;
  160. }
  161. s = DumpLine;
  162. while (*s) {
  163. s1 = s;
  164. while (*s1 && *s1 != '\n') {
  165. s1 += 1;
  166. }
  167. if (s1 != s && !WriteFile( OutputFile, s, (ULONG)(s1 - s), &d, NULL )) {
  168. CloseHandle( OutputFile );
  169. OutputFile = NULL;
  170. return;
  171. }
  172. if (*s1 == '\n') {
  173. s1 += 1;
  174. if (!WriteFile( OutputFile, "\r\n", 2, &d, NULL )) {
  175. CloseHandle( OutputFile );
  176. OutputFile = NULL;
  177. return;
  178. }
  179. }
  180. s = s1;
  181. }
  182. }
  183. ////////////////////////////////////////////////////////////////////////////////////////////
  184. //
  185. // Usage
  186. //
  187. // Function: prints usage info to stderr and exits.
  188. //
  189. VOID
  190. Usage( VOID )
  191. {
  192. fputs( "Usage: DH [-p n | -p -1 | -p 0 [-k] [-o]] [-l] [-m] [-s] [-g] [-h] [-t] [r n][-f fileName]\n"
  193. "where: -p n - displays information about process with ClientId of n in DH_n.dmp\n"
  194. " -p -1 - displays information about Win32 Subsystem process in DH_WIN32.DMP.\n"
  195. " -l - displays information about locks.\n"
  196. " -m - displays information about module table.\n"
  197. " -s - displays summary information about heaps.\n"
  198. " -g - displays information about memory hogs.\n"
  199. " -h - displays information about heap entries for each heap.\n"
  200. " -t - displays information about heap tags for each heap.\n"
  201. " -b - displays information about stack back trace database.\n"
  202. " -i - ignore information about stack back trace database.\n"
  203. " -p 0 - displays information about kernel memory and objects in DH_SYS.DMP.\n"
  204. " -o - displays information about object handles (only valid with -p 0).\n"
  205. " -k - displays information about processes and threads (only valid with -p 0).\n"
  206. " -f fileName - specifies the name of the file to write the dump to.\n"
  207. " -# n - sets buffer size to n Meg\n"
  208. " -- specifies the dump output should be written to stdout.\n"
  209. " -r n - generates an log every n minutes with _# appended to filename\n"
  210. " -umdh umdh_options (use -umdh ? for help) \n"
  211. "\n"
  212. " Default flags for -p n are -s -g\n"
  213. " Default flags for -p 0 are -m -s -g -t -k -o\n"
  214. , stderr);
  215. exit( 1 );
  216. }
  217. ////////////////////////////////////////////////////////////////////////////////////////////
  218. //
  219. // InitializeSymbolPathEnvVar
  220. //
  221. //
  222. // Function: Sets _NT_SYMBOLS_PATH to point to where the symbols should be.
  223. //
  224. VOID
  225. InitializeSymbolPathEnvVar( VOID )
  226. {
  227. ULONG n;
  228. CHAR Buffer[ MAX_PATH ];
  229. n = GetEnvironmentVariable( "_NT_SYMBOL_PATH", Buffer, sizeof( Buffer ) );
  230. if (n == 0) {
  231. n = GetEnvironmentVariable( "SystemRoot", Buffer, sizeof( Buffer ) );
  232. if (n != 0) {
  233. strcat( Buffer, "\\Symbols" );
  234. SetEnvironmentVariable( "_NT_SYMBOL_PATH", Buffer );
  235. fprintf( stderr, "DH: Default _NT_SYMBOL_PATH to %s\n", Buffer );
  236. }
  237. }
  238. return;
  239. }
  240. ////////////////////////////////////////////////////////////////////////////////////////////
  241. PRTL_PROCESS_MODULES Modules;
  242. PRTL_PROCESS_BACKTRACES BackTraces;
  243. PUCHAR SymbolicInfoBase;
  244. PUCHAR SymbolicInfoCurrent;
  245. PUCHAR SymbolicInfoCommitNext;
  246. typedef struct _PROCESS_INFO {
  247. LIST_ENTRY Entry;
  248. PSYSTEM_PROCESS_INFORMATION ProcessInfo;
  249. PSYSTEM_THREAD_INFORMATION ThreadInfo[ 1 ];
  250. } PROCESS_INFO, *PPROCESS_INFO;
  251. LIST_ENTRY ProcessListHead;
  252. PSYSTEM_OBJECTTYPE_INFORMATION ObjectInformation;
  253. PSYSTEM_HANDLE_INFORMATION_EX HandleInformation;
  254. PSYSTEM_PROCESS_INFORMATION ProcessInformation;
  255. #define MAX_TYPE_NAMES 128
  256. PUNICODE_STRING *TypeNames;
  257. UNICODE_STRING UnknownTypeIndex;
  258. ////////////////////////////////////////////////////////////////////////////////////////////
  259. //
  260. // main
  261. //
  262. ////////////////////////////////////////////////////////////////////////////////////////////
  263. int __cdecl
  264. main(
  265. int argc,
  266. CHAR *argv[],
  267. CHAR *envp[]
  268. )
  269. {
  270. CHAR FileNameBuffer[ 32 ];
  271. CHAR *FilePart;
  272. CHAR *s;
  273. NTSTATUS Status;
  274. PRTL_DEBUG_INFORMATION p;
  275. ULONG QueryDebugProcessFlags;
  276. ULONG HeapNumber;
  277. PRTL_HEAP_INFORMATION HeapInfo;
  278. BOOLEAN WasEnabled;
  279. BOOL bSta;
  280. DWORD dwEventState = WAIT_TIMEOUT;
  281. SYSTEMTIME st;
  282. DWORD CompNameLength = MAX_COMPUTERNAME_LENGTH + 1;
  283. CHAR CompName[MAX_COMPUTERNAME_LENGTH + 1];
  284. //
  285. // Before anything else check if we need to dispatch the command line
  286. // to the umdh parser.
  287. //
  288. if (argc >= 2 && _stricmp (argv[1], "-umdh") == 0) {
  289. UmdhMain (argc - 1, argv + 1);
  290. }
  291. //
  292. // Boost our priority in case a service is higher than us.
  293. //
  294. //EnablePrivilege( SE_INC_BASE_PRIORITY_NAME );
  295. bSta= SetPriorityClass( GetCurrentProcess(), HIGH_PRIORITY_CLASS );
  296. if( !bSta ) printf("SetPriorityClass failed: %d\n",GetLastError());
  297. bSta= SetThreadPriority( GetCurrentProcess(), THREAD_PRIORITY_HIGHEST );;
  298. if( !bSta ) printf("SetThreadPriority failed: %d\n",GetLastError());
  299. InitializeSymbolPathEnvVar();
  300. ProcessId = 0xFFFFFFFF;
  301. OutputFile = NULL;
  302. OutputFileName[ 0 ] = '\0';
  303. while (--argc) {
  304. s = *++argv;
  305. if (*s == '/' || *s == '-') {
  306. while (*++s) {
  307. switch (tolower(*s)) {
  308. case 'v':
  309. case 'V':
  310. fVerbose = TRUE;
  311. break;
  312. case 'i':
  313. case 'I':
  314. fIgnoreBackTraces = TRUE;
  315. break;
  316. case 'b':
  317. case 'B':
  318. fDumpBackTraces = TRUE;
  319. break;
  320. case 'g':
  321. case 'G':
  322. fDumpHeapHogs = TRUE;
  323. break;
  324. case 'h':
  325. case 'H':
  326. fDumpHeapEntries = TRUE;
  327. break;
  328. case 't':
  329. case 'T':
  330. fDumpHeapTags = TRUE;
  331. break;
  332. case 'l':
  333. case 'L':
  334. fDumpLocks = TRUE;
  335. break;
  336. case 'm':
  337. case 'M':
  338. fDumpModules = TRUE;
  339. break;
  340. case 'o':
  341. case 'O':
  342. fDumpSystemObjects = TRUE;
  343. break;
  344. case 'k':
  345. case 'K':
  346. fDumpSystemProcesses = TRUE;
  347. break;
  348. case 's':
  349. case 'S':
  350. fDumpHeapSummaries = TRUE;
  351. break;
  352. case 'p':
  353. case 'P':
  354. if (--argc) {
  355. ProcessId = atoi( *++argv );
  356. if (ProcessId == 0) {
  357. fDumpKernelModeInformation = TRUE;
  358. }
  359. }
  360. else {
  361. Usage();
  362. }
  363. break;
  364. case 'r':
  365. case 'R':
  366. if (--argc) {
  367. dwTimeInterval = atoi( *++argv );
  368. if (dwTimeInterval) {
  369. fRepetitive = TRUE;
  370. dwCurrentIteration = 1;
  371. if (dwTimeInterval > (MAXDWORD/60000))
  372. dwTimeInterval = (MAXDWORD/60000);
  373. hCtrlCEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  374. SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlCHandler, TRUE);
  375. }
  376. }
  377. else {
  378. Usage();
  379. }
  380. break;
  381. case '-':
  382. OutputFile = GetStdHandle( STD_OUTPUT_HANDLE );
  383. break;
  384. case 'f':
  385. case 'F':
  386. if (--argc) {
  387. strcpy( OutputFileName, *++argv );
  388. }
  389. else {
  390. Usage();
  391. }
  392. break;
  393. case '#':
  394. if (--argc)
  395. {
  396. BufferSize = atoi( *++argv ) * 1024 * 1024 ;
  397. }
  398. else
  399. {
  400. Usage();
  401. }
  402. break;
  403. default:
  404. Usage();
  405. }
  406. }
  407. }
  408. else {
  409. Usage();
  410. }
  411. }
  412. if (!fDumpModules && !fDumpHeapSummaries &&
  413. !fDumpHeapTags && !fDumpHeapHogs && !fDumpLocks
  414. ) {
  415. if (fDumpKernelModeInformation) {
  416. if (!fDumpSystemObjects &&
  417. !fDumpSystemProcesses
  418. ) {
  419. fDumpModules = TRUE;
  420. fDumpHeapSummaries = TRUE;
  421. fDumpHeapTags = TRUE;
  422. fDumpHeapHogs = TRUE;
  423. fDumpSystemObjects = TRUE;
  424. fDumpSystemProcesses = TRUE;
  425. }
  426. }
  427. else {
  428. fDumpHeapSummaries = TRUE;
  429. fDumpHeapHogs = TRUE;
  430. }
  431. }
  432. if ((fDumpSystemObjects || fDumpSystemProcesses) && !fDumpKernelModeInformation) {
  433. Usage();
  434. }
  435. if (OutputFile == NULL) {
  436. if (OutputFileName[ 0 ] == '\0') {
  437. if ( ProcessId == -1 ) {
  438. sprintf( FileNameBuffer, "DH_win32.dmp" );
  439. }
  440. else if ( ProcessId == 0 ) {
  441. sprintf( FileNameBuffer, "DH_sys.dmp" );
  442. }
  443. else {
  444. sprintf( FileNameBuffer, "DH_%u.dmp", (USHORT)ProcessId );
  445. }
  446. GetFullPathName( FileNameBuffer,
  447. sizeof( OutputFileName ),
  448. OutputFileName,
  449. &FilePart
  450. );
  451. }
  452. }
  453. else {
  454. strcpy( OutputFileName, "(stdout)" );
  455. }
  456. if (fRepetitive) {
  457. strcpy(SavedFileName, OutputFileName);
  458. AdjustFileName();
  459. }
  460. Status= RtlAdjustPrivilege( SE_DEBUG_PRIVILEGE,
  461. TRUE, FALSE, &WasEnabled );
  462. if( !NT_SUCCESS(Status) ) {
  463. fprintf(stderr,"RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE) failed: %08x\n",Status);
  464. }
  465. //
  466. // Get the real process id for the windows sub-system
  467. //
  468. if (ProcessId == -1) {
  469. HANDLE Process;
  470. OBJECT_ATTRIBUTES ObjectAttributes;
  471. UNICODE_STRING UnicodeString;
  472. PROCESS_BASIC_INFORMATION BasicInfo;
  473. RtlInitUnicodeString( &UnicodeString, L"\\WindowsSS" );
  474. InitializeObjectAttributes( &ObjectAttributes,
  475. &UnicodeString,
  476. 0,
  477. NULL,
  478. NULL
  479. );
  480. Status = NtOpenProcess( &Process,
  481. PROCESS_ALL_ACCESS,
  482. &ObjectAttributes,
  483. NULL
  484. );
  485. if (NT_SUCCESS(Status)) {
  486. Status = NtQueryInformationProcess( Process,
  487. ProcessBasicInformation,
  488. (PVOID)&BasicInfo,
  489. sizeof(BasicInfo),
  490. NULL
  491. );
  492. NtClose( Process );
  493. }
  494. if (!NT_SUCCESS(Status)) {
  495. fprintf( stderr,"Unable to access Win32 server process - %08x", Status );
  496. if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
  497. fprintf( stderr,"\nUse GFLAGS.EXE to ""Enable debugging of Win32 Subsystem"" and reboot.\n" );
  498. }
  499. exit( 1 );
  500. }
  501. ProcessId = BasicInfo.UniqueProcessId;
  502. }
  503. //
  504. // Compute QueryDebugProcessFlags
  505. //
  506. QueryDebugProcessFlags = 0;
  507. if (fDumpModules) {
  508. QueryDebugProcessFlags |= RTL_QUERY_PROCESS_MODULES;
  509. }
  510. if (fDumpBackTraces || fDumpHeapHogs) {
  511. QueryDebugProcessFlags |= RTL_QUERY_PROCESS_BACKTRACES | RTL_QUERY_PROCESS_MODULES;
  512. }
  513. if (fDumpHeapSummaries) {
  514. QueryDebugProcessFlags |= RTL_QUERY_PROCESS_HEAP_SUMMARY;
  515. }
  516. if (fDumpHeapTags) {
  517. QueryDebugProcessFlags |= RTL_QUERY_PROCESS_HEAP_TAGS;
  518. }
  519. if (fDumpHeapEntries || fDumpHeapHogs) {
  520. QueryDebugProcessFlags |= RTL_QUERY_PROCESS_HEAP_ENTRIES;
  521. }
  522. if (fDumpLocks) {
  523. QueryDebugProcessFlags |= RTL_QUERY_PROCESS_LOCKS;
  524. }
  525. // Starting the main loop that does most of the work. This will only
  526. // execute once unless fRepetitive is set
  527. do {
  528. //
  529. // Open the output file
  530. //
  531. fprintf( stderr, "DH: Writing dump output to %s", OutputFileName );
  532. if (OutputFile == NULL) {
  533. OutputFile = CreateFile( OutputFileName,
  534. GENERIC_WRITE,
  535. FILE_SHARE_READ | FILE_SHARE_WRITE,
  536. NULL,
  537. CREATE_ALWAYS,
  538. 0,
  539. NULL
  540. );
  541. if ( OutputFile == INVALID_HANDLE_VALUE ) {
  542. fprintf( stderr, " - unable to open, error == %u\n", GetLastError() );
  543. exit( 1 );
  544. }
  545. }
  546. fprintf( stderr, "\n" );
  547. //Output a Timestamp to the first line of the file
  548. GetLocalTime(&st);
  549. GetComputerName(CompName, &CompNameLength);
  550. sprintf( DumpLine, "DH: Logtime %02u/%02u/%4u-%02u:%02u - Machine=%s - PID=%u\n", st.wMonth,
  551. st.wDay, st.wYear, (st.wHour <= 12) ? st.wHour : (st.wHour - 12), st.wMinute,
  552. CompName, ProcessId);
  553. DumpOutputString();
  554. if (fDumpKernelModeInformation) {
  555. p = RtlQuerySystemDebugInformation( QueryDebugProcessFlags );
  556. if (p == NULL) {
  557. fprintf( stderr, "DH: Unable to query kernel mode information.\n" );
  558. exit( 1 );
  559. }
  560. Status = STATUS_SUCCESS;
  561. }
  562. else {
  563. p = RtlCreateQueryDebugBuffer( BufferSize, FALSE );
  564. printf("RtlCreateQueryDebugBuffer returns: %p\n",p);
  565. Status = RtlQueryProcessDebugInformation( (HANDLE)ProcessId,
  566. QueryDebugProcessFlags,
  567. p
  568. );
  569. if (NT_SUCCESS( Status )) {
  570. printf("RtpQueryProcessDebugInformation\n");
  571. printf(" ProcessId: %d ProcessFlags: %08x Status %08x\n",
  572. ProcessId, QueryDebugProcessFlags, Status );
  573. if ((fDumpBackTraces || fDumpHeapHogs) && p->BackTraces == NULL) {
  574. printf("p->BackTraces: %p\n",p->BackTraces);
  575. fputs( "DH: Unable to query stack back trace information\n"
  576. " Be sure target process was launched with the\n"
  577. " 'Create user mode stack trace DB' enabled\n"
  578. " Use the GFLAGS.EXE application to do this.\n"
  579. , stderr);
  580. }
  581. if (fDumpHeapTags) {
  582. HeapInfo = &p->Heaps->Heaps[ 0 ];
  583. for (HeapNumber = 0; HeapNumber < p->Heaps->NumberOfHeaps; HeapNumber++) {
  584. if (HeapInfo->Tags != NULL && HeapInfo->NumberOfTags != 0) {
  585. break;
  586. }
  587. }
  588. if (HeapNumber == p->Heaps->NumberOfHeaps) {
  589. fputs( "DH: Unable to query heap tag information\n"
  590. " Be sure target process was launched with the\n"
  591. " 'Enable heap tagging' option enabled.\n"
  592. " Use the GFLAGS.EXE application to do this.\n"
  593. , stderr);
  594. }
  595. }
  596. }
  597. else {
  598. fprintf(stderr,"RtlQueryProcessDebugInformation failed: %08x\n",Status);
  599. }
  600. }
  601. if (NT_SUCCESS( Status )) {
  602. if (!fIgnoreBackTraces &&
  603. p->Modules != NULL &&
  604. LoadSymbolsForModules( p->Modules ) &&
  605. p->BackTraces != NULL
  606. ) {
  607. ComputeSymbolicBackTraces( p->BackTraces );
  608. }
  609. if (fDumpModules) {
  610. DumpModules( p->Modules );
  611. }
  612. if (!fIgnoreBackTraces && fDumpBackTraces) {
  613. DumpBackTraces();
  614. }
  615. if (p->Heaps) {
  616. DumpHeaps( p->Heaps, fDumpHeapSummaries, fDumpHeapHogs, fDumpHeapTags, fDumpHeapEntries );
  617. }
  618. if (fDumpLocks) {
  619. DumpLocks( p->Locks );
  620. }
  621. if (fDumpSystemObjects) {
  622. DumpObjects();
  623. DumpHandles();
  624. }
  625. if (fDumpSystemProcesses) {
  626. DumpSystemProcesses();
  627. }
  628. }
  629. else {
  630. fprintf( stderr, "Failed to query process, %x\n", Status );
  631. }
  632. RtlDestroyQueryDebugBuffer( p );
  633. // Are we in repetitive mode
  634. if (fRepetitive) {
  635. if (hCtrlCEvent)
  636. dwEventState = WaitForSingleObject(hCtrlCEvent,0);
  637. if (dwEventState == WAIT_OBJECT_0)
  638. fRepetitive = FALSE;
  639. else {
  640. // Lets let the user know we are not hung
  641. GetLocalTime(&st);
  642. printf("Starting at %u:%02u - Sleeping for %u Minute(s)\n",
  643. (st.wHour <= 12) ? st.wHour : (st.wHour - 12), st.wMinute, dwTimeInterval);
  644. // lets sleep for our time interval unless signaled with a ctrl-c
  645. if (hCtrlCEvent)
  646. dwEventState = WaitForSingleObject(hCtrlCEvent,(dwTimeInterval * 60000));
  647. else
  648. Sleep(dwTimeInterval * 60000);
  649. // Don't want to close our handle to stdout
  650. if (strcmp(SavedFileName, "(stdout)")){
  651. CloseHandle( OutputFile );
  652. OutputFile = NULL;
  653. }
  654. // Set up for the next iteration.
  655. AdjustFileName();
  656. //Adjust the pointers to this nasty global memory blob
  657. VirtualFree(SymbolicInfoBase, 4096*4096, MEM_DECOMMIT);
  658. SymbolicInfoCurrent = SymbolicInfoBase;
  659. SymbolicInfoCommitNext = SymbolicInfoBase;
  660. }
  661. }
  662. } while (fRepetitive); //do loop
  663. CloseHandle( OutputFile );
  664. VirtualFree(SymbolicInfoBase, 0, MEM_RELEASE);
  665. if (hCtrlCEvent)
  666. CloseHandle(hCtrlCEvent);
  667. return 0;
  668. }
  669. ////////////////////////////////////////////////////////////////////////////////////////////
  670. BOOL
  671. SymbolCallbackFunction(
  672. HANDLE hProcess,
  673. ULONG ActionCode,
  674. #ifdef _WIN64
  675. ULONG_PTR CallbackData,
  676. ULONG_PTR UserContext
  677. #else
  678. PVOID CallbackData,
  679. PVOID UserContext
  680. #endif
  681. )
  682. {
  683. PIMAGEHLP_DEFERRED_SYMBOL_LOAD idsl;
  684. idsl = (PIMAGEHLP_DEFERRED_SYMBOL_LOAD) CallbackData;
  685. switch( ActionCode ) {
  686. case CBA_DEFERRED_SYMBOL_LOAD_START:
  687. _strlwr( idsl->FileName );
  688. fprintf( stderr, "Loading symbols for 0x%08x %16s - ",
  689. idsl->BaseOfImage,
  690. idsl->FileName
  691. );
  692. fflush( stderr );
  693. return TRUE;
  694. case CBA_DEFERRED_SYMBOL_LOAD_FAILURE:
  695. fprintf( stderr, "*** Error: could not load symbols\n", idsl->FileName );
  696. fflush( stderr );
  697. return TRUE;
  698. case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE:
  699. fprintf( stderr, "done\n" );
  700. fflush( stderr );
  701. return TRUE;
  702. case CBA_SYMBOLS_UNLOADED:
  703. fprintf( stderr, "Symbols unloaded for 0x%08x %s\n",
  704. idsl->BaseOfImage,
  705. idsl->FileName
  706. );
  707. fflush( stderr );
  708. return TRUE;
  709. default:
  710. return FALSE;
  711. }
  712. return FALSE;
  713. }
  714. ////////////////////////////////////////////////////////////////////////////////////////////
  715. #define MAX_SYMNAME_SIZE 1024
  716. #define SYM_BUFFER_SIZE (sizeof(IMAGEHLP_SYMBOL)+MAX_SYMNAME_SIZE)
  717. CHAR symBuffer[SYM_BUFFER_SIZE];
  718. PIMAGEHLP_SYMBOL sym;
  719. PIMAGEHLP_SYMBOL sym = (PIMAGEHLP_SYMBOL) symBuffer;
  720. BOOLEAN
  721. LoadSymbolsForModules(
  722. PRTL_PROCESS_MODULES Modules1
  723. )
  724. {
  725. PRTL_PROCESS_MODULE_INFORMATION ModuleInfo;
  726. ULONG ModuleNumber;
  727. PVOID MaxUserModeAddress;
  728. SymSetOptions( SYMOPT_CASE_INSENSITIVE | SYMOPT_UNDNAME | SYMOPT_NO_CPP );
  729. sym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
  730. sym->MaxNameLength = MAX_SYMNAME_SIZE;
  731. SymInitialize( (HANDLE)ProcessId, NULL, FALSE );
  732. SymRegisterCallback( (HANDLE)ProcessId, SymbolCallbackFunction, 0 );
  733. if (!NT_SUCCESS(NtQuerySystemInformation(SystemRangeStartInformation,
  734. &MaxUserModeAddress,
  735. sizeof(MaxUserModeAddress),
  736. NULL))) {
  737. // assume usermode is the low half of the address space
  738. MaxUserModeAddress = (PVOID)MAXLONG_PTR;
  739. }
  740. Modules = Modules1;
  741. ModuleInfo = &Modules->Modules[ 0 ];
  742. for (ModuleNumber=0; ModuleNumber<Modules->NumberOfModules; ModuleNumber++) {
  743. if (!fDumpKernelModeInformation || ModuleInfo->ImageBase >= MaxUserModeAddress) {
  744. SymLoadModule( (HANDLE)ProcessId,
  745. NULL,
  746. ModuleInfo->FullPathName,
  747. NULL,
  748. (ULONG_PTR)ModuleInfo->ImageBase,
  749. ModuleInfo->ImageSize
  750. );
  751. }
  752. ModuleInfo += 1;
  753. }
  754. return TRUE;
  755. }
  756. ////////////////////////////////////////////////////////////////////////////////////////////
  757. static CHAR DllNameBuffer[ MAX_PATH ];
  758. PCHAR
  759. FindDllHandleName(
  760. PVOID DllHandle
  761. )
  762. {
  763. PRTL_PROCESS_MODULE_INFORMATION ModuleInfo;
  764. LPSTR DllName;
  765. ULONG ModuleNumber;
  766. ModuleInfo = &Modules->Modules[ 0 ];
  767. for (ModuleNumber=0; ModuleNumber<Modules->NumberOfModules; ModuleNumber++) {
  768. if (ModuleInfo->ImageBase == DllHandle) {
  769. strcpy( DllNameBuffer, &ModuleInfo->FullPathName[ ModuleInfo->OffsetToFileName ] );
  770. if ((DllName = strchr( DllNameBuffer, '.' )) != NULL) {
  771. *DllName = '\0';
  772. }
  773. return DllNameBuffer;
  774. }
  775. ModuleInfo += 1;
  776. }
  777. return "UNKNOWN";
  778. }
  779. ////////////////////////////////////////////////////////////////////////////////////////////
  780. PUCHAR
  781. SaveSymbolicBackTrace(
  782. IN ULONG Depth,
  783. IN PVOID BackTrace[]
  784. )
  785. {
  786. NTSTATUS Status;
  787. ULONG i, FileNameLength, SymbolOffset;
  788. PCHAR s, SymbolicBackTrace;
  789. if (Depth == 0) {
  790. return NULL;
  791. }
  792. if (SymbolicInfoBase == NULL) {
  793. SymbolicInfoBase = (PUCHAR)VirtualAlloc( NULL,
  794. 4096 * 4096,
  795. MEM_RESERVE,
  796. PAGE_READWRITE
  797. );
  798. if (SymbolicInfoBase == NULL) {
  799. fprintf(stderr,"DH: VirtualAlloc(4096*4096...) failed: GetLastError()= %d\n",GetLastError());
  800. return NULL;
  801. }
  802. SymbolicInfoCurrent = SymbolicInfoBase;
  803. SymbolicInfoCommitNext = SymbolicInfoBase;
  804. }
  805. i = 4096;
  806. if ((SymbolicInfoCurrent + i - 1) > SymbolicInfoCommitNext) {
  807. if (!VirtualAlloc( SymbolicInfoCommitNext,
  808. i,
  809. MEM_COMMIT,
  810. PAGE_READWRITE
  811. )
  812. ) {
  813. fprintf( stderr, "DH: Exceeded 16MB of space for symbolic stack back traces.\n" );
  814. fprintf( stderr, "DH: virtualalloc(%p,%d...)\n",SymbolicInfoCommitNext,i);
  815. return NULL;
  816. }
  817. SymbolicInfoCommitNext += i;
  818. }
  819. s = SymbolicInfoCurrent;
  820. SymbolicBackTrace = s;
  821. for (i=0; i<Depth; i++) {
  822. if (BackTrace[ i ] == 0) {
  823. break;
  824. }
  825. s += GetDhSymbolicNameForAddress( (HANDLE)ProcessId, (ULONG_PTR)BackTrace[ i ], s, MAX_PATH );
  826. *s++ = '\0';
  827. }
  828. *s++ = '\0';
  829. SymbolicInfoCurrent = s;
  830. return SymbolicBackTrace;
  831. }
  832. ////////////////////////////////////////////////////////////////////////////////////////////
  833. BOOLEAN
  834. ComputeSymbolicBackTraces(
  835. PRTL_PROCESS_BACKTRACES BackTraces1
  836. )
  837. {
  838. PRTL_PROCESS_BACKTRACE_INFORMATION BackTraceInfo;
  839. ULONG BackTraceIndex, NumberOfBackTraces;
  840. BackTraces = BackTraces1;
  841. NumberOfBackTraces = BackTraces->NumberOfBackTraces;
  842. BackTraceInfo = &BackTraces->BackTraces[ 0 ];
  843. BackTraceIndex = 0;
  844. while (NumberOfBackTraces--) {
  845. if (!(BackTraceIndex++ % 50)) {
  846. printf( "Getting symbols for Stack Back Trace %05u\r", BackTraceIndex );
  847. }
  848. BackTraceInfo->SymbolicBackTrace = SaveSymbolicBackTrace( BackTraceInfo->Depth,
  849. &BackTraceInfo->BackTrace[ 0 ]
  850. );
  851. BackTraceInfo += 1;
  852. }
  853. return TRUE;
  854. }
  855. ////////////////////////////////////////////////////////////////////////////////////////////
  856. PRTL_PROCESS_BACKTRACE_INFORMATION
  857. FindBackTrace(
  858. IN ULONG BackTraceIndex
  859. )
  860. {
  861. PRTL_PROCESS_BACKTRACE_INFORMATION BackTraceInfo;
  862. if (!BackTraceIndex ||
  863. BackTraces == NULL ||
  864. BackTraceIndex >= BackTraces->NumberOfBackTraces
  865. ) {
  866. return( NULL );
  867. }
  868. return &BackTraces->BackTraces[ BackTraceIndex-1 ];
  869. }
  870. ////////////////////////////////////////////////////////////////////////////////////////////
  871. VOID
  872. FormatHeapHeader(
  873. PRTL_HEAP_INFORMATION HeapInfo,
  874. PCHAR Title
  875. )
  876. {
  877. CHAR TempBuffer[ 64 ];
  878. PCHAR s;
  879. if (HeapInfo->BaseAddress == (PVOID)IntToPtr(SystemPagedPoolInformation)) {
  880. s = "Paged Pool";
  881. }
  882. else
  883. if (HeapInfo->BaseAddress == (PVOID)IntToPtr(SystemNonPagedPoolInformation)) {
  884. s = "NonPaged Pool";
  885. }
  886. else {
  887. sprintf( TempBuffer, "Heap %p", HeapInfo->BaseAddress );
  888. s = TempBuffer;
  889. }
  890. sprintf( DumpLine, "\n\n*********** %s %s ********************\n\n", s, Title );
  891. DumpOutputString();
  892. }
  893. ////////////////////////////////////////////////////////////////////////////////////////////
  894. VOID
  895. DumpModules(
  896. PRTL_PROCESS_MODULES Modules
  897. )
  898. {
  899. PRTL_PROCESS_MODULE_INFORMATION ModuleInfo;
  900. ULONG ModuleNumber;
  901. if (fVerbose) {
  902. fprintf( stderr, "DH: Dumping module information.\n" );
  903. }
  904. ModuleInfo = &Modules->Modules[ 0 ];
  905. sprintf( DumpLine, "\n\n*********** Module Information ********************\n\n" );
  906. DumpOutputString();
  907. sprintf( DumpLine, "Number of loaded modules: %u\n", Modules->NumberOfModules );
  908. DumpOutputString();
  909. ModuleNumber = 0;
  910. while (ModuleNumber++ < Modules->NumberOfModules) {
  911. sprintf( DumpLine, "Module%02u (%02u,%02u,%02u): [%p .. %p] %s\n",
  912. ModuleNumber,
  913. (ULONG)ModuleInfo->LoadOrderIndex,
  914. (ULONG)ModuleInfo->InitOrderIndex,
  915. (ULONG)ModuleInfo->LoadCount,
  916. ModuleInfo->ImageBase,
  917. (ULONG_PTR)ModuleInfo->ImageBase + ModuleInfo->ImageSize - 1,
  918. ModuleInfo->FullPathName
  919. );
  920. DumpOutputString();
  921. ModuleInfo++;
  922. }
  923. return;
  924. }
  925. ////////////////////////////////////////////////////////////////////////////////////////////
  926. VOID
  927. DumpBackTraces( VOID )
  928. {
  929. PRTL_PROCESS_BACKTRACE_INFORMATION BackTraceInfo;
  930. ULONG BackTraceIndex;
  931. CHAR *s;
  932. if (BackTraces == NULL) {
  933. return;
  934. }
  935. if (fVerbose) {
  936. fprintf( stderr, "DH: Dumping back trace information.\n" );
  937. }
  938. sprintf( DumpLine, "\n\n*********** BackTrace Information ********************\n\n" );
  939. DumpOutputString();
  940. sprintf( DumpLine, "Number of back traces: %u Looked Up Count: %u\n",
  941. BackTraces->NumberOfBackTraces - 1,
  942. BackTraces->NumberOfBackTraceLookups
  943. );
  944. DumpOutputString();
  945. sprintf( DumpLine, "Reserved Memory: %08x Committed Memory: %08x\n",
  946. BackTraces->ReservedMemory,
  947. BackTraces->CommittedMemory
  948. );
  949. DumpOutputString();
  950. BackTraceInfo = BackTraces->BackTraces;
  951. for (BackTraceIndex=0; BackTraceIndex<BackTraces->NumberOfBackTraces; BackTraceIndex++) {
  952. sprintf( DumpLine, "BackTrace%05lu\n", BackTraceInfo->Index );
  953. DumpOutputString();
  954. if (BackTraceInfo->SymbolicBackTrace == NULL) {
  955. BackTraceInfo->SymbolicBackTrace = SaveSymbolicBackTrace( BackTraceInfo->Depth,
  956. &BackTraceInfo->BackTrace[ 0 ]
  957. );
  958. }
  959. if (s = BackTraceInfo->SymbolicBackTrace) {
  960. while (*s) {
  961. sprintf( DumpLine, " %s\n", s );
  962. DumpOutputString();
  963. while (*s++) {
  964. }
  965. }
  966. }
  967. BackTraceInfo += 1;
  968. }
  969. }
  970. ////////////////////////////////////////////////////////////////////////////////////////////
  971. typedef struct _VA_CHUNK {
  972. ULONG_PTR Base;
  973. ULONG_PTR End;
  974. ULONG_PTR Committed;
  975. } VA_CHUNK, *PVA_CHUNK;
  976. VOID
  977. DumpHeapSummary(
  978. PRTL_HEAP_INFORMATION HeapInfo
  979. )
  980. {
  981. PRTL_PROCESS_BACKTRACE_INFORMATION BackTraceInfo;
  982. PUCHAR s;
  983. PRTL_HEAP_ENTRY p;
  984. PCHAR HeapEntryAddress;
  985. ULONG i, HeapEntryNumber;
  986. SIZE_T AddressSpaceUsed;
  987. ULONG NumberOfChunks;
  988. ULONG MaxNumberOfChunks;
  989. PVA_CHUNK Chunks, NewChunks;
  990. MaxNumberOfChunks = 0;
  991. NumberOfChunks = 0;
  992. Chunks = NULL;
  993. p = HeapInfo->Entries;
  994. if (p != NULL && HeapInfo->NumberOfEntries != 0) {
  995. HeapEntryAddress = NULL;
  996. for (HeapEntryNumber=0; HeapEntryNumber<HeapInfo->NumberOfEntries; HeapEntryNumber++) {
  997. if (p->Flags != 0xFF && p->Flags & RTL_HEAP_SEGMENT) {
  998. if (NumberOfChunks == MaxNumberOfChunks) {
  999. MaxNumberOfChunks += 16;
  1000. NewChunks = RtlAllocateHeap( RtlProcessHeap(),
  1001. HEAP_ZERO_MEMORY,
  1002. MaxNumberOfChunks * sizeof( VA_CHUNK )
  1003. );
  1004. if (Chunks != NULL) {
  1005. if (NewChunks != NULL) {
  1006. RtlMoveMemory( NewChunks, Chunks, NumberOfChunks * sizeof( VA_CHUNK ) );
  1007. }
  1008. RtlFreeHeap( RtlProcessHeap(), 0, Chunks );
  1009. }
  1010. Chunks = NewChunks;
  1011. if (Chunks == NULL) {
  1012. NumberOfChunks = 0;
  1013. break;
  1014. }
  1015. }
  1016. HeapEntryAddress = (PCHAR)p->u.s2.FirstBlock;
  1017. Chunks[ NumberOfChunks ].Base = (ULONG_PTR)HeapEntryAddress & ~(4096-1);
  1018. if (((ULONG_PTR)HeapEntryAddress - (ULONG_PTR)Chunks[ NumberOfChunks ].Base) < 32) {
  1019. HeapEntryAddress = (PCHAR)Chunks[ NumberOfChunks ].Base;
  1020. }
  1021. Chunks[ NumberOfChunks ].Committed = p->u.s2.CommittedSize;
  1022. NumberOfChunks += 1;
  1023. }
  1024. else {
  1025. HeapEntryAddress += p->Size;
  1026. if (NumberOfChunks > 0) {
  1027. Chunks[ NumberOfChunks-1 ].End = (ULONG_PTR)HeapEntryAddress;
  1028. }
  1029. }
  1030. p += 1;
  1031. }
  1032. }
  1033. sprintf( DumpLine, " Flags: %08x\n", HeapInfo->Flags );
  1034. DumpOutputString();
  1035. sprintf( DumpLine, " Number Of Entries: %u\n", HeapInfo->NumberOfEntries );
  1036. DumpOutputString();
  1037. sprintf( DumpLine, " Number Of Tags: %u\n", HeapInfo->NumberOfTags );
  1038. DumpOutputString();
  1039. sprintf( DumpLine, " Bytes Allocated: %08x\n", HeapInfo->BytesAllocated );
  1040. DumpOutputString();
  1041. sprintf( DumpLine, " Bytes Committed: %08x\n", HeapInfo->BytesCommitted );
  1042. DumpOutputString();
  1043. sprintf( DumpLine, " Total FreeSpace: %08x\n", HeapInfo->BytesCommitted -
  1044. HeapInfo->BytesAllocated );
  1045. DumpOutputString();
  1046. sprintf( DumpLine, " Number of Virtual Address chunks used: %u\n", NumberOfChunks );
  1047. DumpOutputString();
  1048. AddressSpaceUsed = 0;
  1049. for (i=0; i<NumberOfChunks; i++) {
  1050. sprintf( DumpLine, " Chunk[ %2u ]: [%08x .. %08x) %08x committed\n",
  1051. i+1,
  1052. Chunks[i].Base,
  1053. Chunks[i].End,
  1054. Chunks[i].Committed
  1055. );
  1056. DumpOutputString();
  1057. AddressSpaceUsed += (Chunks[i].End - Chunks[i].Base);
  1058. }
  1059. sprintf( DumpLine, " Address Space Used: %08x\n", AddressSpaceUsed );
  1060. DumpOutputString();
  1061. sprintf( DumpLine, " Entry Overhead: %u\n", HeapInfo->EntryOverhead );
  1062. DumpOutputString();
  1063. sprintf( DumpLine, " Creator: (Backtrace%05lu)\n", HeapInfo->CreatorBackTraceIndex );
  1064. DumpOutputString();
  1065. BackTraceInfo = FindBackTrace( HeapInfo->CreatorBackTraceIndex );
  1066. if (BackTraceInfo != NULL && (s = BackTraceInfo->SymbolicBackTrace)) {
  1067. while (*s) {
  1068. sprintf( DumpLine, " %s\n", s );
  1069. DumpOutputString();
  1070. while (*s++) {
  1071. }
  1072. }
  1073. }
  1074. return;
  1075. }
  1076. ////////////////////////////////////////////////////////////////////////////////////////////
  1077. __inline int DiffSizeT(SIZE_T s1, SIZE_T s2)
  1078. {
  1079. if (s1 == s2)
  1080. return 0;
  1081. if (s1 > s2)
  1082. return -1;
  1083. else
  1084. return 1;
  1085. }
  1086. ////////////////////////////////////////////////////////////////////////////////////////////
  1087. int
  1088. __cdecl
  1089. CmpTagsRoutine(
  1090. const void *Element1,
  1091. const void *Element2
  1092. )
  1093. {
  1094. return( DiffSizeT((*(PRTL_HEAP_TAG *)Element2)->BytesAllocated,
  1095. (*(PRTL_HEAP_TAG *)Element1)->BytesAllocated)
  1096. );
  1097. }
  1098. ////////////////////////////////////////////////////////////////////////////////////////////
  1099. PRTL_HEAP_TAG
  1100. FindTagEntry(
  1101. PRTL_HEAP_INFORMATION HeapInfo,
  1102. ULONG TagIndex
  1103. )
  1104. {
  1105. if (TagIndex == 0 || (TagIndex & ~HEAP_PSEUDO_TAG_FLAG) >= HeapInfo->NumberOfTags) {
  1106. return NULL;
  1107. }
  1108. else {
  1109. if (TagIndex & HEAP_PSEUDO_TAG_FLAG) {
  1110. return HeapInfo->Tags + (TagIndex & ~HEAP_PSEUDO_TAG_FLAG);
  1111. }
  1112. else {
  1113. return HeapInfo->Tags + HeapInfo->NumberOfPseudoTags + TagIndex;
  1114. }
  1115. }
  1116. }
  1117. ////////////////////////////////////////////////////////////////////////////////////////////
  1118. VOID
  1119. DumpHeapTags(
  1120. PRTL_HEAP_INFORMATION HeapInfo
  1121. )
  1122. {
  1123. PRTL_HEAP_TAG *TagEntries, TagEntry;
  1124. ULONG TagIndex;
  1125. PUCHAR s;
  1126. UCHAR HeapName[ 64 ];
  1127. if (HeapInfo->Tags == NULL || HeapInfo->NumberOfTags == 0) {
  1128. return;
  1129. }
  1130. TagEntries = RtlAllocateHeap( RtlProcessHeap(),
  1131. HEAP_ZERO_MEMORY,
  1132. HeapInfo->NumberOfTags * sizeof( PRTL_HEAP_TAG )
  1133. );
  1134. if (TagEntries == NULL) {
  1135. fprintf(stderr,"DH: RtlAllocateHeap failed at %d\n",__LINE__ );
  1136. return;
  1137. }
  1138. for (TagIndex=1; TagIndex<HeapInfo->NumberOfTags; TagIndex++) {
  1139. TagEntries[ TagIndex-1 ] = &HeapInfo->Tags[ TagIndex ];
  1140. }
  1141. qsort( (void *)TagEntries,
  1142. HeapInfo->NumberOfTags - 1,
  1143. sizeof( PRTL_HEAP_TAG ),
  1144. CmpTagsRoutine
  1145. );
  1146. TagEntry = &HeapInfo->Tags[ HeapInfo->NumberOfPseudoTags ];
  1147. if (HeapInfo->NumberOfTags > HeapInfo->NumberOfPseudoTags &&
  1148. TagEntry->TagName[ 0 ] != UNICODE_NULL
  1149. ) {
  1150. sprintf( HeapName, "Tags for %ws heap", TagEntry->TagName );
  1151. }
  1152. else {
  1153. sprintf( HeapName, "Tags" );
  1154. }
  1155. FormatHeapHeader( HeapInfo, HeapName );
  1156. sprintf( DumpLine, " Allocs Frees Diff Bytes Tag\n" );
  1157. DumpOutputString();
  1158. for (TagIndex=1; TagIndex<(HeapInfo->NumberOfTags-1); TagIndex++) {
  1159. TagEntry = TagEntries[ TagIndex ];
  1160. if (TagEntry->BytesAllocated != 0) {
  1161. sprintf( DumpLine, " %08x %08x %08x %08x %ws\n",
  1162. TagEntry->NumberOfAllocations,
  1163. TagEntry->NumberOfFrees,
  1164. TagEntry->NumberOfAllocations - TagEntry->NumberOfFrees,
  1165. TagEntry->BytesAllocated,
  1166. TagEntry->TagName
  1167. );
  1168. DumpOutputString();
  1169. }
  1170. }
  1171. RtlFreeHeap( RtlProcessHeap(), 0, TagEntries );
  1172. return;
  1173. }
  1174. ////////////////////////////////////////////////////////////////////////////////////////////
  1175. typedef struct _HEAP_CALLER {
  1176. SIZE_T TotalAllocated;
  1177. USHORT NumberOfAllocations;
  1178. USHORT CallerBackTraceIndex;
  1179. PRTL_HEAP_TAG TagEntry;
  1180. } HEAP_CALLER, *PHEAP_CALLER;
  1181. int
  1182. __cdecl
  1183. CmpCallerRoutine(
  1184. const void *Element1,
  1185. const void *Element2
  1186. )
  1187. {
  1188. return( DiffSizeT(((PHEAP_CALLER)Element2)->TotalAllocated,
  1189. ((PHEAP_CALLER)Element1)->TotalAllocated)
  1190. );
  1191. }
  1192. ////////////////////////////////////////////////////////////////////////////////////////////
  1193. VOID
  1194. DumpHeapHogs(
  1195. PRTL_HEAP_INFORMATION HeapInfo
  1196. )
  1197. {
  1198. PRTL_PROCESS_BACKTRACE_INFORMATION BackTraceInfo;
  1199. PUCHAR s;
  1200. ULONG BackTraceNumber, HeapEntryNumber;
  1201. USHORT TagIndex;
  1202. PRTL_HEAP_ENTRY p;
  1203. PHEAP_CALLER HogList;
  1204. if (BackTraces == NULL) {
  1205. return;
  1206. }
  1207. HogList = (PHEAP_CALLER)VirtualAlloc( NULL,
  1208. BackTraces->NumberOfBackTraces *
  1209. sizeof( HEAP_CALLER ),
  1210. MEM_COMMIT,
  1211. PAGE_READWRITE
  1212. );
  1213. if (HogList == NULL) {
  1214. fprintf(stderr,"DH: VirtualAlloc failed at %d size: %d\n",__LINE__,
  1215. BackTraces->NumberOfBackTraces * sizeof( HEAP_CALLER ) );
  1216. return;
  1217. }
  1218. p = HeapInfo->Entries;
  1219. if (p == NULL) {
  1220. VirtualFree( HogList, 0, MEM_RELEASE );
  1221. return;
  1222. }
  1223. for (HeapEntryNumber=0; HeapEntryNumber<HeapInfo->NumberOfEntries; HeapEntryNumber++) {
  1224. if (p->Flags & RTL_HEAP_BUSY) {
  1225. if (p->AllocatorBackTraceIndex >= BackTraces->NumberOfBackTraces) {
  1226. p->AllocatorBackTraceIndex = 0;
  1227. }
  1228. HogList[ p->AllocatorBackTraceIndex ].NumberOfAllocations++;
  1229. HogList[ p->AllocatorBackTraceIndex ].TotalAllocated += p->Size;
  1230. if (p->u.s1.Tag != 0) {
  1231. HogList[ p->AllocatorBackTraceIndex ].TagEntry = FindTagEntry( HeapInfo, p->u.s1.Tag );
  1232. }
  1233. else
  1234. if (HeapInfo->NumberOfPseudoTags != 0) {
  1235. TagIndex = HEAP_PSEUDO_TAG_FLAG;
  1236. if (p->Size < (HeapInfo->NumberOfPseudoTags * HeapInfo->PseudoTagGranularity)) {
  1237. TagIndex |= (p->Size / HeapInfo->PseudoTagGranularity);
  1238. }
  1239. HogList[ p->AllocatorBackTraceIndex ].TagEntry = FindTagEntry( HeapInfo, TagIndex );
  1240. }
  1241. }
  1242. p++;
  1243. }
  1244. for (BackTraceNumber = 1;
  1245. BackTraceNumber < BackTraces->NumberOfBackTraces;
  1246. BackTraceNumber++
  1247. ) {
  1248. HogList[ BackTraceNumber ].CallerBackTraceIndex = (USHORT)BackTraceNumber;
  1249. }
  1250. qsort( (void *)HogList,
  1251. BackTraces->NumberOfBackTraces,
  1252. sizeof( HEAP_CALLER ),
  1253. CmpCallerRoutine
  1254. );
  1255. FormatHeapHeader( HeapInfo, "Hogs" );
  1256. for (BackTraceNumber=0;
  1257. BackTraceNumber<BackTraces->NumberOfBackTraces;
  1258. BackTraceNumber++
  1259. ) {
  1260. if (HogList[ BackTraceNumber ].TotalAllocated != 0) {
  1261. BackTraceInfo = FindBackTrace( HogList[ BackTraceNumber ].CallerBackTraceIndex );
  1262. sprintf( DumpLine, "%08x bytes",
  1263. HogList[ BackTraceNumber ].TotalAllocated
  1264. );
  1265. DumpOutputString();
  1266. if (HogList[ BackTraceNumber ].NumberOfAllocations > 1) {
  1267. sprintf( DumpLine, " in %04lx allocations (@ %04lx)",
  1268. HogList[ BackTraceNumber ].NumberOfAllocations,
  1269. HogList[ BackTraceNumber ].TotalAllocated /
  1270. HogList[ BackTraceNumber ].NumberOfAllocations
  1271. );
  1272. DumpOutputString();
  1273. }
  1274. sprintf( DumpLine, " by: BackTrace%05lu",
  1275. BackTraceInfo ? BackTraceInfo->Index : 99999
  1276. );
  1277. DumpOutputString();
  1278. if (HogList[ BackTraceNumber ].TagEntry != NULL) {
  1279. sprintf( DumpLine, " (%ws)\n", HogList[ BackTraceNumber ].TagEntry->TagName );
  1280. }
  1281. else {
  1282. sprintf( DumpLine, "\n" );
  1283. }
  1284. DumpOutputString();
  1285. if (BackTraceInfo != NULL && (s = BackTraceInfo->SymbolicBackTrace)) {
  1286. while (*s) {
  1287. sprintf( DumpLine, " %s\n", s );
  1288. DumpOutputString();
  1289. while (*s++) {
  1290. }
  1291. }
  1292. }
  1293. sprintf( DumpLine, " \n" );
  1294. DumpOutputString();
  1295. }
  1296. }
  1297. VirtualFree( HogList, 0, MEM_RELEASE );
  1298. }
  1299. ////////////////////////////////////////////////////////////////////////////////////////////
  1300. VOID
  1301. DumpHeapEntries(
  1302. PRTL_HEAP_INFORMATION HeapInfo
  1303. )
  1304. {
  1305. PRTL_PROCESS_BACKTRACE_INFORMATION BackTraceInfo;
  1306. PUCHAR s;
  1307. PRTL_HEAP_ENTRY p;
  1308. PRTL_HEAP_TAG TagEntry;
  1309. PCHAR HeapEntryAddress;
  1310. SIZE_T HeapEntrySize;
  1311. ULONG HeapEntryNumber;
  1312. p = HeapInfo->Entries;
  1313. if (p == NULL || HeapInfo->NumberOfEntries == 0) {
  1314. return;
  1315. }
  1316. FormatHeapHeader( HeapInfo, "Entries" );
  1317. HeapEntryAddress = NULL;
  1318. for (HeapEntryNumber=0; HeapEntryNumber<HeapInfo->NumberOfEntries; HeapEntryNumber++) {
  1319. if (p->Flags != 0xFF && p->Flags & RTL_HEAP_SEGMENT) {
  1320. HeapEntryAddress = (PCHAR)p->u.s2.FirstBlock;
  1321. sprintf( DumpLine, "\n[%p : %p]\n",
  1322. (ULONG_PTR)HeapEntryAddress & ~(4096-1),
  1323. p->u.s2.CommittedSize
  1324. );
  1325. DumpOutputString();
  1326. }
  1327. else {
  1328. HeapEntrySize = p->Size;
  1329. if (p->Flags == RTL_HEAP_UNCOMMITTED_RANGE) {
  1330. sprintf( DumpLine, "%p: %p - UNCOMMITTED\n",
  1331. HeapEntryAddress,
  1332. HeapEntrySize
  1333. );
  1334. DumpOutputString();
  1335. }
  1336. else
  1337. if (p->Flags & RTL_HEAP_BUSY) {
  1338. s = DumpLine;
  1339. s += sprintf( s, "%p: %p - BUSY [%02x]",
  1340. HeapEntryAddress,
  1341. HeapEntrySize,
  1342. p->Flags
  1343. );
  1344. TagEntry = FindTagEntry( HeapInfo, p->u.s1.Tag );
  1345. if (TagEntry != NULL) {
  1346. s += sprintf( s, "(%ws)", TagEntry->TagName );
  1347. }
  1348. if (BackTraces != NULL) {
  1349. s += sprintf( s, " (BackTrace%05lu)",
  1350. p->AllocatorBackTraceIndex
  1351. );
  1352. }
  1353. if (p->Flags & RTL_HEAP_SETTABLE_VALUE &&
  1354. p->Flags & RTL_HEAP_SETTABLE_FLAG1
  1355. ) {
  1356. s += sprintf( s, " (Handle: %x)", p->u.s1.Settable );
  1357. }
  1358. if (p->Flags & RTL_HEAP_SETTABLE_FLAG2) {
  1359. s += sprintf( s, " (DDESHARE)" );
  1360. }
  1361. if (p->Flags & RTL_HEAP_PROTECTED_ENTRY) {
  1362. s += sprintf( s, " (Protected)" );
  1363. }
  1364. sprintf( s, "\n" );
  1365. DumpOutputString();
  1366. }
  1367. else {
  1368. sprintf( DumpLine, "%p: %p - FREE\n",
  1369. HeapEntryAddress,
  1370. HeapEntrySize
  1371. );
  1372. DumpOutputString();
  1373. }
  1374. sprintf( DumpLine, "\n" );
  1375. DumpOutputString();
  1376. HeapEntryAddress += HeapEntrySize;
  1377. }
  1378. p++;
  1379. }
  1380. return;
  1381. }
  1382. ////////////////////////////////////////////////////////////////////////////////////////////
  1383. VOID
  1384. DumpHeaps(
  1385. PRTL_PROCESS_HEAPS Heaps,
  1386. BOOL fDumpSummary,
  1387. BOOL fDumpHogs,
  1388. BOOL fDumpTags,
  1389. BOOL fDumpEntries
  1390. )
  1391. {
  1392. ULONG HeapNumber;
  1393. PRTL_HEAP_INFORMATION HeapInfo;
  1394. if (fVerbose) {
  1395. fprintf( stderr, "DH: Dumping heap information.\n" );
  1396. }
  1397. HeapInfo = &Heaps->Heaps[ 0 ];
  1398. for (HeapNumber = 0; HeapNumber < Heaps->NumberOfHeaps; HeapNumber++) {
  1399. FormatHeapHeader( HeapInfo, "Information" );
  1400. if (fDumpSummary) {
  1401. DumpHeapSummary( HeapInfo );
  1402. }
  1403. if (fDumpTags) {
  1404. DumpHeapTags( HeapInfo );
  1405. }
  1406. if (fDumpHogs) {
  1407. DumpHeapHogs( HeapInfo );
  1408. }
  1409. if (fDumpEntries) {
  1410. DumpHeapEntries( HeapInfo );
  1411. }
  1412. HeapInfo += 1;
  1413. }
  1414. return;
  1415. }
  1416. ////////////////////////////////////////////////////////////////////////////////////////////
  1417. VOID
  1418. DumpLocks(
  1419. PRTL_PROCESS_LOCKS Locks
  1420. )
  1421. {
  1422. PRTL_PROCESS_LOCK_INFORMATION LockInfo;
  1423. PRTL_PROCESS_BACKTRACE_INFORMATION BackTraceInfo;
  1424. ULONG LockNumber;
  1425. PUCHAR s;
  1426. if (fVerbose) {
  1427. fprintf( stderr, "DH: Dumping lock information.\n" );
  1428. }
  1429. sprintf( DumpLine, "\n\n*********** Lock Information ********************\n\n" );
  1430. DumpOutputString();
  1431. if (Locks == NULL) {
  1432. return;
  1433. }
  1434. sprintf( DumpLine, "NumberOfLocks == %u\n", Locks->NumberOfLocks );
  1435. DumpOutputString();
  1436. LockInfo = &Locks->Locks[ 0 ];
  1437. LockNumber = 0;
  1438. while (LockNumber++ < Locks->NumberOfLocks) {
  1439. sprintf( DumpLine, "Lock%u at %p (%s)\n",
  1440. LockNumber,
  1441. LockInfo->Address,
  1442. LockInfo->Type == RTL_CRITSECT_TYPE ? "CriticalSection" : "Resource"
  1443. );
  1444. DumpOutputString();
  1445. sprintf( DumpLine, " Contention: %u\n", LockInfo->ContentionCount );
  1446. DumpOutputString();
  1447. sprintf( DumpLine, " Usage: %u\n", LockInfo->EntryCount );
  1448. DumpOutputString();
  1449. if (LockInfo->CreatorBackTraceIndex != 0) {
  1450. sprintf( DumpLine, " Creator: (Backtrace%05lu)\n", LockInfo->CreatorBackTraceIndex );
  1451. DumpOutputString();
  1452. BackTraceInfo = FindBackTrace( LockInfo->CreatorBackTraceIndex );
  1453. if (BackTraceInfo != NULL && (s = BackTraceInfo->SymbolicBackTrace)) {
  1454. while (*s) {
  1455. sprintf( DumpLine, " %s\n", s );
  1456. DumpOutputString();
  1457. while (*s++) {
  1458. }
  1459. }
  1460. }
  1461. }
  1462. if (LockInfo->OwningThread) {
  1463. sprintf( DumpLine, " Owner: (ThreadID == %p)\n", LockInfo->OwningThread );
  1464. DumpOutputString();
  1465. }
  1466. sprintf( DumpLine, "\n" );
  1467. DumpOutputString();
  1468. LockInfo++;
  1469. }
  1470. }
  1471. ////////////////////////////////////////////////////////////////////////////////////////////
  1472. #define RTL_NEW( p ) RtlAllocateHeap( RtlProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *p ) )
  1473. BOOLEAN
  1474. LoadSystemModules(
  1475. PRTL_DEBUG_INFORMATION Buffer
  1476. );
  1477. BOOLEAN
  1478. LoadSystemBackTraces(
  1479. PRTL_DEBUG_INFORMATION Buffer
  1480. );
  1481. BOOLEAN
  1482. LoadSystemPools(
  1483. PRTL_DEBUG_INFORMATION Buffer
  1484. );
  1485. BOOLEAN
  1486. LoadSystemTags(
  1487. PRTL_HEAP_INFORMATION PagedPoolInfo,
  1488. PRTL_HEAP_INFORMATION NonPagedPoolInfo
  1489. );
  1490. BOOLEAN
  1491. LoadSystemPool(
  1492. PRTL_HEAP_INFORMATION HeapInfo,
  1493. SYSTEM_INFORMATION_CLASS SystemInformationClass
  1494. );
  1495. BOOLEAN
  1496. LoadSystemLocks(
  1497. PRTL_DEBUG_INFORMATION Buffer
  1498. );
  1499. BOOLEAN
  1500. LoadSystemObjects(
  1501. PRTL_DEBUG_INFORMATION Buffer
  1502. );
  1503. BOOLEAN
  1504. LoadSystemHandles(
  1505. PRTL_DEBUG_INFORMATION Buffer
  1506. );
  1507. BOOLEAN
  1508. LoadSystemProcesses(
  1509. PRTL_DEBUG_INFORMATION Buffer
  1510. );
  1511. PSYSTEM_PROCESS_INFORMATION
  1512. FindProcessInfoForCid(
  1513. IN HANDLE UniqueProcessId
  1514. );
  1515. ////////////////////////////////////////////////////////////////////////////////////////////
  1516. PRTL_DEBUG_INFORMATION
  1517. RtlQuerySystemDebugInformation(
  1518. ULONG Flags
  1519. )
  1520. {
  1521. PRTL_DEBUG_INFORMATION Buffer;
  1522. Buffer = RTL_NEW( Buffer );
  1523. if (Buffer == NULL) {
  1524. fprintf(stderr,"DH: allocation failure for %d byte at line %d\n",sizeof(*Buffer),__LINE__);
  1525. return NULL;
  1526. }
  1527. if ((Flags & RTL_QUERY_PROCESS_MODULES) != 0 && !LoadSystemModules( Buffer )) {
  1528. fputs( "DH: Unable to query system module list.\n", stderr );
  1529. }
  1530. if ((Flags & RTL_QUERY_PROCESS_BACKTRACES) != 0 && !LoadSystemBackTraces( Buffer )) {
  1531. fputs( "DH: Unable to query system back trace information.\n"
  1532. " Be sure the system was booted with the\n"
  1533. " 'Create kernel mode stack trace DB' enabled\n"
  1534. " Use the GFLAGS.EXE application to do this.\n"
  1535. , stderr);
  1536. }
  1537. if ((Flags & (RTL_QUERY_PROCESS_HEAP_SUMMARY |
  1538. RTL_QUERY_PROCESS_HEAP_TAGS |
  1539. RTL_QUERY_PROCESS_HEAP_ENTRIES
  1540. )
  1541. ) != 0 &&
  1542. !LoadSystemPools( Buffer )
  1543. ) {
  1544. fputs( "DH: Unable to query system pool information.\n", stderr );
  1545. }
  1546. if ((Flags & RTL_QUERY_PROCESS_LOCKS) != 0 && !LoadSystemLocks( Buffer )) {
  1547. fputs( "DH: Unable to query system lock information.\n", stderr);
  1548. }
  1549. if (fDumpSystemObjects && !LoadSystemObjects( Buffer )) {
  1550. fputs( "DH: Unable to query system object information.\n", stderr );
  1551. }
  1552. if (fDumpSystemObjects && !LoadSystemHandles( Buffer )) {
  1553. fputs( "DH: Unable to query system handle information.\n", stderr );
  1554. }
  1555. if (!LoadSystemProcesses( Buffer )) {
  1556. fputs( "DH: Unable to query system process information.\n", stderr );
  1557. }
  1558. return Buffer;
  1559. }
  1560. ////////////////////////////////////////////////////////////////////////////////////////////
  1561. PVOID
  1562. BufferAlloc(
  1563. IN OUT SIZE_T *Length
  1564. )
  1565. {
  1566. PVOID Buffer;
  1567. MEMORY_BASIC_INFORMATION MemoryInformation;
  1568. Buffer = VirtualAlloc( NULL,
  1569. *Length,
  1570. MEM_COMMIT,
  1571. PAGE_READWRITE
  1572. );
  1573. if (Buffer != NULL &&
  1574. VirtualQuery( Buffer, &MemoryInformation, sizeof( MemoryInformation ) )
  1575. ) {
  1576. *Length = MemoryInformation.RegionSize;
  1577. }
  1578. if( Buffer == NULL ) {
  1579. fprintf(stderr,"DH: VirtualAlloc failed for %d bytes at line %d\n",*Length,__LINE__);
  1580. }
  1581. return Buffer;
  1582. }
  1583. ////////////////////////////////////////////////////////////////////////////////////////////
  1584. BOOLEAN
  1585. LoadSystemModules(
  1586. PRTL_DEBUG_INFORMATION Buffer
  1587. )
  1588. {
  1589. NTSTATUS Status;
  1590. PVOID BufferToFree;
  1591. RTL_PROCESS_MODULES ModulesBuffer;
  1592. PRTL_PROCESS_MODULES Modules;
  1593. SIZE_T RequiredLength;
  1594. Modules = &ModulesBuffer;
  1595. RequiredLength = sizeof( ModulesBuffer );
  1596. BufferToFree = NULL;
  1597. while (TRUE) {
  1598. Status = NtQuerySystemInformation( SystemModuleInformation,
  1599. Modules,
  1600. (ULONG)RequiredLength,
  1601. (ULONG *)&RequiredLength
  1602. );
  1603. if (Status == STATUS_INFO_LENGTH_MISMATCH) {
  1604. if (Modules != &ModulesBuffer) {
  1605. break;
  1606. }
  1607. Modules = BufferAlloc( &RequiredLength );
  1608. if (Modules == NULL) {
  1609. break;
  1610. }
  1611. BufferToFree = Modules;
  1612. }
  1613. else
  1614. if (NT_SUCCESS( Status )) {
  1615. Buffer->Modules = Modules;
  1616. return TRUE;
  1617. }
  1618. else {
  1619. fprintf(stderr,"DH: QuerySystemInformation failed ntstatus: %08x line: %d\n",
  1620. Status,__LINE__);
  1621. break;
  1622. }
  1623. }
  1624. if (Modules != &ModulesBuffer) {
  1625. VirtualFree( Modules, 0, MEM_RELEASE );
  1626. }
  1627. return FALSE;
  1628. }
  1629. ////////////////////////////////////////////////////////////////////////////////////////////
  1630. BOOLEAN
  1631. LoadSystemBackTraces(
  1632. PRTL_DEBUG_INFORMATION Buffer
  1633. )
  1634. {
  1635. NTSTATUS Status;
  1636. RTL_PROCESS_BACKTRACES BackTracesBuffer;
  1637. SIZE_T RequiredLength;
  1638. BackTraces = &BackTracesBuffer;
  1639. RequiredLength = sizeof( BackTracesBuffer );
  1640. while (TRUE) {
  1641. Status = NtQuerySystemInformation( SystemStackTraceInformation,
  1642. BackTraces,
  1643. (ULONG)RequiredLength,
  1644. (ULONG *)&RequiredLength
  1645. );
  1646. if (Status == STATUS_INFO_LENGTH_MISMATCH) {
  1647. if (BackTraces != &BackTracesBuffer) {
  1648. break;
  1649. }
  1650. RequiredLength += 4096; // slop, since we may trigger more allocs.
  1651. BackTraces = BufferAlloc( &RequiredLength );
  1652. if (BackTraces == NULL) {
  1653. return FALSE;
  1654. }
  1655. }
  1656. else
  1657. if (!NT_SUCCESS( Status )) {
  1658. fprintf(stderr,"DH: QuerySystemInformation failed ntstatus: %08x line: %d\n",Status,__LINE__);
  1659. break;
  1660. }
  1661. else {
  1662. Buffer->BackTraces = BackTraces;
  1663. return TRUE;
  1664. }
  1665. }
  1666. if (BackTraces != &BackTracesBuffer) {
  1667. VirtualFree( BackTraces, 0, MEM_RELEASE );
  1668. }
  1669. return FALSE;
  1670. }
  1671. ////////////////////////////////////////////////////////////////////////////////////////////
  1672. BOOLEAN
  1673. LoadSystemPools(
  1674. PRTL_DEBUG_INFORMATION Buffer
  1675. )
  1676. {
  1677. PRTL_PROCESS_HEAPS Heaps;
  1678. SIZE_T Size;
  1679. Size= FIELD_OFFSET( RTL_PROCESS_HEAPS, Heaps) + 2 * sizeof( RTL_HEAP_INFORMATION );
  1680. Heaps = RtlAllocateHeap( RtlProcessHeap(),
  1681. HEAP_ZERO_MEMORY,
  1682. Size );
  1683. if (Heaps == NULL) {
  1684. fprintf(stderr,"DH: AllocateHeap failed for %d bytes at line %d\n",Size,__LINE__);
  1685. return FALSE;
  1686. }
  1687. Buffer->Heaps = Heaps;
  1688. if (LoadSystemTags( &Heaps->Heaps[ 0 ], &Heaps->Heaps[ 1 ] )) {
  1689. if (LoadSystemPool( &Heaps->Heaps[ 0 ], SystemPagedPoolInformation )) {
  1690. Heaps->NumberOfHeaps = 1;
  1691. if (LoadSystemPool( &Heaps->Heaps[ 1 ], SystemNonPagedPoolInformation )) {
  1692. Heaps->NumberOfHeaps = 2;
  1693. return TRUE;
  1694. }
  1695. }
  1696. }
  1697. return FALSE;
  1698. }
  1699. ////////////////////////////////////////////////////////////////////////////////////////////
  1700. NTSTATUS
  1701. QueryPoolTagInformationIterative(
  1702. PVOID *CurrentBuffer,
  1703. SIZE_T *CurrentBufferSize
  1704. )
  1705. {
  1706. SIZE_T NewBufferSize;
  1707. NTSTATUS ReturnedStatus = STATUS_SUCCESS;
  1708. if( CurrentBuffer == NULL || CurrentBufferSize == NULL ) {
  1709. return STATUS_INVALID_PARAMETER;
  1710. }
  1711. if( *CurrentBufferSize == 0 || *CurrentBuffer == NULL ) {
  1712. //
  1713. // there is no buffer allocated yet
  1714. //
  1715. NewBufferSize = sizeof( UCHAR ) * BUFFER_SIZE_STEP;
  1716. *CurrentBuffer = VirtualAlloc(
  1717. NULL,
  1718. NewBufferSize,
  1719. MEM_COMMIT,
  1720. PAGE_READWRITE
  1721. );
  1722. if( *CurrentBuffer != NULL ) {
  1723. *CurrentBufferSize = NewBufferSize;
  1724. } else {
  1725. //
  1726. // insufficient memory
  1727. //
  1728. ReturnedStatus = STATUS_INSUFFICIENT_RESOURCES;
  1729. }
  1730. }
  1731. //
  1732. // iterate by buffer's size
  1733. //
  1734. while( *CurrentBuffer != NULL ) {
  1735. ReturnedStatus = NtQuerySystemInformation (
  1736. SystemPoolTagInformation,
  1737. *CurrentBuffer,
  1738. (ULONG)*CurrentBufferSize,
  1739. NULL );
  1740. if( ! NT_SUCCESS(ReturnedStatus) ) {
  1741. //
  1742. // free the current buffer
  1743. //
  1744. VirtualFree(
  1745. *CurrentBuffer,
  1746. 0,
  1747. MEM_RELEASE );
  1748. *CurrentBuffer = NULL;
  1749. if (ReturnedStatus == STATUS_INFO_LENGTH_MISMATCH) {
  1750. //
  1751. // try with a greater buffer size
  1752. //
  1753. NewBufferSize = *CurrentBufferSize + BUFFER_SIZE_STEP;
  1754. *CurrentBuffer = VirtualAlloc(
  1755. NULL,
  1756. NewBufferSize,
  1757. MEM_COMMIT,
  1758. PAGE_READWRITE
  1759. );
  1760. if( *CurrentBuffer != NULL ) {
  1761. //
  1762. // allocated new buffer
  1763. //
  1764. *CurrentBufferSize = NewBufferSize;
  1765. } else {
  1766. //
  1767. // insufficient memory
  1768. //
  1769. ReturnedStatus = STATUS_INSUFFICIENT_RESOURCES;
  1770. *CurrentBufferSize = 0;
  1771. }
  1772. } else {
  1773. *CurrentBufferSize = 0;
  1774. }
  1775. } else {
  1776. //
  1777. // NtQuerySystemInformation returned success
  1778. //
  1779. break;
  1780. }
  1781. }
  1782. return ReturnedStatus;
  1783. }
  1784. ////////////////////////////////////////////////////////////////////////////////////////////
  1785. BOOLEAN
  1786. LoadSystemTags(
  1787. PRTL_HEAP_INFORMATION PagedPoolInfo,
  1788. PRTL_HEAP_INFORMATION NonPagedPoolInfo
  1789. )
  1790. {
  1791. NTSTATUS Status;
  1792. SIZE_T RequiredLength;
  1793. PSYSTEM_POOLTAG_INFORMATION Tags;
  1794. PSYSTEM_POOLTAG TagInfo;
  1795. PRTL_HEAP_TAG pPagedPoolTag, pNonPagedPoolTag;
  1796. ULONG n, TagIndex;
  1797. PagedPoolInfo->NumberOfTags = 0;
  1798. PagedPoolInfo->Tags = NULL;
  1799. NonPagedPoolInfo->NumberOfTags = 0;
  1800. NonPagedPoolInfo->Tags = NULL;
  1801. Tags = NULL;
  1802. RequiredLength = 0;
  1803. while (TRUE) {
  1804. Status = QueryPoolTagInformationIterative(
  1805. &Tags,
  1806. &RequiredLength
  1807. );
  1808. if (!NT_SUCCESS( Status )) {
  1809. fprintf(stderr,"DH: QuerySystemInformation failed ntstatus: %08x line: %d\n",Status,__LINE__);
  1810. break;
  1811. }
  1812. else {
  1813. PagedPoolInfo->NumberOfTags = Tags->Count + 1;
  1814. NonPagedPoolInfo->NumberOfTags = Tags->Count + 1;
  1815. n = (Tags->Count + 1) * sizeof( RTL_HEAP_TAG );
  1816. PagedPoolInfo->Tags = RtlAllocateHeap( RtlProcessHeap(), HEAP_ZERO_MEMORY, n );
  1817. NonPagedPoolInfo->Tags = RtlAllocateHeap( RtlProcessHeap(), HEAP_ZERO_MEMORY, n );
  1818. TagInfo = &Tags->TagInfo[ 0 ];
  1819. pPagedPoolTag = PagedPoolInfo->Tags + 1;
  1820. pNonPagedPoolTag = NonPagedPoolInfo->Tags + 1;
  1821. for (TagIndex=1; TagIndex<=Tags->Count; TagIndex++) {
  1822. UNICODE_STRING UnicodeString;
  1823. ANSI_STRING AnsiString;
  1824. pPagedPoolTag->TagIndex = (USHORT)TagIndex;
  1825. pPagedPoolTag->NumberOfAllocations = TagInfo->PagedAllocs;
  1826. pPagedPoolTag->NumberOfFrees = TagInfo->PagedFrees;
  1827. pPagedPoolTag->BytesAllocated = TagInfo->PagedUsed;
  1828. UnicodeString.Buffer = pPagedPoolTag->TagName;
  1829. UnicodeString.MaximumLength = sizeof( pPagedPoolTag->TagName );
  1830. AnsiString.Buffer = TagInfo->Tag;
  1831. AnsiString.Length = sizeof( TagInfo->Tag );
  1832. AnsiString.MaximumLength = AnsiString.Length;
  1833. RtlAnsiStringToUnicodeString( &UnicodeString, &AnsiString, FALSE );
  1834. pNonPagedPoolTag->TagIndex = (USHORT)TagIndex;
  1835. pNonPagedPoolTag->NumberOfAllocations = TagInfo->NonPagedAllocs;
  1836. pNonPagedPoolTag->NumberOfFrees = TagInfo->NonPagedFrees;
  1837. pNonPagedPoolTag->BytesAllocated = TagInfo->NonPagedUsed;
  1838. wcscpy( pNonPagedPoolTag->TagName, pPagedPoolTag->TagName );
  1839. pPagedPoolTag += 1;
  1840. pNonPagedPoolTag += 1;
  1841. TagInfo += 1;
  1842. }
  1843. break;
  1844. }
  1845. }
  1846. if (Tags != NULL) {
  1847. VirtualFree( Tags, 0, MEM_RELEASE );
  1848. }
  1849. return TRUE;
  1850. }
  1851. ////////////////////////////////////////////////////////////////////////////////////////////
  1852. USHORT
  1853. FindPoolTagIndex(
  1854. PRTL_HEAP_TAG Tags,
  1855. ULONG NumberOfTags,
  1856. PCHAR Tag
  1857. )
  1858. {
  1859. ULONG i;
  1860. UCHAR AnsiTagName[ 5 ];
  1861. WCHAR UnicodeTagName[ 5 ];
  1862. UNICODE_STRING UnicodeString;
  1863. ANSI_STRING AnsiString;
  1864. strncpy( AnsiTagName, Tag, 4 );
  1865. UnicodeString.Buffer = UnicodeTagName;
  1866. UnicodeString.MaximumLength = sizeof( UnicodeTagName );
  1867. AnsiString.Buffer = AnsiTagName;
  1868. AnsiString.Length = (USHORT)strlen( AnsiTagName );
  1869. AnsiString.MaximumLength = AnsiString.Length;
  1870. RtlAnsiStringToUnicodeString( &UnicodeString, &AnsiString, FALSE );
  1871. Tags += 1;
  1872. for (i=1; i<NumberOfTags; i++) {
  1873. if (!_wcsicmp( UnicodeTagName, Tags->TagName )) {
  1874. return (USHORT)i;
  1875. }
  1876. Tags += 1;
  1877. }
  1878. return 0;
  1879. }
  1880. ////////////////////////////////////////////////////////////////////////////////////////////
  1881. BOOLEAN
  1882. LoadSystemPool(
  1883. PRTL_HEAP_INFORMATION HeapInfo,
  1884. SYSTEM_INFORMATION_CLASS SystemInformationClass
  1885. )
  1886. {
  1887. NTSTATUS Status;
  1888. SIZE_T RequiredLength;
  1889. SYSTEM_POOL_INFORMATION PoolInfoBuffer;
  1890. PSYSTEM_POOL_INFORMATION PoolInfo;
  1891. PSYSTEM_POOL_ENTRY PoolEntry;
  1892. PRTL_HEAP_ENTRY p;
  1893. ULONG n;
  1894. BOOLEAN Result;
  1895. HeapInfo->BaseAddress = (PVOID)SystemInformationClass;
  1896. PoolInfo = &PoolInfoBuffer;
  1897. RequiredLength = sizeof( PoolInfoBuffer );
  1898. Result = FALSE;
  1899. while (TRUE) {
  1900. Status = NtQuerySystemInformation( SystemInformationClass,
  1901. PoolInfo,
  1902. (ULONG)RequiredLength,
  1903. (ULONG *)&RequiredLength
  1904. );
  1905. if (Status == STATUS_INFO_LENGTH_MISMATCH) {
  1906. if (PoolInfo != &PoolInfoBuffer) {
  1907. break;
  1908. }
  1909. RequiredLength += 4096; // slop, since we may trigger more allocs.
  1910. PoolInfo = BufferAlloc( &RequiredLength );
  1911. if (PoolInfo == NULL) {
  1912. return FALSE;
  1913. }
  1914. }
  1915. else
  1916. if (!NT_SUCCESS( Status )) {
  1917. fprintf(stderr,"DH: QuerySystemInformation failed ntstatus: %08x line: %d\n",Status,__LINE__);
  1918. break;
  1919. }
  1920. else {
  1921. n = PoolInfo->NumberOfEntries;
  1922. HeapInfo->NumberOfEntries = n + 1;
  1923. HeapInfo->EntryOverhead = PoolInfo->EntryOverhead;
  1924. HeapInfo->Entries = RtlAllocateHeap( RtlProcessHeap(),
  1925. HEAP_ZERO_MEMORY,
  1926. HeapInfo->NumberOfEntries * sizeof( RTL_HEAP_ENTRY )
  1927. );
  1928. if( HeapInfo->Entries == NULL ) {
  1929. fprintf(stderr,"DH: Alloc failed for %d bytes at line %d\n",
  1930. HeapInfo->NumberOfEntries * sizeof( RTL_HEAP_ENTRY),__LINE__);
  1931. break;
  1932. }
  1933. p = HeapInfo->Entries;
  1934. p->Flags = RTL_HEAP_SEGMENT;
  1935. p->u.s2.CommittedSize = PoolInfo->TotalSize;
  1936. p->u.s2.FirstBlock = PoolInfo->FirstEntry;
  1937. p += 1;
  1938. PoolEntry = &PoolInfo->Entries[ 0 ];
  1939. while (n--) {
  1940. p->Size = PoolEntry->Size;
  1941. if (PoolEntry->TagUlong & PROTECTED_POOL) {
  1942. p->Flags |= RTL_HEAP_PROTECTED_ENTRY;
  1943. PoolEntry->TagUlong &= ~PROTECTED_POOL;
  1944. }
  1945. p->u.s1.Tag = FindPoolTagIndex( HeapInfo->Tags,
  1946. HeapInfo->NumberOfTags,
  1947. PoolEntry->Tag
  1948. );
  1949. HeapInfo->BytesCommitted += p->Size;
  1950. if (PoolEntry->Allocated) {
  1951. p->Flags |= RTL_HEAP_BUSY;
  1952. p->AllocatorBackTraceIndex = PoolEntry->AllocatorBackTraceIndex;
  1953. HeapInfo->BytesAllocated += p->Size;
  1954. }
  1955. p += 1;
  1956. PoolEntry += 1;
  1957. }
  1958. Result = TRUE;
  1959. break;
  1960. }
  1961. }
  1962. if (PoolInfo != &PoolInfoBuffer) {
  1963. VirtualFree( PoolInfo, 0, MEM_RELEASE );
  1964. }
  1965. return Result;
  1966. }
  1967. ////////////////////////////////////////////////////////////////////////////////////////////
  1968. BOOLEAN
  1969. LoadSystemLocks(
  1970. PRTL_DEBUG_INFORMATION Buffer
  1971. )
  1972. {
  1973. NTSTATUS Status;
  1974. RTL_PROCESS_LOCKS LocksBuffer;
  1975. PRTL_PROCESS_LOCKS Locks;
  1976. SIZE_T RequiredLength;
  1977. Locks = &LocksBuffer;
  1978. RequiredLength = sizeof( LocksBuffer );
  1979. while (TRUE) {
  1980. Status = NtQuerySystemInformation( SystemLocksInformation,
  1981. Locks,
  1982. (ULONG)RequiredLength,
  1983. (ULONG *)&RequiredLength
  1984. );
  1985. if (Status == STATUS_INFO_LENGTH_MISMATCH) {
  1986. if (Locks != &LocksBuffer) {
  1987. break;
  1988. }
  1989. Locks = BufferAlloc( &RequiredLength );
  1990. if (Locks == NULL) {
  1991. return FALSE;
  1992. }
  1993. }
  1994. else
  1995. if (!NT_SUCCESS( Status )) {
  1996. fprintf(stderr,"DH: QuerySystemInformation failed ntstatus: %08x line: %d\n",Status,__LINE__);
  1997. break;
  1998. }
  1999. else {
  2000. Buffer->Locks = Locks;
  2001. return TRUE;
  2002. }
  2003. }
  2004. if (Locks != &LocksBuffer) {
  2005. VirtualFree( Locks, 0, MEM_RELEASE );
  2006. }
  2007. return FALSE;
  2008. }
  2009. ////////////////////////////////////////////////////////////////////////////////////////////
  2010. BOOLEAN
  2011. LoadSystemObjects(
  2012. PRTL_DEBUG_INFORMATION Buffer
  2013. )
  2014. {
  2015. NTSTATUS Status;
  2016. SYSTEM_OBJECTTYPE_INFORMATION ObjectInfoBuffer;
  2017. SIZE_T RequiredLength;
  2018. ULONG i;
  2019. PSYSTEM_OBJECTTYPE_INFORMATION TypeInfo;
  2020. ObjectInformation = &ObjectInfoBuffer;
  2021. RequiredLength = sizeof( *ObjectInformation );
  2022. while (TRUE) {
  2023. Status = NtQuerySystemInformation( SystemObjectInformation,
  2024. ObjectInformation,
  2025. (ULONG)RequiredLength,
  2026. (ULONG *)&RequiredLength
  2027. );
  2028. if (Status == STATUS_INFO_LENGTH_MISMATCH) {
  2029. if (ObjectInformation != &ObjectInfoBuffer) {
  2030. return FALSE;
  2031. }
  2032. RequiredLength += 4096; // slop, since we may trigger more object creations.
  2033. ObjectInformation = BufferAlloc( &RequiredLength );
  2034. if (ObjectInformation == NULL) {
  2035. return FALSE;
  2036. }
  2037. }
  2038. else
  2039. if (!NT_SUCCESS( Status )) {
  2040. fprintf(stderr,"DH: QuerySystemInformation failed ntstatus: %08x line: %d\n",Status,__LINE__);
  2041. return FALSE;
  2042. }
  2043. else {
  2044. break;
  2045. }
  2046. }
  2047. TypeNames = RtlAllocateHeap( RtlProcessHeap(),
  2048. HEAP_ZERO_MEMORY,
  2049. sizeof( PUNICODE_STRING ) * (MAX_TYPE_NAMES+1)
  2050. );
  2051. if (TypeNames == NULL) {
  2052. fprintf(stderr,"DH: Alloc failed for %d bytes at line %d\n",
  2053. sizeof( PUNICODE_STRING ) * (MAX_TYPE_NAMES+1) ,__LINE__);
  2054. return FALSE;
  2055. }
  2056. TypeInfo = ObjectInformation;
  2057. while (TRUE) {
  2058. if (TypeInfo->TypeIndex < MAX_TYPE_NAMES) {
  2059. TypeNames[ TypeInfo->TypeIndex ] = &TypeInfo->TypeName;
  2060. }
  2061. if (TypeInfo->NextEntryOffset == 0) {
  2062. break;
  2063. }
  2064. TypeInfo = (PSYSTEM_OBJECTTYPE_INFORMATION)
  2065. ((PCHAR)ObjectInformation + TypeInfo->NextEntryOffset);
  2066. }
  2067. RtlInitUnicodeString( &UnknownTypeIndex, L"Unknown Type Index" );
  2068. for (i=0; i<=MAX_TYPE_NAMES; i++) {
  2069. if (TypeNames[ i ] == NULL) {
  2070. TypeNames[ i ] = &UnknownTypeIndex;
  2071. }
  2072. }
  2073. return TRUE;
  2074. }
  2075. ////////////////////////////////////////////////////////////////////////////////////////////
  2076. BOOLEAN
  2077. LoadSystemHandles(
  2078. PRTL_DEBUG_INFORMATION Buffer
  2079. )
  2080. {
  2081. NTSTATUS Status;
  2082. SYSTEM_HANDLE_INFORMATION_EX HandleInfoBuffer;
  2083. SIZE_T RequiredLength;
  2084. PSYSTEM_OBJECTTYPE_INFORMATION TypeInfo;
  2085. PSYSTEM_OBJECT_INFORMATION ObjectInfo;
  2086. HandleInformation = &HandleInfoBuffer;
  2087. RequiredLength = sizeof( *HandleInformation );
  2088. while (TRUE) {
  2089. Status = NtQuerySystemInformation( SystemExtendedHandleInformation,
  2090. HandleInformation,
  2091. (ULONG)RequiredLength,
  2092. (ULONG *)&RequiredLength
  2093. );
  2094. if (Status == STATUS_INFO_LENGTH_MISMATCH) {
  2095. if (HandleInformation != &HandleInfoBuffer) {
  2096. return FALSE;
  2097. }
  2098. RequiredLength += 4096; // slop, since we may trigger more handle creations.
  2099. HandleInformation = (PSYSTEM_HANDLE_INFORMATION_EX)BufferAlloc( &RequiredLength );
  2100. if (HandleInformation == NULL) {
  2101. return FALSE;
  2102. }
  2103. }
  2104. else
  2105. if (!NT_SUCCESS( Status )) {
  2106. fprintf(stderr,"DH: QuerySystemInformation failed ntstatus: %08x line: %d\n",Status,__LINE__);
  2107. return FALSE;
  2108. }
  2109. else {
  2110. break;
  2111. }
  2112. }
  2113. TypeInfo = ObjectInformation;
  2114. while (TRUE) {
  2115. ObjectInfo = (PSYSTEM_OBJECT_INFORMATION)
  2116. ((PCHAR)TypeInfo->TypeName.Buffer + TypeInfo->TypeName.MaximumLength);
  2117. while (TRUE) {
  2118. if (ObjectInfo->HandleCount != 0) {
  2119. PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX HandleEntry;
  2120. ULONG HandleNumber;
  2121. HandleEntry = &HandleInformation->Handles[ 0 ];
  2122. HandleNumber = 0;
  2123. while (HandleNumber++ < HandleInformation->NumberOfHandles) {
  2124. if (!(HandleEntry->HandleAttributes & 0x80) &&
  2125. HandleEntry->Object == ObjectInfo->Object
  2126. ) {
  2127. HandleEntry->Object = ObjectInfo;
  2128. HandleEntry->HandleAttributes |= 0x80;
  2129. }
  2130. HandleEntry++;
  2131. }
  2132. }
  2133. if (ObjectInfo->NextEntryOffset == 0) {
  2134. break;
  2135. }
  2136. ObjectInfo = (PSYSTEM_OBJECT_INFORMATION)
  2137. ((PCHAR)ObjectInformation + ObjectInfo->NextEntryOffset);
  2138. }
  2139. if (TypeInfo->NextEntryOffset == 0) {
  2140. break;
  2141. }
  2142. TypeInfo = (PSYSTEM_OBJECTTYPE_INFORMATION)
  2143. ((PCHAR)ObjectInformation + TypeInfo->NextEntryOffset);
  2144. }
  2145. return TRUE;
  2146. }
  2147. ////////////////////////////////////////////////////////////////////////////////////////////
  2148. BOOLEAN
  2149. LoadSystemProcesses(
  2150. PRTL_DEBUG_INFORMATION Buffer
  2151. )
  2152. {
  2153. NTSTATUS Status;
  2154. SIZE_T RequiredLength;
  2155. ULONG i, TotalOffset;
  2156. PSYSTEM_PROCESS_INFORMATION ProcessInfo;
  2157. PSYSTEM_THREAD_INFORMATION ThreadInfo;
  2158. PPROCESS_INFO ProcessEntry;
  2159. UCHAR NameBuffer[ MAX_PATH ];
  2160. ANSI_STRING AnsiString;
  2161. SIZE_T Size;
  2162. RequiredLength = 64 * 1024;
  2163. ProcessInformation = BufferAlloc( &RequiredLength );
  2164. if (ProcessInformation == NULL) {
  2165. return FALSE;
  2166. }
  2167. Status = NtQuerySystemInformation( SystemProcessInformation,
  2168. ProcessInformation,
  2169. (ULONG)RequiredLength,
  2170. (ULONG *)&RequiredLength
  2171. );
  2172. if (!NT_SUCCESS( Status )) {
  2173. fprintf(stderr,"DH: QuerySystemInformation failed ntstatus: %08x line: %d\n",Status,__LINE__);
  2174. return FALSE;
  2175. }
  2176. InitializeListHead( &ProcessListHead );
  2177. ProcessInfo = ProcessInformation;
  2178. TotalOffset = 0;
  2179. while (TRUE) {
  2180. if (ProcessInfo->ImageName.Buffer == NULL) {
  2181. sprintf( NameBuffer, "System Process (%p)", ProcessInfo->UniqueProcessId );
  2182. }
  2183. else {
  2184. sprintf( NameBuffer, "%wZ (%p)",
  2185. &ProcessInfo->ImageName,
  2186. ProcessInfo->UniqueProcessId
  2187. );
  2188. }
  2189. RtlInitAnsiString( &AnsiString, NameBuffer );
  2190. RtlAnsiStringToUnicodeString( &ProcessInfo->ImageName, &AnsiString, TRUE );
  2191. Size = sizeof( *ProcessEntry ) + (sizeof( ThreadInfo ) * ProcessInfo->NumberOfThreads);
  2192. ProcessEntry = RtlAllocateHeap( RtlProcessHeap(),
  2193. HEAP_ZERO_MEMORY,
  2194. Size );
  2195. if (ProcessEntry == NULL) {
  2196. fprintf(stderr,"DH: Alloc failed for %d bytes at line %d\n",Size,__LINE__);
  2197. return FALSE;
  2198. }
  2199. InitializeListHead( &ProcessEntry->Entry );
  2200. ProcessEntry->ProcessInfo = ProcessInfo;
  2201. ThreadInfo = (PSYSTEM_THREAD_INFORMATION)(ProcessInfo + 1);
  2202. for (i = 0; i < ProcessInfo->NumberOfThreads; i++) {
  2203. ProcessEntry->ThreadInfo[ i ] = ThreadInfo++;
  2204. }
  2205. InsertTailList( &ProcessListHead, &ProcessEntry->Entry );
  2206. if (ProcessInfo->NextEntryOffset == 0) {
  2207. break;
  2208. }
  2209. TotalOffset += ProcessInfo->NextEntryOffset;
  2210. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)
  2211. ((PCHAR)ProcessInformation + TotalOffset);
  2212. }
  2213. return TRUE;
  2214. }
  2215. ////////////////////////////////////////////////////////////////////////////////////////////
  2216. PSYSTEM_PROCESS_INFORMATION
  2217. FindProcessInfoForCid(
  2218. IN HANDLE UniqueProcessId
  2219. )
  2220. {
  2221. PLIST_ENTRY Next, Head;
  2222. PSYSTEM_PROCESS_INFORMATION ProcessInfo;
  2223. PPROCESS_INFO ProcessEntry;
  2224. UCHAR NameBuffer[ 64 ];
  2225. ANSI_STRING AnsiString;
  2226. Head = &ProcessListHead;
  2227. Next = Head->Flink;
  2228. while (Next != Head) {
  2229. ProcessEntry = CONTAINING_RECORD( Next,
  2230. PROCESS_INFO,
  2231. Entry
  2232. );
  2233. ProcessInfo = ProcessEntry->ProcessInfo;
  2234. if (ProcessInfo->UniqueProcessId == UniqueProcessId) {
  2235. return ProcessInfo;
  2236. }
  2237. Next = Next->Flink;
  2238. }
  2239. ProcessEntry = RtlAllocateHeap( RtlProcessHeap(),
  2240. HEAP_ZERO_MEMORY,
  2241. sizeof( *ProcessEntry ) +
  2242. sizeof( *ProcessInfo )
  2243. );
  2244. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)(ProcessEntry+1);
  2245. ProcessEntry->ProcessInfo = ProcessInfo;
  2246. sprintf( NameBuffer, "Unknown Process (%p)", UniqueProcessId );
  2247. RtlInitAnsiString( &AnsiString, NameBuffer );
  2248. RtlAnsiStringToUnicodeString( (PUNICODE_STRING)&ProcessInfo->ImageName, &AnsiString, TRUE );
  2249. ProcessInfo->UniqueProcessId = UniqueProcessId;
  2250. InitializeListHead( &ProcessEntry->Entry );
  2251. InsertTailList( &ProcessListHead, &ProcessEntry->Entry );
  2252. return ProcessInfo;
  2253. }
  2254. ////////////////////////////////////////////////////////////////////////////////////////////
  2255. VOID
  2256. DumpSystemThread(
  2257. PSYSTEM_THREAD_INFORMATION ThreadInfo
  2258. )
  2259. {
  2260. UCHAR Buffer[ MAX_PATH ];
  2261. Buffer[ 0 ] = '\0';
  2262. GetDhSymbolicNameForAddress( NULL, (ULONG_PTR)ThreadInfo->StartAddress, Buffer, sizeof( Buffer ) );
  2263. sprintf( DumpLine, " Thread Id: %p Start Address: %p (%s)\n",
  2264. ThreadInfo->ClientId.UniqueThread,
  2265. ThreadInfo->StartAddress,
  2266. Buffer
  2267. );
  2268. DumpOutputString();
  2269. return;
  2270. }
  2271. ////////////////////////////////////////////////////////////////////////////////////////////
  2272. VOID
  2273. DumpSystemProcess(
  2274. PPROCESS_INFO ProcessEntry
  2275. )
  2276. {
  2277. PSYSTEM_PROCESS_INFORMATION ProcessInfo;
  2278. ULONG ThreadNumber;
  2279. ProcessInfo = ProcessEntry->ProcessInfo;
  2280. sprintf( DumpLine, "\n\n*********** %p (%wZ) Information ********************\n\n",
  2281. ProcessInfo->UniqueProcessId,
  2282. &ProcessInfo->ImageName
  2283. );
  2284. DumpOutputString();
  2285. if (ProcessInfo->InheritedFromUniqueProcessId) {
  2286. sprintf( DumpLine, " Parent Process: %p (%wZ)\n",
  2287. ProcessInfo->InheritedFromUniqueProcessId,
  2288. &(FindProcessInfoForCid( ProcessInfo->InheritedFromUniqueProcessId )->ImageName)
  2289. );
  2290. DumpOutputString();
  2291. }
  2292. sprintf( DumpLine, " BasePriority: %u\n",
  2293. ProcessInfo->BasePriority
  2294. );
  2295. DumpOutputString();
  2296. sprintf( DumpLine, " VirtualSize: %08x\n",
  2297. ProcessInfo->VirtualSize
  2298. );
  2299. DumpOutputString();
  2300. sprintf( DumpLine, " PeakVirtualSize: %08x\n",
  2301. ProcessInfo->PeakVirtualSize
  2302. );
  2303. DumpOutputString();
  2304. sprintf( DumpLine, " WorkingSetSize: %08x\n",
  2305. ProcessInfo->WorkingSetSize
  2306. );
  2307. DumpOutputString();
  2308. sprintf( DumpLine, " PeakWorkingSetSize: %08x\n",
  2309. ProcessInfo->PeakWorkingSetSize
  2310. );
  2311. DumpOutputString();
  2312. sprintf( DumpLine, " PagefileUsage: %08x\n",
  2313. ProcessInfo->PagefileUsage
  2314. );
  2315. DumpOutputString();
  2316. sprintf( DumpLine, " PeakPagefileUsage: %08x\n",
  2317. ProcessInfo->PeakPagefileUsage
  2318. );
  2319. DumpOutputString();
  2320. sprintf( DumpLine, " PageFaultCount: %08x\n",
  2321. ProcessInfo->PageFaultCount
  2322. );
  2323. DumpOutputString();
  2324. sprintf( DumpLine, " PrivatePageCount: %08x\n",
  2325. ProcessInfo->PrivatePageCount
  2326. );
  2327. DumpOutputString();
  2328. sprintf( DumpLine, " Number of Threads: %u\n",
  2329. ProcessInfo->NumberOfThreads
  2330. );
  2331. DumpOutputString();
  2332. for (ThreadNumber=0; ThreadNumber<ProcessInfo->NumberOfThreads; ThreadNumber++) {
  2333. DumpSystemThread( ProcessEntry->ThreadInfo[ ThreadNumber ] );
  2334. }
  2335. return;
  2336. }
  2337. ////////////////////////////////////////////////////////////////////////////////////////////
  2338. VOID
  2339. DumpSystemProcesses( VOID )
  2340. {
  2341. PLIST_ENTRY Next, Head;
  2342. PPROCESS_INFO ProcessEntry;
  2343. if (fVerbose) {
  2344. fprintf( stderr, "DH: Dumping object information.\n" );
  2345. }
  2346. sprintf( DumpLine, "\n\n*********** Process Information ********************\n\n" );
  2347. DumpOutputString();
  2348. Head = &ProcessListHead;
  2349. Next = Head->Flink;
  2350. while (Next != Head) {
  2351. ProcessEntry = CONTAINING_RECORD( Next,
  2352. PROCESS_INFO,
  2353. Entry
  2354. );
  2355. DumpSystemProcess( ProcessEntry );
  2356. Next = Next->Flink;
  2357. }
  2358. return;
  2359. }
  2360. ////////////////////////////////////////////////////////////////////////////////////////////
  2361. VOID
  2362. DumpObjects( VOID )
  2363. {
  2364. PSYSTEM_OBJECTTYPE_INFORMATION TypeInfo;
  2365. PSYSTEM_OBJECT_INFORMATION ObjectInfo;
  2366. PRTL_PROCESS_BACKTRACE_INFORMATION BackTraceInfo;
  2367. UNICODE_STRING ObjectName;
  2368. PUCHAR s;
  2369. if (fVerbose) {
  2370. fprintf( stderr, "DH: Dumping object information.\n" );
  2371. }
  2372. sprintf( DumpLine, "\n\n*********** Object Information ********************\n\n" );
  2373. DumpOutputString();
  2374. TypeInfo = ObjectInformation;
  2375. while (TRUE) {
  2376. sprintf( DumpLine, "\n\n*********** %wZ Object Type ********************\n\n",
  2377. &TypeInfo->TypeName
  2378. );
  2379. DumpOutputString();
  2380. sprintf( DumpLine, " NumberOfObjects: %u\n", TypeInfo->NumberOfObjects );
  2381. DumpOutputString();
  2382. ObjectInfo = (PSYSTEM_OBJECT_INFORMATION)
  2383. ((PCHAR)TypeInfo->TypeName.Buffer + TypeInfo->TypeName.MaximumLength);
  2384. while (TRUE) {
  2385. ObjectName = ObjectInfo->NameInfo.Name;
  2386. try {
  2387. if (ObjectName.Length != 0 && *ObjectName.Buffer == UNICODE_NULL) {
  2388. ObjectName.Length = 0;
  2389. }
  2390. sprintf( DumpLine, " Object: %p Name: %wZ Creator: %wZ (Backtrace%05lu)\n",
  2391. ObjectInfo->Object,
  2392. &ObjectName,
  2393. &(FindProcessInfoForCid( ObjectInfo->CreatorUniqueProcess )->ImageName),
  2394. ObjectInfo->CreatorBackTraceIndex
  2395. );
  2396. }
  2397. except( EXCEPTION_EXECUTE_HANDLER ) {
  2398. sprintf( DumpLine, " Object: %p Name: [%04x, %04x, %p]\n",
  2399. ObjectInfo->Object,
  2400. ObjectName.MaximumLength,
  2401. ObjectName.Length,
  2402. ObjectName.Buffer
  2403. );
  2404. }
  2405. DumpOutputString();
  2406. BackTraceInfo = FindBackTrace( ObjectInfo->CreatorBackTraceIndex );
  2407. if (BackTraceInfo != NULL && (s = BackTraceInfo->SymbolicBackTrace)) {
  2408. while (*s) {
  2409. sprintf( DumpLine, " %s\n", s );
  2410. DumpOutputString();
  2411. while (*s++) {
  2412. }
  2413. }
  2414. }
  2415. s = DumpLine;
  2416. s += sprintf( s, "\n PointerCount: %u HandleCount: %u",
  2417. ObjectInfo->PointerCount,
  2418. ObjectInfo->HandleCount
  2419. );
  2420. if (ObjectInfo->SecurityDescriptor != NULL) {
  2421. s += sprintf( s, " Security: %p", ObjectInfo->SecurityDescriptor );
  2422. }
  2423. if (ObjectInfo->ExclusiveProcessId) {
  2424. s += sprintf( s, " Exclusive by Process: %p", ObjectInfo->ExclusiveProcessId );
  2425. }
  2426. s += sprintf( s, " Flags: %02x", ObjectInfo->Flags );
  2427. if (ObjectInfo->Flags & OB_FLAG_NEW_OBJECT) {
  2428. s += sprintf( s, " New" );
  2429. }
  2430. if (ObjectInfo->Flags & OB_FLAG_KERNEL_OBJECT) {
  2431. s += sprintf( s, " KernelMode" );
  2432. }
  2433. if (ObjectInfo->Flags & OB_FLAG_PERMANENT_OBJECT) {
  2434. s += sprintf( s, " Permanent" );
  2435. }
  2436. if (ObjectInfo->Flags & OB_FLAG_DEFAULT_SECURITY_QUOTA) {
  2437. s += sprintf( s, " DefaultSecurityQuota" );
  2438. }
  2439. if (ObjectInfo->Flags & OB_FLAG_SINGLE_HANDLE_ENTRY) {
  2440. s += sprintf( s, " Single Handle Entry" );
  2441. }
  2442. s += sprintf( s, "\n" );
  2443. DumpOutputString();
  2444. if (ObjectInfo->HandleCount != 0) {
  2445. PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX HandleEntry;
  2446. ULONG HandleNumber;
  2447. HandleEntry = &HandleInformation->Handles[ 0 ];
  2448. HandleNumber = 0;
  2449. while (HandleNumber++ < HandleInformation->NumberOfHandles) {
  2450. if (((HandleEntry->HandleAttributes & 0x80) && HandleEntry->Object == ObjectInfo) ||
  2451. (!(HandleEntry->HandleAttributes & 0x80) && HandleEntry->Object == ObjectInfo->Object)
  2452. ) {
  2453. sprintf( DumpLine, " Handle: %08lx Access:%08lx Process: %wZ\n",
  2454. HandleEntry->HandleValue,
  2455. HandleEntry->GrantedAccess,
  2456. &(FindProcessInfoForCid( (HANDLE)HandleEntry->UniqueProcessId )->ImageName)
  2457. );
  2458. DumpOutputString();
  2459. }
  2460. HandleEntry++;
  2461. }
  2462. }
  2463. sprintf( DumpLine, "\n" );
  2464. DumpOutputString();
  2465. if (ObjectInfo->NextEntryOffset == 0) {
  2466. break;
  2467. }
  2468. ObjectInfo = (PSYSTEM_OBJECT_INFORMATION)
  2469. ((PCHAR)ObjectInformation + ObjectInfo->NextEntryOffset);
  2470. }
  2471. if (TypeInfo->NextEntryOffset == 0) {
  2472. break;
  2473. }
  2474. TypeInfo = (PSYSTEM_OBJECTTYPE_INFORMATION)
  2475. ((PCHAR)ObjectInformation + TypeInfo->NextEntryOffset);
  2476. }
  2477. return;
  2478. }
  2479. ////////////////////////////////////////////////////////////////////////////////////////////
  2480. VOID
  2481. DumpHandles( VOID )
  2482. {
  2483. PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX HandleEntry;
  2484. HANDLE PreviousUniqueProcessId;
  2485. ULONG HandleNumber;
  2486. PRTL_PROCESS_BACKTRACE_INFORMATION BackTraceInfo;
  2487. PSYSTEM_OBJECT_INFORMATION ObjectInfo;
  2488. PVOID Object;
  2489. PUCHAR s;
  2490. if (fVerbose) {
  2491. fprintf( stderr, "DH: Dumping handle information.\n" );
  2492. }
  2493. sprintf( DumpLine, "\n\n*********** Object Handle Information ********************\n\n" );
  2494. DumpOutputString();
  2495. sprintf( DumpLine, "Number of handles: %u\n", HandleInformation->NumberOfHandles );
  2496. DumpOutputString();
  2497. HandleEntry = &HandleInformation->Handles[ 0 ];
  2498. HandleNumber = 0;
  2499. PreviousUniqueProcessId = INVALID_HANDLE_VALUE;
  2500. while (HandleNumber++ < HandleInformation->NumberOfHandles) {
  2501. if (PreviousUniqueProcessId != (HANDLE)HandleEntry->UniqueProcessId) {
  2502. PreviousUniqueProcessId = (HANDLE)HandleEntry->UniqueProcessId;
  2503. sprintf( DumpLine, "\n\n*********** Handles for %wZ ********************\n\n",
  2504. &(FindProcessInfoForCid( PreviousUniqueProcessId )->ImageName)
  2505. );
  2506. DumpOutputString();
  2507. }
  2508. if (HandleEntry->HandleAttributes & 0x80) {
  2509. ObjectInfo = HandleEntry->Object;
  2510. Object = ObjectInfo->Object;
  2511. }
  2512. else {
  2513. ObjectInfo = NULL;
  2514. Object = HandleEntry->Object;
  2515. }
  2516. sprintf( DumpLine, " Handle: %08lx%c Type: %wZ Object: %p Access: %08lx\n",
  2517. HandleEntry->HandleValue,
  2518. HandleEntry->HandleAttributes & OBJ_INHERIT ? 'i' : ' ',
  2519. TypeNames[ HandleEntry->ObjectTypeIndex < MAX_TYPE_NAMES ? HandleEntry->ObjectTypeIndex : MAX_TYPE_NAMES ],
  2520. Object,
  2521. HandleEntry->GrantedAccess
  2522. );
  2523. DumpOutputString();
  2524. if (ObjectInfo != NULL) {
  2525. UNICODE_STRING ObjectName;
  2526. ObjectName = ObjectInfo->NameInfo.Name;
  2527. try {
  2528. if (ObjectName.Length != 0 && *ObjectName.Buffer == UNICODE_NULL) {
  2529. ObjectName.Length = 0;
  2530. }
  2531. sprintf( DumpLine, " Name: %wZ\n",
  2532. &ObjectName
  2533. );
  2534. }
  2535. except( EXCEPTION_EXECUTE_HANDLER ) {
  2536. sprintf( DumpLine, " Name: [%04x, %04x, %p]\n",
  2537. ObjectName.MaximumLength,
  2538. ObjectName.Length,
  2539. ObjectName.Buffer
  2540. );
  2541. }
  2542. DumpOutputString();
  2543. }
  2544. if (HandleEntry->CreatorBackTraceIndex != 0) {
  2545. sprintf( DumpLine, " Creator: (Backtrace%05lu)\n", HandleEntry->CreatorBackTraceIndex );
  2546. DumpOutputString();
  2547. BackTraceInfo = FindBackTrace( HandleEntry->CreatorBackTraceIndex );
  2548. if (BackTraceInfo != NULL && (s = BackTraceInfo->SymbolicBackTrace)) {
  2549. while (*s) {
  2550. sprintf( DumpLine, " %s\n", s );
  2551. DumpOutputString();
  2552. while (*s++) {
  2553. }
  2554. }
  2555. }
  2556. }
  2557. sprintf( DumpLine, " \n" );
  2558. DumpOutputString();
  2559. HandleEntry++;
  2560. }
  2561. return;
  2562. }
  2563. ////////////////////////////////////////////////////////////////////////////////////////////
  2564. ULONG
  2565. GetDhSymbolicNameForAddress(
  2566. IN HANDLE UniqueProcess,
  2567. IN ULONG_PTR Address,
  2568. OUT LPSTR Name,
  2569. IN ULONG MaxNameLength
  2570. )
  2571. {
  2572. IMAGEHLP_MODULE ModuleInfo;
  2573. ULONG i, ModuleNameLength, Result;
  2574. ULONG_PTR Offset;
  2575. LPSTR s;
  2576. ModuleInfo.SizeOfStruct = sizeof(IMAGEHLP_MODULE);
  2577. ModuleNameLength = 0;
  2578. if (SymGetModuleInfo( UniqueProcess, Address, &ModuleInfo )) {
  2579. ModuleNameLength = strlen( ModuleInfo.ModuleName );
  2580. }
  2581. if (SymGetSymFromAddr( UniqueProcess, Address, &Offset, sym )) {
  2582. s = sym->Name;
  2583. i = 1;
  2584. while ( sym->MaxNameLength > i &&
  2585. isdigit( s[ sym->MaxNameLength - i ] )
  2586. ) {
  2587. i += 1;
  2588. }
  2589. if (s[ sym->MaxNameLength - i ] == '@') {
  2590. sym->MaxNameLength = sym->MaxNameLength - i;
  2591. }
  2592. s = Name;
  2593. Result = _snprintf( s, MaxNameLength,
  2594. "%.*s!%s",
  2595. ModuleNameLength,
  2596. ModuleInfo.ModuleName,
  2597. sym->Name
  2598. );
  2599. if (Offset != 0) {
  2600. Result += _snprintf( s + Result, MaxNameLength - Result, "+0x%x", Offset );
  2601. }
  2602. }
  2603. else {
  2604. if (ModuleNameLength != 0) {
  2605. Result = _snprintf( Name, MaxNameLength,
  2606. "%.*s!0x%08x",
  2607. ModuleNameLength,
  2608. ModuleInfo.ModuleName,
  2609. Address
  2610. );
  2611. }
  2612. else {
  2613. Result = _snprintf( Name, MaxNameLength, "0x%08x", Address );
  2614. }
  2615. }
  2616. return Result;
  2617. }