Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1018 lines
27 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. GenTable.c
  5. Abstract:
  6. WinDbg Extension Api for walking RtlGenericTable structures
  7. Contains no direct ! entry points, but has makes it possible to
  8. enumerate through generic tables. The standard Rtl functions
  9. cannot be used by debugger extensions because they dereference
  10. pointers to data on the machine being debugged. The function
  11. KdEnumerateGenericTableWithoutSplaying implemented in this
  12. module can be used within kernel debugger extensions. The
  13. enumeration function RtlEnumerateGenericTable has no parallel
  14. in this module, since splaying the tree is an intrusive operation,
  15. and debuggers should try not to be intrusive.
  16. Author:
  17. Keith Kaplan [KeithKa] 09-May-96
  18. Environment:
  19. User Mode.
  20. Revision History:
  21. --*/
  22. #include "precomp.h"
  23. #pragma hdrstop
  24. ULONG64
  25. KdParent (
  26. IN ULONG64 pLinks
  27. )
  28. /*++
  29. Routine Description:
  30. Analogous to RtlParent macro, but works in the kernel debugger.
  31. The description of RtlParent follows:
  32. The macro function Parent takes as input a pointer to a splay link in a
  33. tree and returns a pointer to the splay link of the parent of the input
  34. node. If the input node is the root of the tree the return value is
  35. equal to the input value.
  36. Arguments:
  37. Links - Pointer to a splay link in a tree.
  38. Return Value:
  39. PRTL_SPLAY_LINKS - Pointer to the splay link of the parent of the input
  40. node. If the input node is the root of the tree the
  41. return value is equal to the input value.
  42. --*/
  43. {
  44. ULONG64 Parent;
  45. if ( GetFieldValue( pLinks,
  46. "RTL_SPLAY_LINKS",
  47. "Parent",
  48. Parent) ) {
  49. dprintf( "%08p: Unable to read pLinks\n", pLinks );
  50. return 0;
  51. }
  52. return Parent;
  53. }
  54. ULONG64
  55. KdLeftChild (
  56. IN ULONG64 pLinks
  57. )
  58. /*++
  59. Routine Description:
  60. Analogous to RtlLeftChild macro, but works in the kernel debugger.
  61. The description of RtlLeftChild follows:
  62. The macro function LeftChild takes as input a pointer to a splay link in
  63. a tree and returns a pointer to the splay link of the left child of the
  64. input node. If the left child does not exist, the return value is NULL.
  65. Arguments:
  66. Links - Pointer to a splay link in a tree.
  67. Return Value:
  68. ULONG64 - Pointer to the splay link of the left child of the input node.
  69. If the left child does not exist, the return value is NULL.
  70. --*/
  71. {
  72. ULONG64 LeftChild;
  73. if ( GetFieldValue( pLinks,
  74. "RTL_SPLAY_LINKS",
  75. "LeftChild",
  76. LeftChild) ) {
  77. dprintf( "%08p: Unable to read pLinks\n", pLinks );
  78. return 0;
  79. }
  80. return LeftChild;
  81. }
  82. ULONG64
  83. KdRightChild (
  84. IN ULONG64 pLinks
  85. )
  86. /*++
  87. Routine Description:
  88. Analogous to RtlRightChild macro, but works in the kernel debugger.
  89. The description of RtlRightChild follows:
  90. The macro function RightChild takes as input a pointer to a splay link
  91. in a tree and returns a pointer to the splay link of the right child of
  92. the input node. If the right child does not exist, the return value is
  93. NULL.
  94. Arguments:
  95. Links - Pointer to a splay link in a tree.
  96. Return Value:
  97. PRTL_SPLAY_LINKS - Pointer to the splay link of the right child of the input node.
  98. If the right child does not exist, the return value is NULL.
  99. --*/
  100. {
  101. ULONG64 RightChild;
  102. if ( GetFieldValue( pLinks,
  103. "RTL_SPLAY_LINKS",
  104. "RightChild",
  105. RightChild) ) {
  106. dprintf( "%08p: Unable to read pLinks\n", pLinks );
  107. return 0;
  108. }
  109. return RightChild;
  110. }
  111. BOOLEAN
  112. KdIsLeftChild (
  113. IN ULONG64 Links
  114. )
  115. /*++
  116. Routine Description:
  117. Analogous to RtlIsLeftChild macro, but works in the kernel debugger.
  118. The description of RtlIsLeftChild follows:
  119. The macro function IsLeftChild takes as input a pointer to a splay link
  120. in a tree and returns TRUE if the input node is the left child of its
  121. parent, otherwise it returns FALSE.
  122. Arguments:
  123. Links - Pointer to a splay link in a tree.
  124. Return Value:
  125. BOOLEAN - TRUE if the input node is the left child of its parent,
  126. otherwise it returns FALSE.
  127. --*/
  128. {
  129. return (KdLeftChild(KdParent(Links)) == (Links));
  130. }
  131. BOOLEAN
  132. KdIsRightChild (
  133. IN ULONG64 Links
  134. )
  135. /*++
  136. Routine Description:
  137. Analogous to RtlIsRightChild macro, but works in the kernel debugger.
  138. The description of RtlIsRightChild follows:
  139. The macro function IsRightChild takes as input a pointer to a splay link
  140. in a tree and returns TRUE if the input node is the right child of its
  141. parent, otherwise it returns FALSE.
  142. Arguments:
  143. Links - Pointer to a splay link in a tree.
  144. Return Value:
  145. BOOLEAN - TRUE if the input node is the right child of its parent,
  146. otherwise it returns FALSE.
  147. --*/
  148. {
  149. return (KdRightChild(KdParent(Links)) == (Links));
  150. }
  151. BOOLEAN
  152. KdIsGenericTableEmpty (
  153. IN ULONG64 Table
  154. )
  155. /*++
  156. Routine Description:
  157. Analogous to RtlIsGenericTableEmpty, but works in the kernel debugger.
  158. The description of RtlIsGenericTableEmpty follows:
  159. The function IsGenericTableEmpty will return to the caller TRUE if
  160. the input table is empty (i.e., does not contain any elements) and
  161. FALSE otherwise.
  162. Arguments:
  163. Table - Supplies a pointer to the Generic Table.
  164. Return Value:
  165. BOOLEAN - if enabled the tree is empty.
  166. --*/
  167. {
  168. ULONG64 TableRoot;
  169. if (GetFieldValue(Table, "RTL_GENERIC_TABLE", "TableRoot", TableRoot)) {
  170. return TRUE;
  171. }
  172. //
  173. // Table is empty if the root pointer is null.
  174. //
  175. return ((TableRoot)?(FALSE):(TRUE));
  176. }
  177. ULONG64
  178. KdRealSuccessor (
  179. IN ULONG64 Links
  180. )
  181. /*++
  182. Routine Description:
  183. Analogous to RtlRealSuccessor, but works in the kernel debugger.
  184. The description of RtlRealSuccessor follows:
  185. The RealSuccessor function takes as input a pointer to a splay link
  186. in a tree and returns a pointer to the successor of the input node within
  187. the entire tree. If there is not a successor, the return value is NULL.
  188. Arguments:
  189. Links - Supplies a pointer to a splay link in a tree.
  190. Return Value:
  191. PRTL_SPLAY_LINKS - returns a pointer to the successor in the entire tree
  192. --*/
  193. {
  194. ULONG64 Ptr;
  195. /*
  196. first check to see if there is a right subtree to the input link
  197. if there is then the real successor is the left most node in
  198. the right subtree. That is find and return P in the following diagram
  199. Links
  200. \
  201. .
  202. .
  203. .
  204. /
  205. P
  206. \
  207. */
  208. if ((Ptr = KdRightChild(Links)) != 0) {
  209. while (KdLeftChild(Ptr) != 0) {
  210. Ptr = KdLeftChild(Ptr);
  211. }
  212. return Ptr;
  213. }
  214. /*
  215. we do not have a right child so check to see if have a parent and if
  216. so find the first ancestor that we are a left decendent of. That
  217. is find and return P in the following diagram
  218. P
  219. /
  220. .
  221. .
  222. .
  223. Links
  224. */
  225. Ptr = Links;
  226. while (KdIsRightChild(Ptr)) {
  227. Ptr = KdParent(Ptr);
  228. }
  229. if (KdIsLeftChild(Ptr)) {
  230. return KdParent(Ptr);
  231. }
  232. //
  233. // otherwise we are do not have a real successor so we simply return
  234. // NULL
  235. //
  236. return 0;
  237. }
  238. ULONG64
  239. KdEnumerateGenericTableWithoutSplaying (
  240. IN ULONG64 pTable,
  241. IN PULONG64 RestartKey,
  242. IN BOOLEAN Avl
  243. )
  244. /*++
  245. Routine Description:
  246. Analogous to RtlEnumerateGenericTableWithoutSplaying, but works in the
  247. kernel debugger. The description of RtlEnumerateGenericTableWithoutSplaying
  248. follows:
  249. The function EnumerateGenericTableWithoutSplaying will return to the
  250. caller one-by-one the elements of of a table. The return value is a
  251. pointer to the user defined structure associated with the element.
  252. The input parameter RestartKey indicates if the enumeration should
  253. start from the beginning or should return the next element. If the
  254. are no more new elements to return the return value is NULL. As an
  255. example of its use, to enumerate all of the elements in a table the
  256. user would write:
  257. *RestartKey = NULL;
  258. for (ptr = EnumerateGenericTableWithoutSplaying(Table, &RestartKey);
  259. ptr != NULL;
  260. ptr = EnumerateGenericTableWithoutSplaying(Table, &RestartKey)) {
  261. :
  262. }
  263. Arguments:
  264. Table - Pointer to the generic table to enumerate.
  265. RestartKey - Pointer that indicates if we should restart or return the next
  266. element. If the contents of RestartKey is NULL, the search
  267. will be started from the beginning.
  268. Return Value:
  269. PVOID - Pointer to the user data.
  270. --*/
  271. {
  272. ULONG Result;
  273. ULONG64 TableRoot;
  274. RTL_GENERIC_TABLE Table;
  275. if ( GetFieldValue(pTable,
  276. "RTL_GENERIC_TABLE",
  277. "TableRoot",
  278. TableRoot) ) {
  279. dprintf( "%08p: Unable to read pTable\n", pTable );
  280. return 0;
  281. }
  282. if (!TableRoot) {
  283. //
  284. // Nothing to do if the table is empty.
  285. //
  286. return 0;
  287. } else {
  288. //
  289. // Will be used as the "iteration" through the tree.
  290. //
  291. ULONG64 NodeToReturn;
  292. //
  293. // If the restart flag is true then go to the least element
  294. // in the tree.
  295. //
  296. if (*RestartKey == 0) {
  297. //
  298. // We just loop until we find the leftmost child of the root.
  299. //
  300. for (
  301. NodeToReturn = (Avl)? KdRightChild(TableRoot) : TableRoot;
  302. KdLeftChild(NodeToReturn);
  303. NodeToReturn = KdLeftChild(NodeToReturn)
  304. ) {
  305. ;
  306. }
  307. *RestartKey = NodeToReturn;
  308. } else {
  309. //
  310. // The caller has passed in the previous entry found
  311. // in the table to enable us to continue the search. We call
  312. // KdRealSuccessor to step to the next element in the tree.
  313. //
  314. NodeToReturn = KdRealSuccessor(*RestartKey);
  315. if (NodeToReturn) {
  316. *RestartKey = NodeToReturn;
  317. }
  318. }
  319. //
  320. // If there actually is a next element in the enumeration
  321. // then the pointer to return is right after the list links.
  322. //
  323. if (NodeToReturn) {
  324. if (Avl) {
  325. return NodeToReturn + GetTypeSize("RTL_BALANCED_LINKS");
  326. } else {
  327. return NodeToReturn + GetTypeSize("RTL_SPLAY_LINKS") + GetTypeSize("LIST_ENTRY");
  328. }
  329. }
  330. return 0;
  331. }
  332. }
  333. //+---------------------------------------------------------------------------
  334. //
  335. // Function: gentable
  336. //
  337. // Synopsis: dump a generic splay table only showing ptrs
  338. //
  339. // Arguments:
  340. //
  341. // Returns:
  342. //
  343. // History: 5-14-1999 benl Created
  344. //
  345. // Notes:
  346. //
  347. //----------------------------------------------------------------------------
  348. DECLARE_API( gentable )
  349. {
  350. ULONG64 RestartKey;
  351. ULONG64 Ptr;
  352. ULONG64 Table;
  353. ULONG RowOfData[4];
  354. ULONG64 Address;
  355. ULONG Result;
  356. ULONG64 Flags;
  357. BOOLEAN Avl;
  358. Flags = 0;
  359. Table = 0;
  360. if (GetExpressionEx(args, &Table, &args)) {
  361. Flags = GetExpression(args);
  362. }
  363. if (Flags) {
  364. Avl = TRUE;
  365. } else {
  366. Avl = FALSE;
  367. }
  368. RestartKey = 0;
  369. dprintf( "node: parent left right\n" );
  370. // 0x12345678: 0x12345678 0x12345678 0x12345678
  371. for (Ptr = KdEnumerateGenericTableWithoutSplaying(Table, &RestartKey, Avl);
  372. Ptr != 0;
  373. Ptr = KdEnumerateGenericTableWithoutSplaying(Table, &RestartKey, Avl)) {
  374. if (Ptr) {
  375. if (Avl) {
  376. Address = Ptr - GetTypeSize("RTL_BALANCED_LINKS");
  377. } else {
  378. Address = Ptr - GetTypeSize("RTL_SPLAY_LINKS") - GetTypeSize( "LIST_ENTRY" );
  379. }
  380. if ( !ReadMemory( Address, RowOfData, sizeof( RowOfData ), &Result) ) {
  381. dprintf( "%08p: Unable to read link\n", Address );
  382. } else {
  383. dprintf( "0x%p: 0x%08p 0x%08p 0x%08p\n",
  384. Address, KdParent(Address), KdLeftChild(Address), KdRightChild(Address));
  385. }
  386. if ( !ReadMemory( Ptr, RowOfData, sizeof( RowOfData ), &Result) ) {
  387. dprintf( "%08p: Unable to read userdata\n", Ptr );
  388. } else {
  389. Address = Ptr;
  390. dprintf( "\t0x%p: 0x%08p 0x%08p 0x%08p\n",
  391. Address, KdParent(Address), KdLeftChild(Address), KdRightChild(Address));
  392. }
  393. }
  394. if (CheckControlC() ) {
  395. return E_INVALIDARG;
  396. }
  397. }
  398. return S_OK;
  399. } // DECLARE_API
  400. DECLARE_API( devinst )
  401. {
  402. ULONG64 table;
  403. ULONG64 restartKey;
  404. ULONG64 ptr;
  405. ULONG64 address;
  406. CHAR deviceReferenceType[] = "nt!_DEVICE_REFERENCE";
  407. CHAR unicodeStringType[] = "nt!_UNICODE_STRING";
  408. ULONG64 deviceObject;
  409. UNICODE_STRING64 u;
  410. ULONG64 instance;
  411. table = GetExpression("nt!PpDeviceReferenceTable");
  412. if (table) {
  413. dprintf("DeviceObject: InstancePath\n");
  414. restartKey = 0;
  415. while ((ptr = KdEnumerateGenericTableWithoutSplaying(table, &restartKey, TRUE))) {
  416. address = ptr;
  417. if (GetFieldValue(address, deviceReferenceType, "DeviceObject", deviceObject)) {
  418. dprintf("Failed to get the value of DeviceObject from %s(0x%p)\n", deviceReferenceType, address);
  419. break;
  420. }
  421. if (GetFieldValue(address, deviceReferenceType, "DeviceInstance", instance)) {
  422. dprintf("Failed to get the value of DeviceInstance from %s(0x%p)\n", deviceReferenceType, address);
  423. break;
  424. }
  425. if (GetFieldValue(instance, unicodeStringType, "Length", u.Length)) {
  426. dprintf("Failed to get the value of Length from %s(0x%p)\n", unicodeStringType, instance);
  427. break;
  428. }
  429. if (GetFieldValue(instance, unicodeStringType, "MaximumLength", u.MaximumLength)) {
  430. dprintf("Failed to get the value of Length from %s(0x%p)\n", unicodeStringType, instance);
  431. break;
  432. }
  433. if (GetFieldValue(instance, unicodeStringType, "Buffer", u.Buffer)) {
  434. dprintf("Failed to get the value of Length from %s(0x%p)\n", unicodeStringType, instance);
  435. break;
  436. }
  437. dprintf("!devstack %p: ", deviceObject); DumpUnicode64(u); dprintf("\n");
  438. }
  439. } else {
  440. dprintf("Could not read address of nt!PpDeviceReferenceTable\n");
  441. }
  442. return S_OK;
  443. }
  444. DECLARE_API( blockeddrv )
  445. {
  446. ULONG64 table;
  447. ULONG64 restartKey;
  448. ULONG64 ptr;
  449. ULONG64 address;
  450. CHAR cacheEntryType[] = "nt!_DDBCACHE_ENTRY";
  451. CHAR unicodeStringType[] = "nt!_UNICODE_STRING";
  452. UNICODE_STRING64 u;
  453. ULONG64 unicodeString;
  454. ULONG64 name;
  455. NTSTATUS status;
  456. GUID guid;
  457. ULONG Offset;
  458. table = GetExpression("nt!PiDDBCacheTable");
  459. if (table) {
  460. dprintf("Driver:\tStatus\tGUID\n");
  461. restartKey = 0;
  462. while ((ptr = KdEnumerateGenericTableWithoutSplaying(table, &restartKey, TRUE))) {
  463. address = ptr;
  464. if (GetFieldOffset(cacheEntryType, "Name", &Offset)) {
  465. dprintf("Failed to get Name offset off %s\n", cacheEntryType);
  466. break;
  467. }
  468. name = address + Offset;
  469. if (GetFieldValue(name, unicodeStringType, "Length", u.Length)) {
  470. dprintf("Failed to get the value of Length from %s(0x%p)\n", unicodeStringType, name);
  471. break;
  472. }
  473. if (GetFieldValue(name, unicodeStringType, "MaximumLength", u.MaximumLength)) {
  474. dprintf("Failed to get the value of Length from %s(0x%p)\n", unicodeStringType, name);
  475. break;
  476. }
  477. if (GetFieldValue(name, unicodeStringType, "Buffer", u.Buffer)) {
  478. dprintf("Failed to get the value of Length from %s(0x%p)\n", unicodeStringType, name);
  479. break;
  480. }
  481. if (GetFieldValue(address, cacheEntryType, "Status", status)) {
  482. dprintf("Failed to get the value of Name from %s(0x%p)\n", cacheEntryType, address);
  483. break;
  484. }
  485. if (GetFieldValue(address, cacheEntryType, "Guid", guid)) {
  486. dprintf("Failed to get the value of Name from %s(0x%p)\n", cacheEntryType, address);
  487. break;
  488. }
  489. DumpUnicode64(u);
  490. dprintf("\t%x: ", status);
  491. dprintf("\t{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\n",
  492. guid.Data1,
  493. guid.Data2,
  494. guid.Data3,
  495. guid.Data4[0],
  496. guid.Data4[1],
  497. guid.Data4[2],
  498. guid.Data4[3],
  499. guid.Data4[4],
  500. guid.Data4[5],
  501. guid.Data4[6],
  502. guid.Data4[7] );
  503. }
  504. } else {
  505. dprintf("Could not read address of nt!PiDDBCacheTable\n");
  506. }
  507. return S_OK;
  508. }
  509. //
  510. // returns TRUE to finish dumping or false to continue
  511. //
  512. typedef struct _AHCacheDumpContext {
  513. ULONG64 ListEnd; // end of the list ptr
  514. ULONG Count; // entry count
  515. ULONG64 Flags; // flags
  516. } AHCDUMPCTX, *PAHCDUMPCTX;
  517. ULONG
  518. WDBGAPI
  519. AHCacheDumpFieldCallback(
  520. struct _FIELD_INFO *pField,
  521. PVOID UserContext
  522. )
  523. {
  524. ULONG64 address = pField->address;
  525. ULONG Offset;
  526. UNICODE_STRING64 u;
  527. ULONG64 name, FileSize, FileTime, listent;
  528. ULONG64 flink, blink;
  529. PAHCDUMPCTX pctx = (PAHCDUMPCTX)UserContext;
  530. CHAR cacheEntryType[] = "nt!tagSHIMCACHEENTRY";
  531. CHAR unicodeStringType[] = "nt!_UNICODE_STRING";
  532. CHAR listEntryType[] = "LIST_ENTRY";
  533. BOOL bReturn = TRUE;
  534. if (CheckControlC()) {
  535. dprintf("User terminated with <control>C\n");
  536. return TRUE;
  537. }
  538. // check if we have arrived at the list head
  539. if (address == pctx->ListEnd) {
  540. return TRUE;
  541. }
  542. if (GetFieldOffset(cacheEntryType, "FileName", &Offset)) {
  543. dprintf("Failed to get field FileName offset off %s\n", cacheEntryType);
  544. goto cleanup;
  545. }
  546. name = address + Offset;
  547. if (GetFieldValue(name, unicodeStringType, "Length", u.Length)) {
  548. dprintf("Failed to get the value of Length from %s(0x%p)\n", unicodeStringType, name);
  549. goto cleanup;
  550. }
  551. if (GetFieldValue(name, unicodeStringType, "MaximumLength", u.MaximumLength)) {
  552. dprintf("Failed to get the value of MaximumLength from %s(0x%p)\n", unicodeStringType, name);
  553. goto cleanup;
  554. }
  555. if (GetFieldValue(name, unicodeStringType, "Buffer", u.Buffer)) {
  556. dprintf("Failed to get the value of Length from %s(0x%p)\n", unicodeStringType, name);
  557. goto cleanup;
  558. }
  559. if (GetFieldValue(address, cacheEntryType, "FileSize", FileSize)) {
  560. dprintf("Failed to get the value of FileSize from %s(0x%p)\n", cacheEntryType, address);
  561. goto cleanup;
  562. }
  563. if (GetFieldValue(address, cacheEntryType, "FileTime", FileTime)) {
  564. dprintf("Failed to get the value of FileTime from %s(0x%p)\n", cacheEntryType, address);
  565. goto cleanup;
  566. }
  567. // now read the list ptrs
  568. if (GetFieldOffset(cacheEntryType, "ListEntry", &Offset)) {
  569. dprintf("Failed to get field ListEntry offset off %s\n", cacheEntryType);
  570. goto cleanup;
  571. }
  572. listent = address + Offset;
  573. if (GetFieldValue(listent, "LIST_ENTRY", "Flink", flink)) {
  574. dprintf("Failed to get the value of Flink from %s(0x%p)\n", listEntryType, listent);
  575. goto cleanup;
  576. }
  577. if (GetFieldValue(listent, "LIST_ENTRY", "Blink", blink)) {
  578. dprintf("Failed to get the value of Blink from %s(0x%p)\n", listEntryType, listent);
  579. goto cleanup;
  580. }
  581. // dump the values involved
  582. // time stamp
  583. ++pctx->Count;
  584. dprintf("%3d.(0x%p) ", pctx->Count, address);
  585. if (pctx->Flags) {
  586. dprintf("%16I64x ", FileTime);
  587. dprintf("%16I64x ", FileSize);
  588. dprintf("%p %p ", blink, flink);
  589. }
  590. // name
  591. DumpUnicode64(u);
  592. dprintf("\n");
  593. bReturn = FALSE;
  594. cleanup:
  595. return bReturn;
  596. }
  597. //
  598. // parameters:
  599. // bit 0 - access method
  600. // - 0x01 - dump tree, 0x00 - dump lru
  601. // bit 4 - details
  602. // - 0x00 - no details, just name 0x10 - details
  603. //
  604. DECLARE_API( ahcache )
  605. {
  606. ULONG64 restartKey;
  607. ULONG64 ptr;
  608. ULONG64 address;
  609. CHAR cacheEntryType[] = "nt!tagSHIMCACHEENTRY";
  610. CHAR unicodeStringType[] = "nt!_UNICODE_STRING";
  611. CHAR cacheHeadType[] = "nt!tagSHIMCACHEHEADER";
  612. CHAR listEntryType[] = "LIST_ENTRY";
  613. UNICODE_STRING64 u;
  614. ULONG64 unicodeString;
  615. ULONG64 cacheheader;
  616. ULONG64 listhead;
  617. ULONG64 table;
  618. ULONG64 name;
  619. ULONG64 FileSize;
  620. ULONG64 FileTime;
  621. ULONG64 listent;
  622. ULONG64 flink, blink;
  623. ULONG64 Flags = 0;
  624. ULONG Offset;
  625. AHCDUMPCTX ctx;
  626. ULONG Count;
  627. //
  628. // check args to see whether we need to dump the tree or LRU list
  629. //
  630. if (!GetExpressionEx(args, &Flags, &args)) {
  631. Flags = 0;
  632. }
  633. // default is to dump the tree
  634. // dump the header
  635. cacheheader = GetExpression("nt!g_ShimCache");
  636. if (!cacheheader) {
  637. dprintf("Cannot read address of nt!g_ShimCache\n");
  638. goto cleanup;
  639. }
  640. dprintf("Cache header at 0x%p\n", cacheheader);
  641. if (GetFieldOffset(cacheHeadType, "Table", &Offset)) {
  642. dprintf("Cannot get field Table offset off %s\n", cacheHeadType);
  643. goto cleanup;
  644. }
  645. table = cacheheader + Offset;
  646. if (GetFieldOffset(cacheHeadType, "ListHead", &Offset)) {
  647. dprintf("Cannot get field ListHead offset off %s\n", cacheHeadType);
  648. goto cleanup;
  649. }
  650. listhead = cacheheader + Offset;
  651. flink = 0;
  652. if (GetFieldValue(listhead, listEntryType, "Flink", flink)) {
  653. dprintf("Cannot get the value of flink from %s(0x%p)\n", listEntryType, listhead);
  654. }
  655. blink = 0;
  656. if (GetFieldValue(listhead, listEntryType, "Blink", blink)) {
  657. dprintf("Cannot get the value of blink from %s(0x%p)\n", listEntryType, listhead);
  658. }
  659. dprintf("LRU: Flink 0x%p Blink 0x%p\n", flink, blink);
  660. if (Flags & 0x0F) {
  661. Count = 0;
  662. dprintf("Size\tNext\tPrev\tName\n");
  663. restartKey = 0;
  664. while ((ptr = KdEnumerateGenericTableWithoutSplaying(table, &restartKey, TRUE))) {
  665. address = ptr;
  666. if (CheckControlC()) {
  667. break;
  668. }
  669. if (GetFieldOffset(cacheEntryType, "FileName", &Offset)) {
  670. dprintf("Failed to get field FileName offset off %s\n", cacheEntryType);
  671. break;
  672. }
  673. name = address + Offset;
  674. if (GetFieldValue(name, unicodeStringType, "Length", u.Length)) {
  675. dprintf("Failed to get the value of Length from %s(0x%p)\n", unicodeStringType, name);
  676. break;
  677. }
  678. if (GetFieldValue(name, unicodeStringType, "MaximumLength", u.MaximumLength)) {
  679. dprintf("Failed to get the value of MaximumLength from %s(0x%p)\n", unicodeStringType, name);
  680. break;
  681. }
  682. if (GetFieldValue(name, unicodeStringType, "Buffer", u.Buffer)) {
  683. dprintf("Failed to get the value of Length from %s(0x%p)\n", unicodeStringType, name);
  684. break;
  685. }
  686. if (GetFieldValue(address, cacheEntryType, "FileSize", FileSize)) {
  687. dprintf("Failed to get the value of FileSize from %s(0x%p)\n", cacheEntryType, address);
  688. break;
  689. }
  690. if (GetFieldValue(address, cacheEntryType, "FileTime", FileTime)) {
  691. dprintf("Failed to get the value of FileTime from %s(0x%p)\n", cacheEntryType, address);
  692. break;
  693. }
  694. // now read the list ptrs
  695. if (GetFieldOffset(cacheEntryType, "ListEntry", &Offset)) {
  696. dprintf("Failed to get field ListEntry offset off %s\n", cacheEntryType);
  697. break;
  698. }
  699. listent = address + Offset;
  700. if (GetFieldValue(listent, "LIST_ENTRY", "Flink", flink)) {
  701. dprintf("Failed to get the value of Flink from %s(0x%p)\n", listEntryType, listent);
  702. break;
  703. }
  704. if (GetFieldValue(listent, "LIST_ENTRY", "Blink", blink)) {
  705. dprintf("Failed to get the value of Blink from %s(0x%p)\n", listEntryType, listent);
  706. break;
  707. }
  708. // dump the values involved
  709. // time stamp
  710. ++Count;
  711. dprintf("%3d.(0x%p) ", Count, address);
  712. if (Flags & 0xF0) {
  713. dprintf("%16I64x ", FileTime);
  714. dprintf("%16I64x ", FileSize);
  715. dprintf("%p %p ", blink, flink);
  716. }
  717. // name
  718. DumpUnicode64(u);
  719. dprintf("\n");
  720. }
  721. } else {
  722. ; // not yet implemented
  723. ctx.Count = 0;
  724. ctx.ListEnd = listhead;
  725. ctx.Flags = Flags & 0x0F0;
  726. if (Flags & 0x100) {
  727. ListType(cacheEntryType,
  728. blink,
  729. 1,
  730. "ListEntry.Blink",
  731. (PVOID)&ctx,
  732. AHCacheDumpFieldCallback
  733. );
  734. } else {
  735. ListType(cacheEntryType,
  736. flink,
  737. 1,
  738. "ListEntry.Flink",
  739. (PVOID)&ctx,
  740. AHCacheDumpFieldCallback
  741. );
  742. }
  743. }
  744. cleanup:
  745. return S_OK;
  746. }