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.

2115 lines
56 KiB

  1. /*++
  2. Copyright (c) 1990-2000 Microsoft Corporation
  3. Module Name:
  4. ntsdexts.c
  5. Abstract:
  6. This function contains the default ntsd debugger extensions
  7. Revision History:
  8. Daniel Mihai (DMihai) 18-Feb-2001
  9. Add !htrace - useful for dumping handle trace information.
  10. --*/
  11. #include "ntsdextp.h"
  12. VOID
  13. DecodeError(
  14. PSTR Banner,
  15. ULONG Code,
  16. BOOL TreatAsStatus
  17. )
  18. {
  19. HANDLE Dll ;
  20. PSTR Source ;
  21. UCHAR Message[ 512 ];
  22. PUCHAR s;
  23. if ( !TreatAsStatus )
  24. {
  25. //
  26. // The value "type" is not known. Try and figure out what it
  27. // is.
  28. //
  29. if ( (Code & 0xC0000000) == 0xC0000000 )
  30. {
  31. //
  32. // Easy: NTSTATUS failure case
  33. //
  34. Dll = GetModuleHandle( "NTDLL.DLL" );
  35. Source = "NTSTATUS" ;
  36. TreatAsStatus = TRUE ;
  37. }
  38. else if ( ( Code & 0xF0000000 ) == 0xD0000000 )
  39. {
  40. //
  41. // HRESULT from NTSTATUS
  42. //
  43. Dll = GetModuleHandle( "NTDLL.DLL" );
  44. Source = "NTSTATUS" ;
  45. Code &= 0xCFFFFFFF ;
  46. TreatAsStatus = TRUE ;
  47. }
  48. else if ( ( Code & 0x80000000 ) == 0x80000000 )
  49. {
  50. //
  51. // Note, this can overlap with NTSTATUS warning area. In that
  52. // case, force the NTSTATUS.
  53. //
  54. Dll = GetModuleHandle( "KERNEL32.DLL" );
  55. Source = "HRESULT" ;
  56. }
  57. else
  58. {
  59. //
  60. // Sign bit is off. Explore some known ranges:
  61. //
  62. if ( (Code >= WSABASEERR) && (Code <= WSABASEERR + 1000 ))
  63. {
  64. Dll = LoadLibrary( "wsock32.dll" );
  65. Source = "Winsock" ;
  66. }
  67. else if ( ( Code >= NERR_BASE ) && ( Code <= MAX_NERR ) )
  68. {
  69. Dll = LoadLibrary( "netmsg.dll" );
  70. Source = "NetAPI" ;
  71. }
  72. else
  73. {
  74. Dll = GetModuleHandle( "KERNEL32.DLL" );
  75. Source = "Win32" ;
  76. }
  77. }
  78. }
  79. else
  80. {
  81. Dll = GetModuleHandle( "NTDLL.DLL" );
  82. Source = "NTSTATUS" ;
  83. }
  84. if (!FormatMessage( FORMAT_MESSAGE_IGNORE_INSERTS |
  85. FORMAT_MESSAGE_FROM_HMODULE,
  86. Dll,
  87. Code,
  88. 0,
  89. Message,
  90. sizeof( Message ),
  91. NULL ) )
  92. {
  93. strcpy( Message, "No mapped error code" );
  94. }
  95. s = Message ;
  96. while (*s) {
  97. if (*s < ' ') {
  98. *s = ' ';
  99. }
  100. s++;
  101. }
  102. if ( !TreatAsStatus )
  103. {
  104. dprintf( "%s: (%s) %#x (%u) - %s\n",
  105. Banner,
  106. Source,
  107. Code,
  108. Code,
  109. Message );
  110. }
  111. else
  112. {
  113. dprintf( "%s: (%s) %#x - %s\n",
  114. Banner,
  115. Source,
  116. Code,
  117. Message );
  118. }
  119. }
  120. DECLARE_API( error )
  121. {
  122. ULONG err ;
  123. INIT_API();
  124. err = (ULONG) GetExpression( args );
  125. DecodeError( "Error code", err, FALSE );
  126. EXIT_API();
  127. }
  128. BOOL
  129. DumpLastErrorForTeb(
  130. ULONG64 Address
  131. )
  132. {
  133. TEB Teb;
  134. if (ReadMemory( (ULONG_PTR)Address,
  135. &Teb,
  136. sizeof(Teb),
  137. NULL
  138. )
  139. ) {
  140. DecodeError( "LastErrorValue", Teb.LastErrorValue, FALSE );
  141. DecodeError( "LastStatusValue", Teb.LastStatusValue, TRUE );
  142. return TRUE;
  143. }
  144. dprintf("Unable to read TEB at %p\n", Address );
  145. return FALSE;
  146. }
  147. BOOL
  148. DumpCurrentThreadLastError(
  149. ULONG CurrThreadID,
  150. PVOID Context
  151. )
  152. {
  153. NTSTATUS Status;
  154. THREAD_BASIC_INFORMATION ThreadInformation;
  155. ULONGLONG Address;
  156. TEB Teb;
  157. if (Context) {
  158. dprintf("Last error for thread %lx:\n", CurrThreadID);
  159. }
  160. GetTebAddress(&Address);
  161. if (Address) {
  162. DumpLastErrorForTeb(Address);
  163. } else {
  164. dprintf("Unable to read thread %lx's TEB\n", CurrThreadID );
  165. }
  166. if (Context) {
  167. dprintf("\n");
  168. }
  169. return TRUE;
  170. }
  171. DECLARE_API( gle )
  172. {
  173. INIT_API();
  174. if (!strcmp(args, "-all")) {
  175. EnumerateUModeThreads(&DumpCurrentThreadLastError, Client);
  176. } else {
  177. DumpCurrentThreadLastError(GetCurrentThreadUserID(), NULL);
  178. }
  179. EXIT_API();
  180. }
  181. DECLARE_API( version )
  182. {
  183. OSVERSIONINFOA VersionInformation;
  184. HKEY hkey;
  185. DWORD cb, dwType;
  186. CHAR szCurrentType[128];
  187. CHAR szCSDString[3+128];
  188. INIT_API();
  189. VersionInformation.dwOSVersionInfoSize = sizeof(VersionInformation);
  190. if (!GetVersionEx( &VersionInformation )) {
  191. dprintf("GetVersionEx failed - %u\n", GetLastError());
  192. goto Exit;
  193. }
  194. szCurrentType[0] = '\0';
  195. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  196. "Software\\Microsoft\\Windows NT\\CurrentVersion",
  197. 0,
  198. KEY_READ,
  199. &hkey
  200. ) == NO_ERROR
  201. ) {
  202. cb = sizeof(szCurrentType);
  203. if (hkey) {
  204. if (RegQueryValueEx(hkey, "CurrentType", NULL, &dwType, szCurrentType, &cb ) != 0) {
  205. szCurrentType[0] = '\0';
  206. }
  207. RegCloseKey(hkey);
  208. }
  209. }
  210. if (VersionInformation.szCSDVersion[0]) {
  211. sprintf(szCSDString, ": %s", VersionInformation.szCSDVersion);
  212. }
  213. else {
  214. szCSDString[0] = '\0';
  215. }
  216. dprintf("Version %d.%d (Build %d%s) %s\n",
  217. VersionInformation.dwMajorVersion,
  218. VersionInformation.dwMinorVersion,
  219. VersionInformation.dwBuildNumber,
  220. szCSDString,
  221. szCurrentType
  222. );
  223. Exit:
  224. EXIT_API();
  225. }
  226. DECLARE_API( help )
  227. {
  228. INIT_API();
  229. while (*args == ' ')
  230. args++;
  231. if (*args == '\0') {
  232. dprintf("ntsdexts help:\n\n");
  233. dprintf("!critSec csAddress - Dump a critical section\n");
  234. dprintf("!dp [v] [pid | pcsr_process] - Dump CSR process\n");
  235. dprintf("!dreg -[d|w] <keyPath>[![<valueName> | *]] - Dump registry information\n");
  236. dprintf("!dt [v] pcsr_thread - Dump CSR thread\n");
  237. dprintf("!error value - Decode error value\n");
  238. dprintf("!gatom - Dump the global atom table\n");
  239. dprintf("!gle [-all] - Dump GetLastError value for current/all thread\n");
  240. dprintf("!handle [handle] - Dump handle information\n");
  241. dprintf("!help [cmd] - Displays this list or gives details on command\n");
  242. dprintf("!locks [-v][-o] - Dump all Critical Sections in process\n");
  243. dprintf("!version - Dump system version and build number\n");
  244. dprintf("!vprot [address] - Dump the virtual protect settings\n");
  245. } else {
  246. if (*args == '!')
  247. args++;
  248. if (strcmp( args, "handle") == 0) {
  249. dprintf("!handle [handle [flags [type]]] - Dump handle information\n");
  250. dprintf(" If no handle specified, all handles are dumped.\n");
  251. dprintf(" Flags are bits indicating greater levels of detail.\n");
  252. dprintf("If the handle is 0 or -1, all handles are scanned. If the handle is not\n");
  253. dprintf("zero, that particular handle is examined. The flags are as follows:\n");
  254. dprintf(" 1 - Get type information (default)\n");
  255. dprintf(" 2 - Get basic information\n");
  256. dprintf(" 4 - Get name information\n");
  257. dprintf(" 8 - Get object specific info (where available)\n");
  258. dprintf("\n");
  259. dprintf("If Type is specified, only object of that type are scanned. Type is a\n");
  260. dprintf("standard NT type name, e.g. Event, Semaphore, etc. Case sensitive, of\n");
  261. dprintf("course.\n");
  262. dprintf("\n");
  263. dprintf("Examples:\n");
  264. dprintf("\n");
  265. dprintf(" !handle -- dumps the types of all the handles, and a summary table\n");
  266. dprintf(" !handle 0 0 -- dumps a summary table of all the open handles\n");
  267. dprintf(" !handle 0 f -- dumps everything we can find about a handle.\n");
  268. dprintf(" !handle 0 f Event\n");
  269. dprintf(" -- dumps everything we can find about open events\n");
  270. } else if (strcmp( args, "gflag") == 0) {
  271. dprintf("If a value is not given then displays the current bits set in\n");
  272. dprintf("NTDLL!NtGlobalFlag variable. Otherwise value can be one of the\n");
  273. dprintf("following:\n");
  274. dprintf("\n");
  275. dprintf(" -? - displays a list of valid flag abbreviations\n");
  276. dprintf(" number - 32-bit number that becomes the new value stored into\n");
  277. dprintf(" NtGlobalFlag\n");
  278. dprintf(" +number - specifies one or more bits to set in NtGlobalFlag\n");
  279. dprintf(" +abbrev - specifies a single bit to set in NtGlobalFlag\n");
  280. dprintf(" -number - specifies one or more bits to clear in NtGlobalFlag\n");
  281. dprintf(" -abbrev - specifies a single bit to clear in NtGlobalFlag\n");
  282. } else {
  283. dprintf("Invalid command. No help available\n");
  284. }
  285. }
  286. EXIT_API();
  287. }
  288. VOID
  289. DumpStackBackTraceIndex(
  290. IN USHORT BackTraceIndex
  291. )
  292. {
  293. #if i386
  294. BOOL b;
  295. PRTL_STACK_TRACE_ENTRY pBackTraceEntry;
  296. RTL_STACK_TRACE_ENTRY BackTraceEntry;
  297. ULONG i;
  298. CHAR Symbol[ 1024 ];
  299. ULONG_PTR Displacement;
  300. ULONG NumberOfEntriesAdded;
  301. PRTL_STACK_TRACE_ENTRY *EntryIndexArray; // Indexed by [-1 .. -NumberOfEntriesAdded]
  302. PSTACK_TRACE_DATABASE *pRtlpStackTraceDataBase;
  303. PSTACK_TRACE_DATABASE RtlpStackTraceDataBase;
  304. STACK_TRACE_DATABASE StackTraceDataBase;
  305. pRtlpStackTraceDataBase = (PSTACK_TRACE_DATABASE *)GetExpression( "NTDLL!RtlpStackTraceDataBase" );
  306. if (pRtlpStackTraceDataBase == NULL) {
  307. dprintf( "HEAPEXT: Unable to get address of NTDLL!RtlpStackTraceDataBase\n" );
  308. }
  309. if ((BackTraceIndex != 0) && (pRtlpStackTraceDataBase != NULL)) {
  310. b = ReadMemory( (ULONG_PTR)pRtlpStackTraceDataBase,
  311. &RtlpStackTraceDataBase,
  312. sizeof( RtlpStackTraceDataBase ),
  313. NULL
  314. );
  315. if (!b || RtlpStackTraceDataBase == NULL) {
  316. return;
  317. }
  318. b = ReadMemory( (ULONG_PTR)RtlpStackTraceDataBase,
  319. &StackTraceDataBase,
  320. sizeof( StackTraceDataBase ),
  321. NULL
  322. );
  323. if (!b) {
  324. return;
  325. }
  326. if (BackTraceIndex < StackTraceDataBase.NumberOfEntriesAdded) {
  327. b = ReadMemory( (ULONG_PTR)(StackTraceDataBase.EntryIndexArray - BackTraceIndex),
  328. &pBackTraceEntry,
  329. sizeof( pBackTraceEntry ),
  330. NULL
  331. );
  332. if (!b) {
  333. dprintf( " unable to read stack back trace index (%x) entry at %p\n",
  334. BackTraceIndex,
  335. (StackTraceDataBase.EntryIndexArray - BackTraceIndex)
  336. );
  337. return;
  338. }
  339. b = ReadMemory( (ULONG_PTR)pBackTraceEntry,
  340. &BackTraceEntry,
  341. sizeof( BackTraceEntry ),
  342. NULL
  343. );
  344. if (!b) {
  345. dprintf( " unable to read stack back trace entry at %p\n",
  346. BackTraceIndex,
  347. pBackTraceEntry
  348. );
  349. return;
  350. }
  351. dprintf( "\n Stack trace (%u) at %x:\n", BackTraceIndex, pBackTraceEntry );
  352. for (i=0; i<BackTraceEntry.Depth; i++) {
  353. GetSymbol( (LPVOID)BackTraceEntry.BackTrace[ i ],
  354. Symbol,
  355. &Displacement
  356. );
  357. dprintf( " %08x: %s", BackTraceEntry.BackTrace[ i ], Symbol );
  358. if (Displacement != 0) {
  359. dprintf( "+0x%p", Displacement );
  360. }
  361. dprintf( "\n" );
  362. }
  363. }
  364. }
  365. #endif
  366. return;
  367. }
  368. PLIST_ENTRY
  369. DumpCritSec(
  370. DWORD_PTR dwAddrCritSec,
  371. DWORD_PTR dwAddrDebugInfo,
  372. BOOLEAN bDumpIfUnowned,
  373. BOOLEAN bOrphaned
  374. )
  375. /*++
  376. Routine Description:
  377. This function is called as an NTSD extension to format and dump
  378. the contents of the specified critical section.
  379. Arguments:
  380. dwAddrCritSec - Supplies the address of the critical section to
  381. be dumped or NULL if dumping via debug info
  382. dwAddrDebugInfo - Supllies the address of a critical section debug info
  383. struct to be dumped or NULL if the critical section address is passed in
  384. bDumpIfUnowned - TRUE means to dump the critical section even if
  385. it is currently unowned.
  386. bOrphaned - TRUE: means that the caller only wants to know if the debuginfo does
  387. not point to a valid critical section
  388. Return Value:
  389. Pointer to the next critical section in the list for the process or
  390. NULL if no more critical sections.
  391. --*/
  392. {
  393. USHORT i;
  394. CHAR Symbol[1024];
  395. DWORD_PTR Displacement;
  396. CRITICAL_SECTION CriticalSection;
  397. CRITICAL_SECTION_DEBUG DebugInfo;
  398. BOOL b;
  399. PLIST_ENTRY Next=NULL;
  400. if (dwAddrDebugInfo != (DWORD_PTR)NULL) {
  401. //
  402. // the address of the debug info was passes in, read it in from the debugged process
  403. //
  404. b = ReadMemory( dwAddrDebugInfo,
  405. &DebugInfo,
  406. sizeof(DebugInfo),
  407. NULL
  408. );
  409. if ( !b ) {
  410. dprintf(" NTSDEXTS: Unable to read RTL_CRITICAL_SECTION_DEBUG at %p\n", dwAddrDebugInfo );
  411. return NULL;
  412. }
  413. //
  414. // get the critical section from the debug info
  415. //
  416. dwAddrCritSec=(DWORD_PTR)DebugInfo.CriticalSection;
  417. //
  418. // set the next pointer now. It is only used when the debuginfo is passed in
  419. //
  420. Next=DebugInfo.ProcessLocksList.Flink;
  421. } else {
  422. //
  423. // the debug info address was zero, the critical section address better not be too
  424. //
  425. if (dwAddrCritSec == (DWORD_PTR)NULL) {
  426. //
  427. // If the debuginfo value was not valid, then the critical section value must be
  428. //
  429. return NULL;
  430. }
  431. }
  432. //
  433. // we should now have a pointer to the critical section, either passed in or read from
  434. // the debug info
  435. //
  436. //
  437. // Read the critical section from the debuggees address space into our
  438. // own.
  439. //
  440. b = ReadMemory( dwAddrCritSec,
  441. &CriticalSection,
  442. sizeof(CriticalSection),
  443. NULL
  444. );
  445. if ( !b ) {
  446. if (bDumpIfUnowned || bOrphaned) {
  447. dprintf("\nCritSec at %p could not be read\n",dwAddrCritSec);
  448. dprintf("Perhaps the critical section was a global variable in a dll that was unloaded?\n");
  449. if (dwAddrDebugInfo != (DWORD_PTR)NULL) {
  450. if (bOrphaned) {
  451. DumpStackBackTraceIndex(DebugInfo.CreatorBackTraceIndex);
  452. }
  453. }
  454. }
  455. return Next;
  456. }
  457. if (dwAddrDebugInfo != (DWORD_PTR)NULL) {
  458. //
  459. // the debug info address was passed in, make sure the critical section that
  460. // it pointed to points back to it.
  461. //
  462. if ((DWORD_PTR)CriticalSection.DebugInfo != dwAddrDebugInfo) {
  463. //
  464. // this critical section does not point back to debug info that we got it from
  465. //
  466. CRITICAL_SECTION_DEBUG OtherDebugInfo;
  467. //
  468. // now lets try to read in the debug info that this critical section points to,
  469. // to see if it does point back the critical section in question
  470. //
  471. ZeroMemory(&OtherDebugInfo,sizeof(OtherDebugInfo));
  472. b = ReadMemory( (ULONG_PTR)CriticalSection.DebugInfo,
  473. &OtherDebugInfo,
  474. sizeof(DebugInfo),
  475. NULL
  476. );
  477. if ( !b ) {
  478. //
  479. // we could not read the debug info pointed to by the critical section,
  480. // probably means the critical section has been trashed
  481. //
  482. if (bDumpIfUnowned || bOrphaned) {
  483. dprintf("\nCritSec at %p does not point back to the debug info at %p\n",dwAddrCritSec,dwAddrDebugInfo);
  484. dprintf("Perhaps the memory that held the critical section has been reused without calling DeleteCriticalSection() ?\n");
  485. if (bOrphaned) {
  486. DumpStackBackTraceIndex(DebugInfo.CreatorBackTraceIndex);
  487. }
  488. }
  489. } else {
  490. //
  491. // we were able to read in the debug info, see if it points to this new
  492. // critical section
  493. //
  494. if ((DWORD_PTR)OtherDebugInfo.CriticalSection == dwAddrCritSec) {
  495. //
  496. // the debug info points back to the critical section.
  497. // The definitely means that it was re-initialized.
  498. //
  499. if (bDumpIfUnowned || bOrphaned) {
  500. GetSymbol((LPVOID)dwAddrCritSec,Symbol,&Displacement);
  501. dprintf(
  502. "\nThe CritSec %s+%lx at %p has been RE-INITIALIZED.\n",
  503. Symbol,
  504. Displacement,
  505. dwAddrCritSec
  506. );
  507. dprintf("The critical section points to DebugInfo at %p instead of %p\n",(DWORD_PTR)CriticalSection.DebugInfo,dwAddrDebugInfo);
  508. if (bOrphaned) {
  509. DumpStackBackTraceIndex(DebugInfo.CreatorBackTraceIndex);
  510. }
  511. }
  512. } else {
  513. //
  514. // The debug info does not point back the critical section, probably means that
  515. // the critical section was trashed
  516. //
  517. if (bDumpIfUnowned || bOrphaned) {
  518. dprintf("\nCritSec at %p does not point back to the debug info at %p\n",dwAddrCritSec,dwAddrDebugInfo);
  519. dprintf("Perhaps the memory that held the critical section has been reused without calling DeleteCriticalSection() ?\n");
  520. if (bOrphaned) {
  521. DumpStackBackTraceIndex(DebugInfo.CreatorBackTraceIndex);
  522. }
  523. }
  524. }
  525. }
  526. }
  527. } else {
  528. //
  529. // we need to read in the debug info from the critical section since it was not passed in
  530. //
  531. ZeroMemory(&DebugInfo,sizeof(DebugInfo));
  532. b = ReadMemory( (ULONG_PTR)CriticalSection.DebugInfo,
  533. &DebugInfo,
  534. sizeof(DebugInfo),
  535. NULL
  536. );
  537. if ( !b ) {
  538. //
  539. // use this to signal that we could not read the debuginfo for the critical section
  540. //
  541. CriticalSection.DebugInfo=NULL;
  542. dprintf("\nDebugInfo for CritSec at %p could not be read\n",dwAddrCritSec);
  543. dprintf("Probably NOT an initialized critical section.\n");
  544. } else {
  545. //
  546. // we were able to read in the debug info, see if it valid
  547. //
  548. if ((DWORD_PTR)DebugInfo.CriticalSection != dwAddrCritSec) {
  549. //
  550. // The debug info does not point back to the critical section
  551. //
  552. dprintf("\nDebugInfo for CritSec at %p does not point back to the critical section\n",dwAddrCritSec);
  553. dprintf("NOT an initialized critical section.\n");
  554. }
  555. }
  556. }
  557. //
  558. // we should now have read in both the critical section and debug info for that critical section
  559. //
  560. if (bOrphaned) {
  561. //
  562. // the user only wanted to check for orphaned critical sections
  563. //
  564. return Next;
  565. }
  566. //
  567. // Dump the critical section
  568. //
  569. if ( CriticalSection.LockCount == -1 && !bDumpIfUnowned) {
  570. //
  571. // Lock is not held and the user does not want verbose output
  572. //
  573. return Next;
  574. }
  575. //
  576. // Get the symbolic name of the critical section
  577. //
  578. dprintf("\n");
  579. GetSymbol((LPVOID)dwAddrCritSec,Symbol,&Displacement);
  580. dprintf(
  581. "CritSec %s+%lx at %p\n",
  582. Symbol,
  583. Displacement,
  584. dwAddrCritSec
  585. );
  586. if ( CriticalSection.LockCount == -1) {
  587. dprintf("LockCount NOT LOCKED\n");
  588. } else {
  589. dprintf("LockCount %ld\n",CriticalSection.LockCount);
  590. }
  591. dprintf("RecursionCount %ld\n",CriticalSection.RecursionCount);
  592. dprintf("OwningThread %lx\n",CriticalSection.OwningThread);
  593. if (CriticalSection.DebugInfo != NULL) {
  594. //
  595. // we have the debug info
  596. //
  597. dprintf("EntryCount %lx\n",DebugInfo.EntryCount);
  598. dprintf("ContentionCount %lx\n",DebugInfo.ContentionCount);
  599. }
  600. if ( CriticalSection.LockCount != -1) {
  601. dprintf("*** Locked\n");
  602. }
  603. return Next;
  604. }
  605. DECLARE_API( critsec )
  606. {
  607. DWORD_PTR dwAddrCritSec;
  608. INIT_API();
  609. //
  610. // Evaluate the argument string to get the address of
  611. // the critical section to dump.
  612. //
  613. dwAddrCritSec = GetExpression(args);
  614. if ( !dwAddrCritSec ) {
  615. goto Exit;
  616. }
  617. DumpCritSec(dwAddrCritSec,0,TRUE,FALSE);
  618. Exit:
  619. EXIT_API();
  620. }
  621. DECLARE_API( locks )
  622. /*++
  623. Routine Description:
  624. This function is called as an NTSD extension to display all
  625. critical sections in the target process.
  626. Return Value:
  627. None.
  628. --*/
  629. {
  630. BOOL b;
  631. CRITICAL_SECTION_DEBUG DebugInfo;
  632. PVOID AddrListHead;
  633. LIST_ENTRY ListHead;
  634. PLIST_ENTRY Next;
  635. BOOLEAN Verbose;
  636. BOOLEAN Orphaned=FALSE;
  637. LPCSTR p;
  638. DWORD NumberOfCriticalSections;
  639. INIT_API();
  640. Verbose = FALSE;
  641. p = (LPSTR)args;
  642. while ( p != NULL && *p ) {
  643. if ( *p == '-' ) {
  644. p++;
  645. switch ( *p ) {
  646. case 'V':
  647. case 'v':
  648. Verbose = TRUE;
  649. p++;
  650. break;
  651. case 'o':
  652. case 'O':
  653. Orphaned=TRUE;
  654. p++;
  655. break;
  656. case ' ':
  657. goto gotBlank;
  658. default:
  659. dprintf( "NTSDEXTS: !locks invalid option flag '-%c'\n", *p );
  660. break;
  661. }
  662. }
  663. else {
  664. gotBlank:
  665. p++;
  666. }
  667. }
  668. if (Orphaned) {
  669. dprintf( "Looking for orphaned critical sections\n" );
  670. }
  671. //
  672. // Locate the address of the list head.
  673. //
  674. AddrListHead = (PVOID)GetExpression("ntdll!RtlCriticalSectionList");
  675. if ( !AddrListHead ) {
  676. dprintf( "NTSDEXTS: Unable to resolve ntdll!RtlCriticalSectionList\n" );
  677. dprintf( "NTSDEXTS: Please check your symbols\n" );
  678. goto Exit;
  679. }
  680. //
  681. // Read the list head
  682. //
  683. b = ReadMemory( (ULONG_PTR)AddrListHead,
  684. &ListHead,
  685. sizeof(ListHead),
  686. NULL
  687. );
  688. if ( !b ) {
  689. dprintf( "NTSDEXTS: Unable to read memory at ntdll!RtlCriticalSectionList\n" );
  690. goto Exit;
  691. }
  692. Next = ListHead.Flink;
  693. (CheckControlC)();
  694. NumberOfCriticalSections=0;
  695. //
  696. // Walk the list of critical sections
  697. //
  698. while ( Next != AddrListHead ) {
  699. Next=DumpCritSec(
  700. 0,
  701. (DWORD_PTR)CONTAINING_RECORD( Next, RTL_CRITICAL_SECTION_DEBUG, ProcessLocksList),
  702. Verbose,
  703. Orphaned
  704. );
  705. if (Next == NULL) {
  706. dprintf( "\nStopped scanning because of problem reading critical section debug info\n");
  707. break;
  708. }
  709. NumberOfCriticalSections++;
  710. if ((CheckControlC)()) {
  711. dprintf( "\nStopped scanning because of control-C\n");
  712. break;
  713. }
  714. }
  715. dprintf( "\nScanned %d critical sections\n",NumberOfCriticalSections);
  716. Exit:
  717. EXIT_API();
  718. }
  719. //
  720. // Simple routine to convert from hex into a string of characters.
  721. // Used by debugger extensions.
  722. //
  723. // by scottlu
  724. //
  725. char *
  726. HexToString(
  727. ULONG_PTR dw,
  728. CHAR *pch
  729. )
  730. {
  731. if (dw > 0xf) {
  732. pch = HexToString(dw >> 4, pch);
  733. dw &= 0xf;
  734. }
  735. *pch++ = ((dw >= 0xA) ? ('A' - 0xA) : '0') + (CHAR)dw;
  736. *pch = 0;
  737. return pch;
  738. }
  739. //
  740. // dt == dump thread
  741. //
  742. // dt [v] pcsr_thread
  743. // v == verbose (structure)
  744. //
  745. // by scottlu
  746. //
  747. DECLARE_API( dt )
  748. {
  749. char chVerbose;
  750. CSR_THREAD csrt;
  751. ULONG_PTR dw;
  752. BOOL b;
  753. INIT_API();
  754. while (*args == ' ')
  755. args++;
  756. chVerbose = ' ';
  757. if (*args == 'v')
  758. chVerbose = *args++;
  759. dw = GetExpression(args);
  760. b = ReadMemory( dw, &csrt, sizeof(csrt), NULL);
  761. if ( !b ) {
  762. dprintf( "NTSDEXTS: Unable to read memory\n" );
  763. goto Exit;
  764. }
  765. //
  766. // Print simple thread info if the user did not ask for verbose.
  767. //
  768. if (chVerbose == ' ') {
  769. dprintf("Thread %08lx, Process %08lx, ClientId %lx.%lx, Flags %lx, Ref Count %lx\n",
  770. dw,
  771. csrt.Process,
  772. csrt.ClientId.UniqueProcess,
  773. csrt.ClientId.UniqueThread,
  774. csrt.Flags,
  775. csrt.ReferenceCount);
  776. goto Exit;
  777. }
  778. dprintf("PCSR_THREAD @ %08lx:\n"
  779. "\t+%04lx Link.Flink %08lx\n"
  780. "\t+%04lx Link.Blink %08lx\n"
  781. "\t+%04lx Process %08lx\n",
  782. dw,
  783. FIELD_OFFSET(CSR_THREAD, Link.Flink), csrt.Link.Flink,
  784. FIELD_OFFSET(CSR_THREAD, Link.Blink), csrt.Link.Blink,
  785. FIELD_OFFSET(CSR_THREAD, Process), csrt.Process);
  786. dprintf(
  787. "\t+%04lx WaitBlock %08lx\n"
  788. "\t+%04lx ClientId.UniqueProcess %08lx\n"
  789. "\t+%04lx ClientId.UniqueThread %08lx\n"
  790. "\t+%04lx ThreadHandle %08lx\n",
  791. FIELD_OFFSET(CSR_THREAD, WaitBlock), csrt.WaitBlock,
  792. FIELD_OFFSET(CSR_THREAD, ClientId.UniqueProcess), csrt.ClientId.UniqueProcess,
  793. FIELD_OFFSET(CSR_THREAD, ClientId.UniqueThread), csrt.ClientId.UniqueThread,
  794. FIELD_OFFSET(CSR_THREAD, ThreadHandle), csrt.ThreadHandle);
  795. dprintf(
  796. "\t+%04lx Flags %08lx\n"
  797. "\t+%04lx ReferenceCount %08lx\n"
  798. "\t+%04lx HashLinks.Flink %08lx\n"
  799. "\t+%04lx HashLinks.Blink %08lx\n",
  800. FIELD_OFFSET(CSR_THREAD, Flags), csrt.Flags,
  801. FIELD_OFFSET(CSR_THREAD, ReferenceCount), csrt.ReferenceCount,
  802. FIELD_OFFSET(CSR_THREAD, HashLinks.Flink), csrt.HashLinks.Flink,
  803. FIELD_OFFSET(CSR_THREAD, HashLinks.Blink), csrt.HashLinks.Blink);
  804. Exit:
  805. EXIT_API();
  806. }
  807. //
  808. // dp == dump process
  809. //
  810. // dp [v] [pid | pcsr_process]
  811. // v == verbose (structure + thread list)
  812. // no process == dump process list
  813. //
  814. // by scottlu
  815. //
  816. DECLARE_API( dp )
  817. {
  818. PLIST_ENTRY ListHead, ListNext;
  819. char ach[80];
  820. char chVerbose;
  821. PCSR_PROCESS pcsrpT;
  822. CSR_PROCESS csrp;
  823. PCSR_PROCESS pcsrpRoot;
  824. PCSR_THREAD pcsrt;
  825. ULONG_PTR dwProcessId;
  826. ULONG_PTR dw;
  827. DWORD_PTR dwRootProcess;
  828. BOOL b;
  829. INIT_API();
  830. while (*args == ' ')
  831. args++;
  832. chVerbose = ' ';
  833. if (*args == 'v')
  834. chVerbose = *args++;
  835. dwRootProcess = GetExpression("csrsrv!CsrRootProcess");
  836. if ( !dwRootProcess ) {
  837. goto Exit;
  838. }
  839. b = ReadMemory( dwRootProcess, &pcsrpRoot, sizeof(pcsrpRoot), NULL);
  840. if ( !b ) {
  841. dprintf( "NTSDEXTS: Unable to read RootProcess\n" );
  842. goto Exit;
  843. }
  844. //
  845. // See if user wants all processes. If so loop through them.
  846. //
  847. if (*args == 0) {
  848. ListHead = &pcsrpRoot->ListLink;
  849. b = ReadMemory( (ULONG_PTR)(&ListHead->Flink), &ListNext, sizeof(ListNext), NULL);
  850. if ( !b ) {
  851. dprintf( "NTSDEXTS: Unable to read ListNext\n" );
  852. goto Exit;
  853. }
  854. while (ListNext != ListHead) {
  855. pcsrpT = CONTAINING_RECORD(ListNext, CSR_PROCESS, ListLink);
  856. ach[0] = chVerbose;
  857. ach[1] = ' ';
  858. HexToString((ULONG_PTR)pcsrpT, &ach[2]);
  859. dp(Client, ach);
  860. b = ReadMemory( (ULONG_PTR)(&ListNext->Flink), &ListNext, sizeof(ListNext), NULL);
  861. if ( !b ) {
  862. dprintf( "NTSDEXTS: Unable to read ListNext\n" );
  863. goto Exit;
  864. }
  865. }
  866. dprintf("---\n");
  867. goto Exit;
  868. }
  869. //
  870. // User wants specific process structure. Evaluate to find id or process
  871. // pointer.
  872. //
  873. dw = (ULONG)GetExpression(args);
  874. ListHead = &pcsrpRoot->ListLink;
  875. b = ReadMemory( (ULONG_PTR)(&ListHead->Flink), &ListNext, sizeof(ListNext), NULL);
  876. if ( !b ) {
  877. dprintf( "NTSDEXTS: Unable to read ListNext\n" );
  878. goto Exit;
  879. }
  880. while (ListNext != ListHead) {
  881. pcsrpT = CONTAINING_RECORD(ListNext, CSR_PROCESS, ListLink);
  882. b = ReadMemory( (ULONG_PTR)(&ListNext->Flink), &ListNext, sizeof(ListNext), NULL);
  883. if ( !b ) {
  884. dprintf( "NTSDEXTS: Unable to read ListNext\n" );
  885. goto Exit;
  886. }
  887. b = ReadMemory( (ULONG_PTR)(&pcsrpT->ClientId.UniqueProcess), &dwProcessId, sizeof(dwProcessId), NULL);
  888. if ( !b ) {
  889. dprintf( "NTSDEXTS: Unable to read ListNext\n" );
  890. goto Exit;
  891. }
  892. if (dw == dwProcessId) {
  893. dw = (ULONG_PTR)pcsrpT;
  894. break;
  895. }
  896. }
  897. pcsrpT = (PCSR_PROCESS)dw;
  898. b = ReadMemory( (ULONG_PTR)pcsrpT, &csrp, sizeof(csrp), NULL);
  899. if ( !b ) {
  900. dprintf( "NTSDEXTS: Unable to read RootProcess\n" );
  901. goto Exit;
  902. }
  903. //
  904. // If not verbose, print simple process info.
  905. //
  906. if (chVerbose == ' ') {
  907. dprintf("Process %08lx, Id %p, Seq# %lx, Flags %lx, Ref Count %lx\n",
  908. pcsrpT,
  909. csrp.ClientId.UniqueProcess,
  910. csrp.SequenceNumber,
  911. csrp.Flags,
  912. csrp.ReferenceCount);
  913. goto Exit;
  914. }
  915. dprintf("PCSR_PROCESS @ %08lx:\n"
  916. "\t+%04lx ListLink.Flink %08lx\n"
  917. "\t+%04lx ListLink.Blink %08lx\n"
  918. "\t+%04lx Parent %08lx\n",
  919. pcsrpT,
  920. FIELD_OFFSET(CSR_PROCESS, ListLink.Flink), csrp.ListLink.Flink,
  921. FIELD_OFFSET(CSR_PROCESS, ListLink.Blink), csrp.ListLink.Blink,
  922. FIELD_OFFSET(CSR_PROCESS, Parent), csrp.Parent);
  923. dprintf(
  924. "\t+%04lx ThreadList.Flink %08lx\n"
  925. "\t+%04lx ThreadList.Blink %08lx\n"
  926. "\t+%04lx NtSession %08lx\n"
  927. "\t+%04lx ExpectedVersion %08lx\n",
  928. FIELD_OFFSET(CSR_PROCESS, ThreadList.Flink), csrp.ThreadList.Flink,
  929. FIELD_OFFSET(CSR_PROCESS, ThreadList.Blink), csrp.ThreadList.Blink,
  930. FIELD_OFFSET(CSR_PROCESS, NtSession), csrp.NtSession,
  931. FIELD_OFFSET(CSR_PROCESS, ExpectedVersion), csrp.ExpectedVersion);
  932. dprintf(
  933. "\t+%04lx ClientPort %08lx\n"
  934. "\t+%04lx ClientViewBase %08lx\n"
  935. "\t+%04lx ClientViewBounds %08lx\n"
  936. "\t+%04lx ClientId.UniqueProcess %08lx\n",
  937. FIELD_OFFSET(CSR_PROCESS, ClientPort), csrp.ClientPort,
  938. FIELD_OFFSET(CSR_PROCESS, ClientViewBase), csrp.ClientViewBase,
  939. FIELD_OFFSET(CSR_PROCESS, ClientViewBounds), csrp.ClientViewBounds,
  940. FIELD_OFFSET(CSR_PROCESS, ClientId.UniqueProcess), csrp.ClientId.UniqueProcess);
  941. dprintf(
  942. "\t+%04lx ProcessHandle %08lx\n"
  943. "\t+%04lx SequenceNumber %08lx\n"
  944. "\t+%04lx Flags %08lx\n"
  945. "\t+%04lx DebugFlags %08lx\n",
  946. FIELD_OFFSET(CSR_PROCESS, ProcessHandle), csrp.ProcessHandle,
  947. FIELD_OFFSET(CSR_PROCESS, SequenceNumber), csrp.SequenceNumber,
  948. FIELD_OFFSET(CSR_PROCESS, Flags), csrp.Flags,
  949. FIELD_OFFSET(CSR_PROCESS, DebugFlags), csrp.DebugFlags);
  950. dprintf(
  951. "\t+%04lx DebugUserInterface %08lx\n"
  952. "\t+%04lx ReferenceCount %08lx\n"
  953. "\t+%04lx ProcessGroupId %08lx\n"
  954. "\t+%04lx ProcessGroupSequence %08lx\n",
  955. FIELD_OFFSET(CSR_PROCESS, DebugUserInterface.UniqueProcess), csrp.DebugUserInterface.UniqueProcess,
  956. FIELD_OFFSET(CSR_PROCESS, ReferenceCount), csrp.ReferenceCount,
  957. FIELD_OFFSET(CSR_PROCESS, ProcessGroupId), csrp.ProcessGroupId,
  958. FIELD_OFFSET(CSR_PROCESS, ProcessGroupSequence), csrp.ProcessGroupSequence);
  959. dprintf(
  960. "\t+%04lx fVDM %08lx\n"
  961. "\t+%04lx ThreadCount %08lx\n"
  962. "\t+%04lx PriorityClass %08lx\n"
  963. "\t+%04lx ShutdownLevel %08lx\n"
  964. "\t+%04lx ShutdownFlags %08lx\n",
  965. FIELD_OFFSET(CSR_PROCESS, fVDM), csrp.fVDM,
  966. FIELD_OFFSET(CSR_PROCESS, ThreadCount), csrp.ThreadCount,
  967. FIELD_OFFSET(CSR_PROCESS, PriorityClass), csrp.PriorityClass,
  968. FIELD_OFFSET(CSR_PROCESS, ShutdownLevel), csrp.ShutdownLevel,
  969. FIELD_OFFSET(CSR_PROCESS, ShutdownFlags), csrp.ShutdownFlags);
  970. //
  971. // Now dump simple thread info for this processes' threads.
  972. //
  973. ListHead = &pcsrpT->ThreadList;
  974. b = ReadMemory( (ULONG_PTR)(&ListHead->Flink), &ListNext, sizeof(ListNext), NULL);
  975. if ( !b ) {
  976. dprintf( "NTSDEXTS: Unable to read ListNext\n" );
  977. goto Exit;
  978. }
  979. dprintf("Threads:\n");
  980. while (ListNext != ListHead) {
  981. pcsrt = CONTAINING_RECORD(ListNext, CSR_THREAD, Link);
  982. //
  983. // Make sure this pcsrt is somewhat real so we don't loop forever.
  984. //
  985. b = ReadMemory( (ULONG_PTR)(&pcsrt->ClientId.UniqueProcess), &dwProcessId, sizeof(dwProcessId), NULL);
  986. if ( !b ) {
  987. dprintf( "NTSDEXTS: Unable to read ListNext\n" );
  988. goto Exit;
  989. }
  990. if (dwProcessId != (DWORD_PTR)csrp.ClientId.UniqueProcess) {
  991. dprintf("Invalid thread. Probably invalid argument to this extension.\n");
  992. goto Exit;
  993. }
  994. HexToString((ULONG_PTR)pcsrt, ach);
  995. dt(Client, ach);
  996. b = ReadMemory( (ULONG_PTR)(&ListNext->Flink), &ListNext, sizeof(ListNext), NULL);
  997. if ( !b ) {
  998. dprintf( "NTSDEXTS: Unable to read ListNext\n" );
  999. goto Exit;
  1000. }
  1001. }
  1002. Exit:
  1003. EXIT_API();
  1004. }
  1005. VOID
  1006. DllsExtension(
  1007. PCSTR args,
  1008. PPEB ProcessPeb
  1009. );
  1010. DECLARE_API( gatom )
  1011. /*++
  1012. Routine Description:
  1013. This function is called as an NTSD extension to dump the global atom table
  1014. kept in kernel mode
  1015. Called as:
  1016. !gatom
  1017. Return Value:
  1018. None.
  1019. --*/
  1020. {
  1021. NTSTATUS Status;
  1022. ATOM_TABLE_INFORMATION TableInfo;
  1023. PATOM_TABLE_INFORMATION pTableInfo;
  1024. PATOM_BASIC_INFORMATION pBasicInfo;
  1025. ULONG RequiredLength, MaxLength, i;
  1026. INIT_API();
  1027. dprintf("\nGlobal atom table ");
  1028. Status = NtQueryInformationAtom( RTL_ATOM_INVALID_ATOM,
  1029. AtomTableInformation,
  1030. &TableInfo,
  1031. sizeof( TableInfo ),
  1032. &RequiredLength
  1033. );
  1034. if (Status != STATUS_INFO_LENGTH_MISMATCH) {
  1035. dprintf( " - cant get information - %x\n", Status );
  1036. goto Exit;
  1037. }
  1038. RequiredLength += 100 * sizeof( RTL_ATOM );
  1039. pTableInfo = LocalAlloc( 0, RequiredLength );
  1040. if (pTableInfo == NULL) {
  1041. dprintf( " - cant allocate memory for %u atoms\n", RequiredLength / sizeof( RTL_ATOM ) );
  1042. goto Exit;
  1043. }
  1044. Status = NtQueryInformationAtom( RTL_ATOM_INVALID_ATOM,
  1045. AtomTableInformation,
  1046. pTableInfo,
  1047. RequiredLength,
  1048. &RequiredLength
  1049. );
  1050. if (!NT_SUCCESS( Status )) {
  1051. dprintf( " - cant get information about %x atoms - %x\n", RequiredLength / sizeof( RTL_ATOM ), Status );
  1052. LocalFree( pTableInfo );
  1053. goto Exit;
  1054. }
  1055. MaxLength = sizeof( *pBasicInfo ) + RTL_ATOM_MAXIMUM_NAME_LENGTH;
  1056. pBasicInfo = LocalAlloc( 0, MaxLength );
  1057. if (!pBasicInfo) {
  1058. dprintf("LocalAlloc failed.\n");
  1059. goto Exit;
  1060. }
  1061. for (i=0; i<pTableInfo->NumberOfAtoms; i++) {
  1062. Status = NtQueryInformationAtom( pTableInfo->Atoms[ i ],
  1063. AtomBasicInformation,
  1064. pBasicInfo,
  1065. MaxLength,
  1066. &RequiredLength
  1067. );
  1068. if (!NT_SUCCESS( Status )) {
  1069. dprintf( "%hx *** query failed (%x)\n", Status );
  1070. }
  1071. else {
  1072. dprintf( "%hx(%2d) = %ls (%d)%s\n",
  1073. pTableInfo->Atoms[ i ],
  1074. pBasicInfo->UsageCount,
  1075. pBasicInfo->Name,
  1076. pBasicInfo->NameLength,
  1077. pBasicInfo->Flags & RTL_ATOM_PINNED ? " pinned" : ""
  1078. );
  1079. }
  1080. }
  1081. Exit:
  1082. EXIT_API();
  1083. }
  1084. #include "hleak.c"
  1085. #include "secexts.c"
  1086. /*++
  1087. Routine Description:
  1088. This function is called as an NTSD extension to mimic the !handle
  1089. kd command. This will walk through the debuggee's handle table
  1090. and duplicate the handle into the ntsd process, then call NtQueryobjectInfo
  1091. to find out what it is.
  1092. Called as:
  1093. !handle [handle [flags [Type]]]
  1094. If the handle is 0 or -1, all handles are scanned. If the handle is not
  1095. zero, that particular handle is examined. The flags are as follows
  1096. (corresponding to secexts.c):
  1097. 1 - Get type information (default)
  1098. 2 - Get basic information
  1099. 4 - Get name information
  1100. 8 - Get object specific info (where available)
  1101. If Type is specified, only object of that type are scanned. Type is a
  1102. standard NT type name, e.g. Event, Semaphore, etc. Case sensitive, of
  1103. course.
  1104. Examples:
  1105. !handle -- dumps the types of all the handles, and a summary table
  1106. !handle 0 0 -- dumps a summary table of all the open handles
  1107. !handle 0 f -- dumps everything we can find about a handle.
  1108. !handle 0 f Event
  1109. -- dumps everything we can find about open events
  1110. --*/
  1111. DECLARE_API( handle )
  1112. {
  1113. HANDLE hThere;
  1114. DWORD Type;
  1115. DWORD Mask;
  1116. DWORD HandleCount;
  1117. NTSTATUS Status;
  1118. DWORD Total;
  1119. DWORD TypeCounts[TYPE_MAX];
  1120. DWORD Handle;
  1121. DWORD Hits;
  1122. DWORD Matches;
  1123. DWORD ObjectType;
  1124. BOOL GetDirect;
  1125. ULONG SessionType;
  1126. ULONG SessionQual;
  1127. INIT_API();
  1128. Mask = GHI_TYPE ;
  1129. hThere = INVALID_HANDLE_VALUE;
  1130. Type = 0;
  1131. while (*args == ' ') {
  1132. args++;
  1133. }
  1134. if ( strcmp( args, "-?" ) == 0 )
  1135. {
  1136. help(Client, "handle" );
  1137. goto Exit;
  1138. }
  1139. hThere = (PVOID) GetExpression( args );
  1140. while (*args && (*args != ' ') ) {
  1141. args++;
  1142. }
  1143. while (*args == ' ') {
  1144. args++;
  1145. }
  1146. if (*args) {
  1147. Mask = (DWORD)GetExpression( args );
  1148. }
  1149. while (*args && (*args != ' ') ) {
  1150. args++;
  1151. }
  1152. while (*args == ' ') {
  1153. args++;
  1154. }
  1155. if (*args) {
  1156. Type = GetObjectTypeIndex( (LPSTR)args );
  1157. if (Type == (DWORD) -1 ) {
  1158. dprintf("Unknown type '%s'\n", args );
  1159. goto Exit;
  1160. }
  1161. }
  1162. //
  1163. // if they specified 0, they just want the summary. Make sure nothing
  1164. // sneaks out.
  1165. //
  1166. if ( Mask == 0 ) {
  1167. Mask = GHI_SILENT;
  1168. }
  1169. //
  1170. // If this is a dump debug session,
  1171. // check and see whether we can retrieve handle
  1172. // information through the engine interface.
  1173. //
  1174. if (g_ExtControl == NULL ||
  1175. g_ExtControl->lpVtbl->
  1176. GetDebuggeeType(g_ExtControl, &SessionType, &SessionQual) != S_OK) {
  1177. SessionType = DEBUG_CLASS_USER_WINDOWS;
  1178. SessionQual = DEBUG_USER_WINDOWS_PROCESS;
  1179. }
  1180. if (SessionType == DEBUG_CLASS_USER_WINDOWS &&
  1181. SessionQual != DEBUG_USER_WINDOWS_PROCESS) {
  1182. // This is a dump or remote session so we have to use
  1183. // the stored handle information accessible
  1184. // through the interface.
  1185. if (g_ExtData2 == NULL ||
  1186. g_ExtData2->lpVtbl->
  1187. ReadHandleData(g_ExtData2, 0, DEBUG_HANDLE_DATA_TYPE_HANDLE_COUNT,
  1188. &HandleCount, sizeof(HandleCount),
  1189. NULL) != S_OK) {
  1190. dprintf("Unable to read handle information\n");
  1191. goto Exit;
  1192. }
  1193. GetDirect = FALSE;
  1194. } else {
  1195. // This is a live session so we can make direct NT calls.
  1196. // More information is available this way so we use it
  1197. // whenever we can.
  1198. GetDirect = TRUE;
  1199. }
  1200. //
  1201. // hThere of 0 indicates all handles.
  1202. //
  1203. if ((hThere == 0) || (hThere == INVALID_HANDLE_VALUE)) {
  1204. if (GetDirect) {
  1205. Status = NtQueryInformationProcess( g_hCurrentProcess,
  1206. ProcessHandleCount,
  1207. &HandleCount,
  1208. sizeof( HandleCount ),
  1209. NULL );
  1210. if ( !NT_SUCCESS( Status ) ) {
  1211. goto Exit;
  1212. }
  1213. }
  1214. Hits = 0;
  1215. Handle = 0;
  1216. Matches = 0;
  1217. ZeroMemory( TypeCounts, sizeof(TypeCounts) );
  1218. while ( Hits < HandleCount ) {
  1219. if ( Type ) {
  1220. if (GetHandleInfo( GetDirect, g_hCurrentProcess,
  1221. (HANDLE) (DWORD_PTR) Handle,
  1222. GHI_TYPE | GHI_SILENT,
  1223. &ObjectType ) ) {
  1224. Hits++;
  1225. if ( ObjectType == Type ) {
  1226. GetHandleInfo( GetDirect, g_hCurrentProcess,
  1227. (HANDLE)(DWORD_PTR)Handle,
  1228. Mask,
  1229. &ObjectType );
  1230. Matches ++;
  1231. }
  1232. }
  1233. } else {
  1234. if (GetHandleInfo( GetDirect, g_hCurrentProcess,
  1235. (HANDLE)(DWORD_PTR)Handle,
  1236. GHI_TYPE | GHI_SILENT,
  1237. &ObjectType) ) {
  1238. Hits++;
  1239. TypeCounts[ ObjectType ] ++;
  1240. GetHandleInfo( GetDirect, g_hCurrentProcess,
  1241. (HANDLE)(DWORD_PTR)Handle,
  1242. Mask,
  1243. &ObjectType );
  1244. }
  1245. }
  1246. Handle += 4;
  1247. }
  1248. if ( Type == 0 ) {
  1249. dprintf( "%d Handles\n", Hits );
  1250. dprintf( "Type \tCount\n");
  1251. for (Type = 0; Type < TYPE_MAX ; Type++ ) {
  1252. if (TypeCounts[Type]) {
  1253. dprintf("%-15ws\t%d\n", pszTypeNames[Type], TypeCounts[Type]);
  1254. }
  1255. }
  1256. } else {
  1257. dprintf("%d handles of type %ws\n", Matches, pszTypeNames[Type] );
  1258. }
  1259. } else {
  1260. GetHandleInfo( GetDirect, g_hCurrentProcess, hThere, Mask, &Type );
  1261. }
  1262. Exit:
  1263. EXIT_API();
  1264. }
  1265. DECLARE_API( threadtoken )
  1266. {
  1267. HANDLE hToken ;
  1268. NTSTATUS Status ;
  1269. INIT_API();
  1270. Status = NtOpenThreadToken(
  1271. g_hCurrentThread,
  1272. TOKEN_READ,
  1273. TRUE,
  1274. &hToken );
  1275. if ( !NT_SUCCESS( Status ) )
  1276. {
  1277. if ( Status == STATUS_ACCESS_DENIED )
  1278. {
  1279. //
  1280. // Try to get around the ACL:
  1281. //
  1282. }
  1283. if ( Status != STATUS_NO_TOKEN )
  1284. {
  1285. dprintf( "Can't open token, %d\n", RtlNtStatusToDosError( Status ) );
  1286. goto Exit;
  1287. }
  1288. Status = NtOpenProcessToken(
  1289. g_hCurrentProcess,
  1290. TOKEN_READ,
  1291. &hToken );
  1292. if ( !NT_SUCCESS( Status ) )
  1293. {
  1294. dprintf( "Can't open any token, %d\n", RtlNtStatusToDosError( Status ) );
  1295. goto Exit;
  1296. }
  1297. dprintf( "\n***Thread is not impersonating, using process token***\n" );
  1298. }
  1299. TokenInfo( hToken, 0xFFF );
  1300. NtClose( hToken );
  1301. Exit:
  1302. EXIT_API();
  1303. }
  1304. #define PAGE_ALL (PAGE_READONLY|\
  1305. PAGE_READWRITE|\
  1306. PAGE_WRITECOPY|\
  1307. PAGE_EXECUTE|\
  1308. PAGE_EXECUTE_READ|\
  1309. PAGE_EXECUTE_READWRITE|\
  1310. PAGE_EXECUTE_WRITECOPY|\
  1311. PAGE_NOACCESS)
  1312. VOID
  1313. printflags(
  1314. DWORD Flags
  1315. )
  1316. {
  1317. switch (Flags & PAGE_ALL) {
  1318. case PAGE_READONLY:
  1319. dprintf("PAGE_READONLY");
  1320. break;
  1321. case PAGE_READWRITE:
  1322. dprintf("PAGE_READWRITE");
  1323. break;
  1324. case PAGE_WRITECOPY:
  1325. dprintf("PAGE_WRITECOPY");
  1326. break;
  1327. case PAGE_EXECUTE:
  1328. dprintf("PAGE_EXECUTE");
  1329. break;
  1330. case PAGE_EXECUTE_READ:
  1331. dprintf("PAGE_EXECUTE_READ");
  1332. break;
  1333. case PAGE_EXECUTE_READWRITE:
  1334. dprintf("PAGE_EXECUTE_READWRITE");
  1335. break;
  1336. case PAGE_EXECUTE_WRITECOPY:
  1337. dprintf("PAGE_EXECUTE_WRITECOPY");
  1338. break;
  1339. case PAGE_NOACCESS:
  1340. if ((Flags & ~PAGE_NOACCESS) == 0) {
  1341. dprintf("PAGE_NOACCESS");
  1342. break;
  1343. } // else fall through
  1344. default:
  1345. dprintf("*** Invalid page protection ***\n");
  1346. return;
  1347. break;
  1348. }
  1349. if (Flags & PAGE_NOCACHE) {
  1350. dprintf(" + PAGE_NOCACHE");
  1351. }
  1352. if (Flags & PAGE_GUARD) {
  1353. dprintf(" + PAGE_GUARD");
  1354. }
  1355. dprintf("\n");
  1356. }
  1357. DECLARE_API( vprot )
  1358. /*++
  1359. Routine Description:
  1360. This debugger extension dumps the virtual memory info for the
  1361. address specified.
  1362. Arguments:
  1363. Return Value:
  1364. --*/
  1365. {
  1366. PVOID Address;
  1367. MEMORY_BASIC_INFORMATION mbi;
  1368. INIT_API();
  1369. while (*args == ' ') {
  1370. args++;
  1371. }
  1372. Address = (PVOID)GetExpression( args );
  1373. if (!VirtualQueryEx( g_hCurrentProcess, Address, &mbi, sizeof(mbi))) {
  1374. dprintf("vprot: VirtualQueryEx failed, error = %d\n", GetLastError());
  1375. goto Exit;
  1376. }
  1377. dprintf("BaseAddress: %p\n", mbi.BaseAddress);
  1378. dprintf("AllocationBase: %08x\n", mbi.AllocationBase);
  1379. dprintf("AllocationProtect: %08x ", mbi.AllocationProtect);
  1380. printflags(mbi.AllocationProtect);
  1381. dprintf("RegionSize: %08x\n", mbi.RegionSize);
  1382. dprintf("State: %08x ", mbi.State);
  1383. switch (mbi.State) {
  1384. case MEM_COMMIT:
  1385. dprintf("MEM_COMMIT\n");
  1386. break;
  1387. case MEM_FREE:
  1388. dprintf("MEM_FREE\n");
  1389. break;
  1390. case MEM_RESERVE:
  1391. dprintf("MEM_RESERVE\n");
  1392. break;
  1393. default:
  1394. dprintf("*** Invalid page state ***\n");
  1395. break;
  1396. }
  1397. dprintf("Protect: %08x ", mbi.Protect);
  1398. printflags(mbi.Protect);
  1399. dprintf("Type: %08x ", mbi.Type);
  1400. switch(mbi.Type) {
  1401. case MEM_IMAGE:
  1402. dprintf("MEM_IMAGE\n");
  1403. break;
  1404. case MEM_MAPPED:
  1405. dprintf("MEM_MAPPED\n");
  1406. break;
  1407. case MEM_PRIVATE:
  1408. dprintf("MEM_PRIVATE\n");
  1409. break;
  1410. default:
  1411. dprintf("*** Invalid page type ***\n");
  1412. break;
  1413. }
  1414. Exit:
  1415. EXIT_API();
  1416. }
  1417. #include "leak.c"
  1418. #include "regexts.c"
  1419. /*++
  1420. Routine Description:
  1421. This function is called as an NTSD extension to dump registry information
  1422. Called as:
  1423. !dreg -[d|w] <keyPath>[![<valueName> | *]]
  1424. Arguments:
  1425. hCurrentProcess - Supplies a handle to the current process (at the
  1426. time the extension was called).
  1427. hCurrentThread - Supplies a handle to the current thread (at the
  1428. time the extension was called).
  1429. CurrentPc - Supplies the current pc at the time the extension is
  1430. called.
  1431. lpExtensionApis - Supplies the address of the functions callable
  1432. by this extension.
  1433. args - Supplies the pattern and expression for this
  1434. command.
  1435. Return Value:
  1436. None.
  1437. --*/
  1438. DECLARE_API( dreg )
  1439. {
  1440. DWORD opts = 1;
  1441. INIT_API();
  1442. // Skip past leading spaces
  1443. while (*args == ' ')
  1444. {
  1445. args++;
  1446. }
  1447. if (*args == '-')
  1448. {
  1449. args++;
  1450. switch (*args)
  1451. {
  1452. case 'd':
  1453. opts = 4;
  1454. break;
  1455. case 'w':
  1456. opts = 2;
  1457. break;
  1458. default:
  1459. opts = 1;
  1460. break;
  1461. }
  1462. if (*args)
  1463. {
  1464. // expect a space between options
  1465. args++;
  1466. // Skip past leading spaces
  1467. while (*args == ' ')
  1468. {
  1469. args++;
  1470. }
  1471. }
  1472. }
  1473. Idreg(opts, (LPSTR)args);
  1474. EXIT_API();
  1475. }
  1476. /*++
  1477. Routine Description:
  1478. This function is called as an NTSD extension to dump handle tracing information
  1479. Called as:
  1480. !htrace [handle]
  1481. Arguments:
  1482. args - Supplies the pattern and expression for this
  1483. command.
  1484. Return Value:
  1485. None.
  1486. --*/
  1487. DECLARE_API( htrace )
  1488. {
  1489. HANDLE Handle;
  1490. PPROCESS_HANDLE_TRACING_QUERY Info;
  1491. ULONG_PTR Displacement;
  1492. NTSTATUS Status;
  1493. ULONG CurrentBufferSize;
  1494. ULONG CrtStackTrace;
  1495. ULONG EntriesDisplayed;
  1496. ULONG CapturedAddressIndex;
  1497. PVOID *CrtStack;
  1498. PVOID CapturedAddress;
  1499. SYSTEM_BASIC_INFORMATION SysBasicInfo;
  1500. CHAR Symbol[ 1024 ];
  1501. INIT_API();
  1502. Info = NULL;
  1503. CrtStackTrace = 0;
  1504. EntriesDisplayed = 0;
  1505. //
  1506. // Did the user ask for some help?
  1507. //
  1508. if (strcmp (args, "-?") == 0 ||
  1509. strcmp (args, "?") == 0 ||
  1510. strcmp (args, "-h") == 0) {
  1511. dprintf ("!htrace [handle]\n");
  1512. goto DoneAll;
  1513. }
  1514. //
  1515. // Get the handle from the command line
  1516. //
  1517. Handle = (HANDLE)GetExpression (args);
  1518. //
  1519. // Get the stack traces using NtQueryInformationProcess
  1520. //
  1521. CurrentBufferSize = sizeof (PROCESS_HANDLE_TRACING_QUERY);
  1522. while (TRUE) {
  1523. //
  1524. // Allocate a new buffer
  1525. //
  1526. Info = (PPROCESS_HANDLE_TRACING_QUERY)malloc (CurrentBufferSize);
  1527. if (Info == NULL) {
  1528. dprintf ("ERROR: Cannot allocate buffer with size 0x%p\n",
  1529. CurrentBufferSize);
  1530. goto DoneAll;
  1531. }
  1532. ZeroMemory( Info,
  1533. CurrentBufferSize );
  1534. Status = NtQueryInformationProcess (g_hCurrentProcess,
  1535. ProcessHandleTracing,
  1536. Info,
  1537. CurrentBufferSize,
  1538. NULL );
  1539. if( NT_SUCCESS (Status) ) {
  1540. //
  1541. // We have all the information ready
  1542. //
  1543. break;
  1544. }
  1545. CurrentBufferSize = sizeof (PROCESS_HANDLE_TRACING_QUERY) + Info->TotalTraces * sizeof (Info->HandleTrace[ 0 ]);
  1546. free (Info);
  1547. Info = NULL;
  1548. if( CheckControlC() ) {
  1549. goto DoneAll;
  1550. }
  1551. if (Status != STATUS_INFO_LENGTH_MISMATCH) {
  1552. //
  1553. // No reason to try querying again
  1554. //
  1555. dprintf ("Query process information failed, status 0x%X\n",
  1556. Status);
  1557. goto DoneAll;
  1558. }
  1559. //
  1560. // Try allocating another buffer with the new size
  1561. //
  1562. }
  1563. //
  1564. // If we have 0 stack traces there is nothing we can dump
  1565. //
  1566. if (Info->TotalTraces == 0) {
  1567. dprintf( "No stack traces available.\n" );
  1568. goto DoneAll;
  1569. }
  1570. //
  1571. // Find out the highest user address because
  1572. // we will skip kernel mode addresses from the stack traces.
  1573. //
  1574. Status = NtQuerySystemInformation (SystemBasicInformation,
  1575. &SysBasicInfo,
  1576. sizeof (SysBasicInfo),
  1577. NULL);
  1578. if (!NT_SUCCESS (Status)) {
  1579. dprintf ("Query system basic information failed, status 0x%X\n",
  1580. Status);
  1581. goto DoneAll;
  1582. }
  1583. //
  1584. // Dump all the stack traces.
  1585. //
  1586. for (CrtStackTrace = 0; CrtStackTrace < Info->TotalTraces; CrtStackTrace += 1) {
  1587. if( CheckControlC() ) {
  1588. CrtStackTrace += 1;
  1589. goto DoneDumping;
  1590. }
  1591. if (Handle == 0 || Handle == Info->HandleTrace[ CrtStackTrace ].Handle) {
  1592. EntriesDisplayed += 1;
  1593. dprintf ("--------------------------------------\n"
  1594. "Handle = 0x%p - ",
  1595. Info->HandleTrace[ CrtStackTrace ].Handle);
  1596. switch( Info->HandleTrace[ CrtStackTrace ].Type ) {
  1597. case HANDLE_TRACE_DB_OPEN:
  1598. dprintf( "OPEN:\n" );
  1599. break;
  1600. case HANDLE_TRACE_DB_CLOSE:
  1601. dprintf( "CLOSE:\n" );
  1602. break;
  1603. case HANDLE_TRACE_DB_BADREF:
  1604. dprintf( "*** BAD REFERENCE ***:\n" );
  1605. break;
  1606. default:
  1607. dprintf( "Invalid operation type: %u\n",
  1608. Info->HandleTrace[ CrtStackTrace ].Type );
  1609. goto DoneDumping;
  1610. }
  1611. for (CapturedAddressIndex = 0, CrtStack = &Info->HandleTrace[ CrtStackTrace ].Stacks[ 0 ];
  1612. CapturedAddressIndex < (sizeof(Info->HandleTrace[ CrtStackTrace ].Stacks) /
  1613. sizeof(Info->HandleTrace[ CrtStackTrace ].Stacks[0]));
  1614. CapturedAddressIndex += 1, CrtStack += 1) {
  1615. if( CheckControlC() ) {
  1616. CrtStackTrace += 1;
  1617. goto DoneDumping;
  1618. }
  1619. CapturedAddress = *CrtStack;
  1620. if (CapturedAddress == NULL) {
  1621. //
  1622. // Done with dumping this stack trace
  1623. //
  1624. break;
  1625. }
  1626. if ((ULONG_PTR)CapturedAddress > SysBasicInfo.MaximumUserModeAddress) {
  1627. //
  1628. // Skip kernel-mode addresses
  1629. //
  1630. continue;
  1631. }
  1632. GetSymbol (CapturedAddress,
  1633. Symbol,
  1634. &Displacement);
  1635. dprintf ("0x%p: %s+0x%p\n",
  1636. CapturedAddress,
  1637. Symbol,
  1638. Displacement );
  1639. }
  1640. }
  1641. }
  1642. DoneDumping:
  1643. dprintf ("\n--------------------------------------\n"
  1644. "Parsed 0x%X stack traces.\n"
  1645. "Dumped 0x%X stack traces.\n",
  1646. CrtStackTrace,
  1647. EntriesDisplayed);
  1648. DoneAll:
  1649. if (Info != NULL) {
  1650. free (Info);
  1651. }
  1652. EXIT_API();
  1653. }