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.

2083 lines
57 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. cmkd.c
  5. Abstract:
  6. Kernel debugger extensions useful for the registry
  7. Starting point: regext.c (jvert)
  8. Author:
  9. Dragos C. Sambotin (dragoss) 5-May-1999
  10. Environment:
  11. Loaded as a kernel debugger extension
  12. Revision History:
  13. Dragos C. Sambotin (dragoss) 5-May-1999
  14. created
  15. Dragos C. Sambotin (dragoss) 06-March-2000
  16. moved to cm directory; ported to new windbg format
  17. --*/
  18. #include "cmp.h"
  19. #include <nt.h>
  20. #include <ntrtl.h>
  21. #include <nturtl.h>
  22. #include <ntos.h>
  23. #include <zwapi.h>
  24. #include <stdlib.h>
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include <windef.h>
  28. #include <windows.h>
  29. #include <ntverp.h>
  30. #include <imagehlp.h>
  31. #include <memory.h>
  32. #include <wdbgexts.h>
  33. #include <stdlib.h>
  34. #include <stdio.h>
  35. EXT_API_VERSION ApiVersion = { 3, 5, EXT_API_VERSION_NUMBER, 0 };
  36. WINDBG_EXTENSION_APIS ExtensionApis;
  37. USHORT SavedMajorVersion;
  38. USHORT SavedMinorVersion;
  39. HIVE_LIST_ENTRY HiveList[8];
  40. ULONG TotalPages;
  41. ULONG TotalPresentPages;
  42. ULONG TotalKcbs;
  43. ULONG TotalKcbName;
  44. BOOLEAN SavePages;
  45. BOOLEAN RestorePages;
  46. FILE *TempFile;
  47. #define ExitIfCtrlC() if (CheckControlC()) return
  48. #define BreakIfCtrlC() if (CheckControlC()) break
  49. VOID
  50. WinDbgExtensionDllInit(
  51. PWINDBG_EXTENSION_APIS lpExtensionApis,
  52. USHORT MajorVersion,
  53. USHORT MinorVersion
  54. )
  55. {
  56. ExtensionApis = *lpExtensionApis;
  57. SavedMajorVersion = MajorVersion;
  58. SavedMinorVersion = MinorVersion;
  59. return;
  60. }
  61. DllInit(
  62. HANDLE hModule,
  63. DWORD dwReason,
  64. DWORD dwReserved
  65. )
  66. {
  67. UNREFERENCED_PARAMETER( hModule );
  68. UNREFERENCED_PARAMETER( dwReserved );
  69. switch (dwReason) {
  70. case DLL_THREAD_ATTACH:
  71. break;
  72. case DLL_THREAD_DETACH:
  73. break;
  74. case DLL_PROCESS_DETACH:
  75. break;
  76. case DLL_PROCESS_ATTACH:
  77. break;
  78. }
  79. return TRUE;
  80. }
  81. DECLARE_API( version )
  82. {
  83. #if DBG
  84. PCHAR DebuggerType = "Checked";
  85. #else
  86. PCHAR DebuggerType = "Free";
  87. #endif
  88. UNREFERENCED_PARAMETER( args );
  89. UNREFERENCED_PARAMETER( dwProcessor );
  90. UNREFERENCED_PARAMETER( dwCurrentPc );
  91. UNREFERENCED_PARAMETER( hCurrentThread );
  92. UNREFERENCED_PARAMETER( hCurrentProcess );
  93. dprintf( "%s Extension dll for Build %d debugging %s kernel for Build %d\n",
  94. DebuggerType,
  95. VER_PRODUCTBUILD,
  96. SavedMajorVersion == 0x0c ? "Checked" : "Free",
  97. SavedMinorVersion
  98. );
  99. }
  100. VOID
  101. CheckVersion(
  102. VOID
  103. )
  104. {
  105. #if DBG
  106. if ((SavedMajorVersion != 0x0c) || (SavedMinorVersion != VER_PRODUCTBUILD)) {
  107. dprintf("\r\n*** Extension DLL(%d Checked) does not match target system(%d %s)\r\n\r\n",
  108. VER_PRODUCTBUILD, SavedMinorVersion, (SavedMajorVersion==0x0f) ? "Free" : "Checked" );
  109. }
  110. #else
  111. if ((SavedMajorVersion != 0x0f) || (SavedMinorVersion != VER_PRODUCTBUILD)) {
  112. dprintf("\r\n*** Extension DLL(%d Free) does not match target system(%d %s)\r\n\r\n",
  113. VER_PRODUCTBUILD, SavedMinorVersion, (SavedMajorVersion==0x0f) ? "Free" : "Checked" );
  114. }
  115. #endif
  116. }
  117. LPEXT_API_VERSION
  118. ExtensionApiVersion(
  119. VOID
  120. )
  121. {
  122. return &ApiVersion;
  123. }
  124. USHORT
  125. GetKcbName(
  126. ULONG_PTR KcbAddr,
  127. PWCHAR NameBuffer,
  128. ULONG BufferSize
  129. )
  130. /*++
  131. Routine Description:
  132. Takes a kcb and dump its complete name.
  133. Arguments:
  134. KcbAddr - Address of key control block.
  135. NameBuffer - The Name buffer to fill in the name.
  136. BufferSize - Size of Buffer.
  137. Return Value:
  138. Size of Name String.
  139. --*/
  140. {
  141. WCHAR Name[ 256 ];
  142. CM_KEY_CONTROL_BLOCK TmpKcb;
  143. ULONG_PTR TmpKcbAddr;
  144. CM_NAME_CONTROL_BLOCK NameBlock;
  145. ULONG_PTR NameBlockAddr;
  146. DWORD BytesRead;
  147. USHORT Length;
  148. USHORT TotalLength;
  149. USHORT size;
  150. USHORT i;
  151. USHORT BeginPosition;
  152. WCHAR *w1, *w2;
  153. WCHAR *BufferEnd;
  154. UCHAR *u2;
  155. //
  156. // Calculate the total string length.
  157. //
  158. TotalLength = 0;
  159. TmpKcbAddr = KcbAddr;
  160. while (TmpKcbAddr) {
  161. ExitIfCtrlC() 0;
  162. if( !ReadMemory(TmpKcbAddr,
  163. &TmpKcb,
  164. sizeof(TmpKcb),
  165. &BytesRead) ) {
  166. dprintf("Could not read KCB: 1\n");
  167. return (0);
  168. }
  169. NameBlockAddr = (ULONG_PTR) TmpKcb.NameBlock;
  170. if(!ReadMemory(NameBlockAddr,
  171. &NameBlock,
  172. sizeof(NameBlock),
  173. &BytesRead)) {
  174. dprintf("Could not read NCB: 2\n");
  175. return (0);
  176. }
  177. if (NameBlock.Compressed) {
  178. Length = NameBlock.NameLength * sizeof(WCHAR);
  179. } else {
  180. Length = NameBlock.NameLength;
  181. }
  182. TotalLength += Length;
  183. //
  184. // Add the sapce for OBJ_NAME_PATH_SEPARATOR;
  185. //
  186. TotalLength += sizeof(WCHAR);
  187. TmpKcbAddr = (ULONG_PTR) TmpKcb.ParentKcb;
  188. }
  189. BufferEnd = &(NameBuffer[BufferSize/sizeof(WCHAR) - 1]);
  190. if (TotalLength < BufferSize) {
  191. NameBuffer[TotalLength/sizeof(WCHAR)] = UNICODE_NULL;
  192. } else {
  193. *BufferEnd = UNICODE_NULL;
  194. }
  195. //
  196. // Now fill the name into the buffer.
  197. //
  198. TmpKcbAddr = KcbAddr;
  199. BeginPosition = TotalLength;
  200. while (TmpKcbAddr) {
  201. ExitIfCtrlC() 0;
  202. //
  203. // Read the information.
  204. //
  205. if(!ReadMemory(TmpKcbAddr,
  206. &TmpKcb,
  207. sizeof(TmpKcb),
  208. &BytesRead) ) {
  209. dprintf("Could not read KCB: 3\n");
  210. return (0);
  211. }
  212. NameBlockAddr = (ULONG_PTR) TmpKcb.NameBlock;
  213. if(!ReadMemory(NameBlockAddr,
  214. &NameBlock,
  215. sizeof(NameBlock),
  216. &BytesRead) ) {
  217. dprintf("Could not read NCB: 4\n");
  218. return (0);
  219. }
  220. if(!ReadMemory(NameBlockAddr + FIELD_OFFSET(CM_NAME_CONTROL_BLOCK, Name),
  221. Name,
  222. NameBlock.NameLength,
  223. &BytesRead) ) {
  224. dprintf("Could not read Name BUFFER: 5\n");
  225. return (0);
  226. }
  227. //
  228. // Calculate the begin position of each subkey. Then fill in the char.
  229. //
  230. //
  231. if (NameBlock.Compressed) {
  232. BeginPosition -= (NameBlock.NameLength + 1) * sizeof(WCHAR);
  233. w1 = &(NameBuffer[BeginPosition/sizeof(WCHAR)]);
  234. if (w1 < BufferEnd) {
  235. *w1 = OBJ_NAME_PATH_SEPARATOR;
  236. }
  237. w1++;
  238. u2 = (UCHAR *) &(Name[0]);
  239. for (i=0; i<NameBlock.NameLength; i++) {
  240. if (w1 < BufferEnd) {
  241. *w1 = (WCHAR)(*u2);
  242. } else {
  243. break;
  244. }
  245. w1++;
  246. u2++;
  247. }
  248. } else {
  249. BeginPosition -= (NameBlock.NameLength + sizeof(WCHAR));
  250. w1 = &(NameBuffer[BeginPosition/sizeof(WCHAR)]);
  251. if (w1 < BufferEnd) {
  252. *w1 = OBJ_NAME_PATH_SEPARATOR;
  253. }
  254. w1++;
  255. w2 = Name;
  256. for (i=0; i<NameBlock.NameLength; i=i+sizeof(WCHAR)) {
  257. if (w1 < BufferEnd) {
  258. *w1 = *w2;
  259. } else {
  260. break;
  261. }
  262. w1++;
  263. w2++;
  264. }
  265. }
  266. TmpKcbAddr = (ULONG_PTR) TmpKcb.ParentKcb;
  267. }
  268. // dprintf("\n%5d, %ws\n", TotalLength, NameBuffer);
  269. return (TotalLength);
  270. }
  271. DECLARE_API( childlist )
  272. {
  273. DWORD Count;
  274. ULONG64 RecvAddr;
  275. ULONG_PTR Addr;
  276. DWORD BytesRead;
  277. USHORT u;
  278. CM_KEY_INDEX Index;
  279. USHORT Signature; // also type selector
  280. HCELL_INDEX Cell;
  281. UCHAR NameHint[5];
  282. sscanf(args,"%I64lX",&RecvAddr);
  283. Addr = (ULONG_PTR)RecvAddr;
  284. if(!ReadMemory(Addr,
  285. &Index,
  286. sizeof(Index),
  287. &BytesRead) ) {
  288. dprintf("\tCould not read index\n");
  289. return;
  290. } else {
  291. Addr+= 2*sizeof(USHORT);
  292. Signature = Index.Signature;
  293. Count = Index.Count;
  294. if(Count > 100) {
  295. Count = 100;
  296. }
  297. if( Signature == CM_KEY_INDEX_ROOT ) {
  298. dprintf("Index is a CM_KEY_INDEX_ROOT, %u elements\n",Count);
  299. for( u=0;u<Count;u++) {
  300. if( !ReadMemory(Addr,
  301. &Cell,
  302. sizeof(Cell),
  303. &BytesRead) ) {
  304. dprintf("\tCould not read Index[%u]\n",u);
  305. } else {
  306. dprintf(" Index[%u] = %lx\n",u,(ULONG)Cell);
  307. }
  308. Addr += sizeof(Cell);
  309. }
  310. } else if( Signature == CM_KEY_FAST_LEAF ) {
  311. dprintf("Index is a CM_KEY_FAST_LEAF, %u elements\n",Count);
  312. dprintf("Index[ ] %8s %s\n","Cell","Hint");
  313. for( u=0;u<Count;u++) {
  314. if( !ReadMemory(Addr,
  315. &Cell,
  316. sizeof(Cell),
  317. &BytesRead) ) {
  318. dprintf("\tCould not read Index[%u]\n",u);
  319. } else {
  320. dprintf(" Index[%2u] = %8lx",u,(ULONG)Cell);
  321. Addr += sizeof(Cell);
  322. if( !ReadMemory(Addr,
  323. NameHint,
  324. 4*sizeof(UCHAR),
  325. &BytesRead) ) {
  326. dprintf("\tCould not read Index[%u]\n",u);
  327. } else {
  328. NameHint[4] = 0;
  329. dprintf(" %s\n",NameHint);
  330. }
  331. }
  332. Addr += 4*sizeof(UCHAR);
  333. }
  334. } else {
  335. dprintf("Index is a CM_KEY_INDEX_LEAF, %u elements\n",Count);
  336. dprintf("CM_KEY_INDEX_LEAF not yet implemented\n");
  337. }
  338. }
  339. return;
  340. }
  341. DECLARE_API( kcb )
  342. /*++
  343. Routine Description:
  344. Dumps the name when given a KCB address
  345. Called as:
  346. !regkcb KCB_Address
  347. Arguments:
  348. args - Supplies the address of the KCB.
  349. Return Value:
  350. .
  351. --*/
  352. {
  353. WCHAR KeyName[ 256 ];
  354. ULONG64 RecvAddr;
  355. ULONG_PTR KcbAddr;
  356. CM_KEY_CONTROL_BLOCK Kcb;
  357. DWORD BytesRead;
  358. CM_INDEX_HINT_BLOCK IndexHint;
  359. sscanf(args,"%I64lX",&RecvAddr);
  360. KcbAddr = (ULONG_PTR)RecvAddr;
  361. if( !ReadMemory(KcbAddr,
  362. &Kcb,
  363. sizeof(Kcb),
  364. &BytesRead) ) {
  365. dprintf("Could not read Kcb\n");
  366. return;
  367. } else {
  368. if(GetKcbName(KcbAddr, KeyName, sizeof(KeyName))) {
  369. dprintf("Key : %ws\n", KeyName);
  370. } else {
  371. dprintf("Could not read key name\n");
  372. return;
  373. }
  374. dprintf("RefCount : %lx\n", Kcb.RefCount);
  375. dprintf("Attrib :");
  376. if (Kcb.ExtFlags & CM_KCB_KEY_NON_EXIST) {
  377. dprintf(" Fake,");
  378. }
  379. if (Kcb.Delete) {
  380. dprintf(" Deleted,");
  381. }
  382. if (Kcb.Flags & KEY_SYM_LINK) {
  383. dprintf(" Symbolic,");
  384. }
  385. if (Kcb.Flags & KEY_VOLATILE) {
  386. dprintf(" Volatile");
  387. } else {
  388. dprintf(" Stable");
  389. }
  390. KcbAddr = (ULONG_PTR)Kcb.ParentKcb;
  391. dprintf("\n");
  392. dprintf("Parent : 0x%p\n", KcbAddr);
  393. dprintf("KeyHive : 0x%p\n", Kcb.KeyHive);
  394. dprintf("KeyCell : 0x%lx [cell index]\n", Kcb.KeyCell);
  395. dprintf("TotalLevels : %u\n", Kcb.TotalLevels);
  396. dprintf("DelayedCloseIndex: %u\n", Kcb.DelayedCloseIndex);
  397. dprintf("MaxNameLen : 0x%lx\n", Kcb.KcbMaxNameLen);
  398. dprintf("MaxValueNameLen : 0x%lx\n", Kcb.KcbMaxValueNameLen);
  399. dprintf("MaxValueDataLen : 0x%lx\n", Kcb.KcbMaxValueDataLen);
  400. dprintf("LastWriteTime : 0x%8lx:0x%8lx\n", Kcb.KcbLastWriteTime.HighPart,Kcb.KcbLastWriteTime.LowPart);
  401. dprintf("KeyBodyListHead : 0x%p 0x%p\n", Kcb.KeyBodyListHead.Flink, Kcb.KeyBodyListHead.Blink);
  402. dprintf("SubKeyCount : ");
  403. if( !(Kcb.ExtFlags & CM_KCB_INVALID_CACHED_INFO) ) {
  404. if (Kcb.ExtFlags & CM_KCB_NO_SUBKEY ) {
  405. dprintf("0");
  406. } else if (Kcb.ExtFlags & CM_KCB_SUBKEY_ONE ) {
  407. dprintf("1");
  408. } else if (Kcb.ExtFlags & CM_KCB_SUBKEY_HINT ) {
  409. if( !ReadMemory((ULONG_PTR)Kcb.IndexHint,
  410. &IndexHint,
  411. sizeof(IndexHint),
  412. &BytesRead) ) {
  413. dprintf("Could not read Kcb\n");
  414. return;
  415. } else {
  416. dprintf("%lu",IndexHint.Count);
  417. }
  418. } else {
  419. dprintf("%lu",Kcb.SubKeyCount);
  420. }
  421. } else {
  422. dprintf("hint not valid");
  423. }
  424. dprintf("\n");
  425. }
  426. return;
  427. }
  428. DECLARE_API( knode )
  429. /*++
  430. Routine Description:
  431. Dumps the name when given a KCB address
  432. Called as:
  433. !knode KNode_Address
  434. Arguments:
  435. args - Supplies the address of the CM_KEY_NODE.
  436. Return Value:
  437. .
  438. --*/
  439. {
  440. char KeyName[ 256 ];
  441. ULONG64 RecvAddr;
  442. ULONG_PTR KnAddr;
  443. CM_KEY_NODE KNode;
  444. DWORD BytesRead;
  445. sscanf(args,"%I64lX",&RecvAddr);
  446. KnAddr = (ULONG_PTR)RecvAddr;
  447. if( !ReadMemory(KnAddr,
  448. &KNode,
  449. sizeof(KNode),
  450. &BytesRead) ) {
  451. dprintf("Could not read KeyNode\n");
  452. return;
  453. } else {
  454. KnAddr += FIELD_OFFSET(CM_KEY_NODE, Name);
  455. if( KNode.Signature == CM_KEY_NODE_SIGNATURE) {
  456. dprintf("Signature: CM_KEY_NODE_SIGNATURE (kn)\n");
  457. } else if(KNode.Signature == CM_LINK_NODE_SIGNATURE) {
  458. dprintf("Signature: CM_LINK_NODE_SIGNATURE (kl)\n");
  459. } else {
  460. dprintf("Invalid Signature %u\n",KNode.Signature);
  461. }
  462. ReadMemory(KnAddr,
  463. KeyName,
  464. KNode.NameLength,
  465. &BytesRead);
  466. KeyName[KNode.NameLength] = '\0';
  467. dprintf("Name : %s\n", KeyName);
  468. dprintf("ParentCell : 0x%lx\n", KNode.Parent);
  469. dprintf("Security : 0x%lx [cell index]\n", KNode.Security);
  470. dprintf("Class : 0x%lx [cell index]\n", KNode.Class);
  471. dprintf("Flags : 0x%lx\n", KNode.Flags);
  472. dprintf("MaxNameLen : 0x%lx\n", KNode.MaxNameLen);
  473. dprintf("MaxClassLen : 0x%lx\n", KNode.MaxClassLen);
  474. dprintf("MaxValueNameLen : 0x%lx\n", KNode.MaxValueNameLen);
  475. dprintf("MaxValueDataLen : 0x%lx\n", KNode.MaxValueDataLen);
  476. dprintf("LastWriteTime : 0x%8lx:0x%8lx\n", KNode.LastWriteTime.HighPart,KNode.LastWriteTime.LowPart);
  477. if(!(KNode.Flags&KEY_HIVE_ENTRY)) {
  478. dprintf("SubKeyCount[Stable ]: 0x%lx\n", KNode.SubKeyCounts[Stable]);
  479. dprintf("SubKeyLists[Stable ]: 0x%lx\n", KNode.SubKeyLists[Stable]);
  480. dprintf("SubKeyCount[Volatile]: 0x%lx\n", KNode.SubKeyCounts[Volatile]);
  481. dprintf("SubKeyLists[Volatile]: 0x%lx\n", KNode.SubKeyLists[Volatile]);
  482. dprintf("ValueList.Count : 0x%lx\n", KNode.ValueList.Count);
  483. dprintf("ValueList.List : 0x%lx\n", KNode.ValueList.List);
  484. }
  485. }
  486. return;
  487. }
  488. //
  489. // Cell Procedures
  490. //
  491. ULONG_PTR
  492. MyHvpGetCellPaged(
  493. PHHIVE Hive,
  494. HCELL_INDEX Cell
  495. )
  496. /*++
  497. Routine Description:
  498. Returns the memory address for the specified Cell. Will never
  499. return failure, but may assert. Use HvIsCellAllocated to check
  500. validity of Cell.
  501. This routine should never be called directly, always call it
  502. via the HvGetCell() macro.
  503. This routine provides GetCell support for hives with full maps.
  504. It is the normal version of the routine.
  505. Arguments:
  506. Hive - supplies a pointer to the hive control structure for the
  507. hive of interest
  508. Cell - supplies HCELL_INDEX of cell to return address for
  509. Return Value:
  510. Address of Cell in memory. Assert or BugCheck if error.
  511. --*/
  512. {
  513. ULONG Type;
  514. ULONG Table;
  515. ULONG Block;
  516. ULONG Offset;
  517. PHCELL pcell;
  518. PHMAP_ENTRY Map;
  519. HMAP_TABLE MapTable;
  520. HMAP_DIRECTORY DirMap;
  521. ULONG Tables;
  522. ULONG_PTR lRez;
  523. DWORD BytesRead;
  524. ULONG_PTR BlockAddress;
  525. HCELL hcell;
  526. ASSERT(Hive->Signature == HHIVE_SIGNATURE);
  527. ASSERT(Cell != HCELL_NIL);
  528. ASSERT(Hive->Flat == FALSE);
  529. ASSERT((Cell & (HCELL_PAD(Hive)-1))==0);
  530. Type = HvGetCellType(Cell);
  531. Table = (Cell & HCELL_TABLE_MASK) >> HCELL_TABLE_SHIFT;
  532. Block = (Cell & HCELL_BLOCK_MASK) >> HCELL_BLOCK_SHIFT;
  533. Offset = (Cell & HCELL_OFFSET_MASK);
  534. ASSERT((Cell - (Type * HCELL_TYPE_MASK)) < Hive->Storage[Type].Length);
  535. //
  536. // read in map directory
  537. //
  538. ReadMemory((DWORD_PTR)Hive->Storage[Type].Map,
  539. &DirMap,
  540. sizeof(DirMap),
  541. &BytesRead);
  542. ReadMemory((DWORD_PTR)DirMap.Directory[Table],
  543. &MapTable,
  544. sizeof(MapTable),
  545. &BytesRead);
  546. Map = &(MapTable.Table[Block]);
  547. BlockAddress = (ULONG_PTR)Map->BlockAddress;
  548. pcell = (PHCELL)((ULONG_PTR)(BlockAddress) + Offset);
  549. lRez = (ULONG_PTR)pcell;
  550. if (USE_OLD_CELL(Hive)) {
  551. return lRez + sizeof(LONG) + sizeof(ULONG);
  552. //return (struct _CELL_DATA *)&(hcell.u.OldCell.u.UserData);
  553. } else {
  554. return lRez + sizeof(LONG);
  555. //return (struct _CELL_DATA *)&(hcell.u.NewCell.u.UserData);
  556. }
  557. }
  558. ULONG_PTR
  559. MyHvpGetCellFlat(
  560. PHHIVE Hive,
  561. HCELL_INDEX Cell
  562. )
  563. /*++
  564. Routine Description:
  565. Returns the memory address for the specified Cell. Will never
  566. return failure, but may assert. Use HvIsCellAllocated to check
  567. validity of Cell.
  568. This routine should never be called directly, always call it
  569. via the HvGetCell() macro.
  570. This routine provides GetCell support for read only hives with
  571. single allocation flat images. Such hives do not have cell
  572. maps ("page tables"), instead, we compute addresses by
  573. arithmetic against the base image address.
  574. Such hives cannot have volatile cells.
  575. Arguments:
  576. Hive - supplies a pointer to the hive control structure for the
  577. hive of interest
  578. Cell - supplies HCELL_INDEX of cell to return address for
  579. Return Value:
  580. Address of Cell in memory. Assert or BugCheck if error.
  581. --*/
  582. {
  583. PUCHAR base;
  584. PHCELL pcell;
  585. HBASE_BLOCK BaseBlock;
  586. ULONG_PTR lRez;
  587. DWORD BytesRead;
  588. ASSERT(Hive->Signature == HHIVE_SIGNATURE);
  589. ASSERT(Cell != HCELL_NIL);
  590. ASSERT(Hive->Flat == TRUE);
  591. ASSERT(HvGetCellType(Cell) == Stable);
  592. ASSERT(Cell >= sizeof(HBIN));
  593. ReadMemory((DWORD_PTR)Hive->BaseBlock,
  594. &BaseBlock,
  595. sizeof(BaseBlock),
  596. &BytesRead);
  597. ASSERT(Cell < BaseBlock.Length);
  598. ASSERT((Cell & 0x7)==0);
  599. //
  600. // Address is base of Hive image + Cell
  601. //
  602. base = (PUCHAR)(Hive->BaseBlock) + HBLOCK_SIZE;
  603. pcell = (PHCELL)(base + Cell);
  604. lRez = (ULONG_PTR)pcell;
  605. if (USE_OLD_CELL(Hive)) {
  606. return lRez + sizeof(LONG) + sizeof(ULONG);
  607. //return (struct _CELL_DATA *)&(pcell->u.OldCell.u.UserData);
  608. } else {
  609. return lRez + sizeof(LONG);
  610. //return (struct _CELL_DATA *)&(pcell->u.NewCell.u.UserData);
  611. }
  612. }
  613. DECLARE_API( cellindex )
  614. /*++
  615. Routine Description:
  616. Dumps the name when given a KCB address
  617. Called as:
  618. !cellindex HiveAddr HCELL_INDEX
  619. Arguments:
  620. args - Supplies the address of the HCELL_INDEX.
  621. Return Value:
  622. .
  623. --*/
  624. {
  625. ULONG64 RecvAddr;
  626. DWORD IdxAddr;
  627. ULONG_PTR HiveAddr;
  628. DWORD BytesRead;
  629. HCELL_INDEX cell;
  630. CMHIVE CmHive;
  631. ULONG_PTR pcell;
  632. sscanf(args,"%I64lX %lx",&RecvAddr,&IdxAddr);
  633. HiveAddr = (ULONG_PTR)RecvAddr;
  634. cell = IdxAddr;
  635. if( !ReadMemory(HiveAddr,
  636. &CmHive,
  637. sizeof(CmHive),
  638. &BytesRead) ) {
  639. dprintf("\tRead %lx bytes from %lx\n",BytesRead,HiveAddr);
  640. return;
  641. }
  642. if(CmHive.Hive.Flat) {
  643. pcell = MyHvpGetCellFlat(&(CmHive.Hive),cell);
  644. } else {
  645. pcell = MyHvpGetCellPaged(&(CmHive.Hive),cell);
  646. }
  647. dprintf("pcell: %p\n",pcell);
  648. }
  649. DECLARE_API( kvalue )
  650. /*++
  651. Routine Description:
  652. Dumps the name when given a KCB address
  653. Called as:
  654. !kvalue KValue_Address
  655. Arguments:
  656. args - Supplies the address of the CM_KEY_NODE.
  657. Return Value:
  658. .
  659. --*/
  660. {
  661. char ValName[ 256 ];
  662. ULONG64 RecvAddr;
  663. ULONG_PTR ValAddr;
  664. CM_KEY_VALUE KVal;
  665. DWORD BytesRead;
  666. sscanf(args,"%I64lX",&RecvAddr);
  667. ValAddr = (ULONG_PTR)RecvAddr;
  668. if( !ReadMemory(ValAddr,
  669. &KVal,
  670. sizeof(KVal),
  671. &BytesRead) ) {
  672. dprintf("Could not read KeyValue\n");
  673. return;
  674. } else {
  675. ValAddr += FIELD_OFFSET(CM_KEY_VALUE, Name);
  676. if( KVal.Signature == CM_KEY_VALUE_SIGNATURE) {
  677. dprintf("Signature: CM_KEY_VALUE_SIGNATURE (kv)\n");
  678. } else {
  679. dprintf("Invalid Signature %lx\n",KVal.Signature);
  680. }
  681. if(KVal.Flags & VALUE_COMP_NAME) {
  682. ReadMemory(ValAddr,
  683. ValName,
  684. KVal.NameLength,
  685. &BytesRead);
  686. ValName[KVal.NameLength] = '\0';
  687. dprintf("Name : %s {compressed}\n", ValName);
  688. }
  689. dprintf("DataLength: %lx\n", KVal.DataLength);
  690. dprintf("Data : %lx [cell index]\n", KVal.Data);
  691. dprintf("Type : %lx\n", KVal.Type);
  692. }
  693. return;
  694. }
  695. DECLARE_API( kbody )
  696. /*++
  697. Routine Description:
  698. displays a CM_KEY_BODY
  699. Called as:
  700. !kbody KBody_Address
  701. Arguments:
  702. args - Supplies the address of the CM_KEY_BODY.
  703. Return Value:
  704. .
  705. --*/
  706. {
  707. ULONG64 RecvAddr;
  708. ULONG_PTR KBodyAddr;
  709. CM_KEY_BODY KBody;
  710. DWORD BytesRead;
  711. sscanf(args,"%I64lX",&RecvAddr);
  712. KBodyAddr = (ULONG_PTR)RecvAddr;
  713. if( !ReadMemory(KBodyAddr,
  714. &KBody,
  715. sizeof(KBody),
  716. &BytesRead) ) {
  717. dprintf("Could not read KeyBody\n");
  718. return;
  719. } else {
  720. if( KBody.Type == KEY_BODY_TYPE) {
  721. dprintf("Type : KEY_BODY_TYPE\n");
  722. } else {
  723. dprintf("Invalid Type %lx\n",KBody.Type);
  724. }
  725. dprintf("KCB : %p\n", KBody.KeyControlBlock);
  726. dprintf("NotifyBlock : %p\n", KBody.NotifyBlock);
  727. dprintf("Process : %p\n", KBody.Process);
  728. dprintf("KeyBodyList : %p %p\n", KBody.KeyBodyList.Flink, KBody.KeyBodyList.Blink);
  729. }
  730. return;
  731. }
  732. DECLARE_API( hashindex )
  733. /*++
  734. Routine Description:
  735. display the index for the convkey
  736. Called as:
  737. !hashindex conv_key
  738. Arguments:
  739. args - convkey.
  740. Return Value:
  741. .
  742. --*/
  743. {
  744. ULONG ConvKey;
  745. ULONG CmpHashTableSize = 2048;
  746. ULONG_PTR Address;
  747. ULONG_PTR CmpCacheTable,CmpNameCacheTable;
  748. DWORD BytesRead;
  749. sscanf(args,"%lx",&ConvKey);
  750. dprintf("Hash Index[%8lx] : %lx\n",ConvKey,GET_HASH_INDEX(ConvKey));
  751. Address = GetExpression("CmpCacheTable");
  752. if( !ReadMemory(Address,
  753. &CmpCacheTable,
  754. sizeof(CmpCacheTable),
  755. &BytesRead) ) {
  756. dprintf("Could not read CmpCacheTable\n");
  757. } else {
  758. dprintf("CmpCacheTable : %p\n",CmpCacheTable);
  759. }
  760. Address = GetExpression("CmpNameCacheTable");
  761. if( !ReadMemory(Address,
  762. &CmpNameCacheTable,
  763. sizeof(CmpNameCacheTable),
  764. &BytesRead) ) {
  765. dprintf("Could not read CmpNameCacheTable\n");
  766. } else {
  767. dprintf("CmpNameCacheTable : %p\n",CmpNameCacheTable);
  768. }
  769. return;
  770. }
  771. DECLARE_API( openkeys )
  772. /*++
  773. Routine Description:
  774. dumps open subkeys for the specified hive
  775. Called as:
  776. !openkeys hive
  777. if hive is 0, dump all KCBs
  778. Arguments:
  779. args - convkey.
  780. Return Value:
  781. .
  782. --*/
  783. {
  784. ULONG CmpHashTableSize = 2048;
  785. ULONG_PTR Address;
  786. ULONG_PTR CmpCacheTable,CmpNameCacheTable;
  787. DWORD BytesRead;
  788. ULONG64 RecvAddr;
  789. ULONG_PTR HiveAddr;
  790. ULONG i;
  791. ULONG_PTR Current;
  792. ULONG KcbNumber = 0;
  793. ULONG Offset = FIELD_OFFSET(CM_KEY_CONTROL_BLOCK, KeyHash);
  794. CM_KEY_HASH KeyHash;
  795. WCHAR KeyName[ 512 ];
  796. sscanf(args,"%I64lX",&RecvAddr);
  797. HiveAddr = (ULONG_PTR)RecvAddr;
  798. Address = GetExpression("CmpCacheTable");
  799. if( !ReadMemory(Address,
  800. &CmpCacheTable,
  801. sizeof(CmpCacheTable),
  802. &BytesRead) ) {
  803. dprintf("\nCould not read CmpCacheTable\n");
  804. } else {
  805. dprintf("\nCmpCacheTable : %p\n",CmpCacheTable);
  806. }
  807. Address = GetExpression("CmpNameCacheTable");
  808. if( !ReadMemory(Address,
  809. &CmpNameCacheTable,
  810. sizeof(CmpNameCacheTable),
  811. &BytesRead) ) {
  812. dprintf("Could not read CmpNameCacheTable\n\n");
  813. } else {
  814. dprintf("CmpNameCacheTable : %p\n\n",CmpNameCacheTable);
  815. }
  816. dprintf("List of open KCBs:\n\n");
  817. for (i=0; i<CmpHashTableSize; i++) {
  818. Address = CmpCacheTable + i* sizeof(PCM_KEY_HASH);
  819. ReadMemory(Address,
  820. &Current,
  821. sizeof(Current),
  822. &BytesRead);
  823. while (Current) {
  824. ExitIfCtrlC();
  825. ReadMemory(Current,
  826. &KeyHash,
  827. sizeof(KeyHash),
  828. &BytesRead);
  829. if( (HiveAddr == 0) || (HiveAddr == (ULONG_PTR)KeyHash.KeyHive) ) {
  830. KcbNumber++;
  831. dprintf("%p",Current-Offset);
  832. if (BytesRead < sizeof(KeyHash)) {
  833. dprintf("Could not read KeyHash at %p\n",Current);
  834. break;
  835. } else {
  836. if(GetKcbName(Current-Offset, KeyName, sizeof(KeyName))) {
  837. dprintf(" : %ws\n", KeyName);
  838. } else {
  839. dprintf("Could not read key name\n");
  840. }
  841. }
  842. }
  843. Current = (ULONG_PTR)KeyHash.NextHash;
  844. }
  845. }
  846. dprintf("\nTotal of %lu KCBs opened\n",KcbNumber);
  847. return;
  848. }
  849. DECLARE_API( baseblock )
  850. /*++
  851. Routine Description:
  852. displays the base block structure
  853. Called as:
  854. !baseblock address
  855. Arguments:
  856. args - convkey.
  857. Return Value:
  858. .
  859. --*/
  860. {
  861. HBASE_BLOCK BaseBlock;
  862. ULONG_PTR BaseAddr;
  863. DWORD BytesRead;
  864. PWCHAR FileName;
  865. ULONG64 RecvAddr;
  866. sscanf(args,"%I64lX",&RecvAddr);
  867. BaseAddr = (ULONG_PTR)RecvAddr;
  868. if( !ReadMemory(BaseAddr,
  869. &BaseBlock,
  870. sizeof(BaseBlock),
  871. &BytesRead) ) {
  872. dprintf("\tRead %lx bytes from %p\n",BytesRead,BaseAddr);
  873. return;
  874. }
  875. if( BaseBlock.Signature == HBASE_BLOCK_SIGNATURE ) {
  876. dprintf("Signature: HBASE_BLOCK_SIGNATURE\n");
  877. } else {
  878. dprintf("Signature: %lx\n",BaseBlock.Signature);
  879. }
  880. FileName = (PWCHAR)&(BaseBlock.FileName);
  881. FileName[HBASE_NAME_ALLOC/sizeof(WCHAR)] = 0;
  882. dprintf("FileName : %ws\n",FileName);
  883. dprintf("Sequence1: %lx\n",BaseBlock.Sequence1);
  884. dprintf("Sequence2: %lx\n",BaseBlock.Sequence2);
  885. dprintf("TimeStamp: %lx %lx\n",BaseBlock.TimeStamp.HighPart,BaseBlock.TimeStamp.LowPart);
  886. dprintf("Major : %lx\n",BaseBlock.Major);
  887. dprintf("Minor : %lx\n",BaseBlock.Minor);
  888. switch(BaseBlock.Type) {
  889. case HFILE_TYPE_PRIMARY:
  890. dprintf("Type : HFILE_TYPE_PRIMARY\n");
  891. break;
  892. case HFILE_TYPE_LOG:
  893. dprintf("Type : HFILE_TYPE_LOG\n");
  894. break;
  895. case HFILE_TYPE_EXTERNAL:
  896. dprintf("Type : HFILE_TYPE_EXTERNAL\n");
  897. break;
  898. default:
  899. dprintf("Type : %lx\n",BaseBlock.Type);
  900. break;
  901. }
  902. if( BaseBlock.Format == HBASE_FORMAT_MEMORY ) {
  903. dprintf("Format : HBASE_FORMAT_MEMORY\n");
  904. } else {
  905. dprintf("Format : %lx\n",BaseBlock.Format);
  906. }
  907. dprintf("RootCell : %lx\n",BaseBlock.RootCell);
  908. dprintf("Length : %lx\n",BaseBlock.Length);
  909. dprintf("Cluster : %lx\n",BaseBlock.Cluster);
  910. dprintf("CheckSum : %lx\n",BaseBlock.CheckSum);
  911. }
  912. DECLARE_API( findkcb )
  913. /*++
  914. Routine Description:
  915. finds a kcb given the full path
  916. Called as:
  917. !findkcb \REGISTRY\MACHINE\foo
  918. Arguments:
  919. args - convkey.
  920. Return Value:
  921. .
  922. --*/
  923. {
  924. ULONG CmpHashTableSize = 2048;
  925. ULONG_PTR Address;
  926. ULONG_PTR CmpCacheTable,CmpNameCacheTable;
  927. DWORD BytesRead;
  928. ULONG i,j,Count;
  929. ULONG_PTR Current;
  930. ULONG Offset = FIELD_OFFSET(CM_KEY_CONTROL_BLOCK, KeyHash);
  931. CM_KEY_HASH KeyHash;
  932. WCHAR KeyName[ 512 ];
  933. UCHAR AnsiFullKeyName[ 512 ];
  934. WCHAR FullKeyName[ 512 ];
  935. PWCHAR Dest;
  936. ULONG ConvKey = 0;
  937. sscanf(args,"%s",AnsiFullKeyName);
  938. for( Count=0;AnsiFullKeyName[Count];Count++) {
  939. FullKeyName[Count] = (WCHAR)AnsiFullKeyName[Count];
  940. if( FullKeyName[Count] != OBJ_NAME_PATH_SEPARATOR ) {
  941. ConvKey = 37 * ConvKey + (ULONG) CmUpcaseUnicodeChar(FullKeyName[Count]);
  942. }
  943. }
  944. FullKeyName[Count] = UNICODE_NULL;
  945. //dprintf("\nFullKeyName :%ws %\n",FullKeyName);
  946. Address = GetExpression("CmpCacheTable");
  947. if( !ReadMemory(Address,
  948. &CmpCacheTable,
  949. sizeof(CmpCacheTable),
  950. &BytesRead) ) {
  951. dprintf("\nCould not read CmpCacheTable\n");
  952. return;
  953. }
  954. Address = GetExpression("CmpNameCacheTable");
  955. if( !ReadMemory(Address,
  956. &CmpNameCacheTable,
  957. sizeof(CmpNameCacheTable),
  958. &BytesRead) ) {
  959. dprintf("Could not read CmpNameCacheTable\n\n");
  960. return;
  961. }
  962. i = GET_HASH_INDEX(ConvKey);
  963. //for (i=0; i<CmpHashTableSize; i++) {
  964. Address = CmpCacheTable + i* sizeof(PCM_KEY_HASH);
  965. ReadMemory(Address,
  966. &Current,
  967. sizeof(Current),
  968. &BytesRead);
  969. while (Current) {
  970. ExitIfCtrlC();
  971. if( !ReadMemory(Current,
  972. &KeyHash,
  973. sizeof(KeyHash),
  974. &BytesRead) ) {
  975. dprintf("Could not read KeyHash at %lx\n",Current);
  976. break;
  977. } else {
  978. if(GetKcbName(Current-Offset, KeyName, sizeof(KeyName))) {
  979. for(j=0;KeyName[j] != UNICODE_NULL;j++);
  980. if( (j == Count) && (_wcsnicmp(FullKeyName,KeyName,Count) == 0) ) {
  981. dprintf("\nFound KCB = %lx :: %ws\n\n",Current-Offset,KeyName);
  982. return;
  983. }
  984. dprintf("Along the path - KCB = %lx :: %ws\n",Current-Offset,KeyName);
  985. } else {
  986. continue;
  987. }
  988. }
  989. Current = (ULONG_PTR)KeyHash.NextHash;
  990. }
  991. //}
  992. dprintf("\nSorry %ws is not cached \n\n",FullKeyName);
  993. return;
  994. }
  995. DECLARE_API( seccache )
  996. /*++
  997. Routine Description:
  998. displays the base block structure
  999. Called as:
  1000. !seccache <HiveAddr>
  1001. Arguments:
  1002. args - convkey.
  1003. Return Value:
  1004. .
  1005. --*/
  1006. {
  1007. CMHIVE CmHive;
  1008. ULONG64 RecvAddr;
  1009. ULONG_PTR HiveAddr;
  1010. DWORD BytesRead;
  1011. PWCHAR FileName;
  1012. CM_KEY_SECURITY_CACHE_ENTRY SecurityCacheEntry;
  1013. ULONG i;
  1014. ULONG Tmp;
  1015. sscanf(args,"%I64lX",&RecvAddr);
  1016. HiveAddr = (ULONG_PTR)RecvAddr;
  1017. if( !ReadMemory(HiveAddr,
  1018. &CmHive,
  1019. sizeof(CmHive),
  1020. &BytesRead) ) {
  1021. dprintf("\tRead %lx bytes from %p\n",BytesRead,HiveAddr);
  1022. return;
  1023. }
  1024. if( CmHive.Hive.Signature != HHIVE_SIGNATURE ) {
  1025. dprintf("Invalid Hive signature: %lx\n",CmHive.Hive.Signature);
  1026. return;
  1027. }
  1028. Tmp = CmHive.SecurityCacheSize;
  1029. dprintf("SecurityCacheSize = : 0x%lx\n",Tmp);
  1030. Tmp = CmHive.SecurityCount;
  1031. dprintf("SecurityCount = : 0x%lx\n",Tmp);
  1032. Tmp = CmHive.SecurityHitHint;
  1033. dprintf("SecurityHitHint = : 0x%lx\n",Tmp);
  1034. HiveAddr = (ULONG_PTR)CmHive.SecurityCache;
  1035. dprintf("SecurityCache = : 0x%p\n\n",HiveAddr);
  1036. dprintf("[Entry No.] [Security Cell] [Security Cache]\n",CmHive.SecurityHitHint);
  1037. for( i=0;i<CmHive.SecurityCount;i++) {
  1038. ExitIfCtrlC();
  1039. if( !ReadMemory(HiveAddr,
  1040. &SecurityCacheEntry,
  1041. sizeof(SecurityCacheEntry),
  1042. &BytesRead) ) {
  1043. dprintf("\tCould not read entry %lu \n",i);
  1044. continue;
  1045. }
  1046. dprintf("%[%8lu] 0x%8lx 0x%p\n",i,SecurityCacheEntry.Cell,SecurityCacheEntry.CachedSecurity);
  1047. HiveAddr += sizeof(SecurityCacheEntry);
  1048. }
  1049. }
  1050. DECLARE_API( viewlist )
  1051. /*++
  1052. Routine Description:
  1053. dumps all the views mapped/pinned for the specified hive
  1054. Called as:
  1055. !viewlist <HiveAddr>
  1056. Arguments:
  1057. args - hive.
  1058. Return Value:
  1059. .
  1060. --*/
  1061. {
  1062. CMHIVE CmHive;
  1063. CM_VIEW_OF_FILE CmView;
  1064. ULONG_PTR HiveAddr;
  1065. DWORD BytesRead;
  1066. USHORT Nr;
  1067. ULONG Offset;
  1068. ULONG_PTR ViewAddr;
  1069. ULONG_PTR Tmp;
  1070. ULONG64 RecvAddr;
  1071. sscanf(args,"%I64lX",&RecvAddr);
  1072. HiveAddr = (ULONG_PTR)RecvAddr;
  1073. if( !ReadMemory(HiveAddr,
  1074. &CmHive,
  1075. sizeof(CmHive),
  1076. &BytesRead) ) {
  1077. dprintf("\tRead %lx bytes from %p\n",BytesRead,HiveAddr);
  1078. return;
  1079. }
  1080. if( CmHive.Hive.Signature != HHIVE_SIGNATURE ) {
  1081. dprintf("Invalid Hive signature: %lx\n",CmHive.Hive.Signature);
  1082. return;
  1083. }
  1084. Nr = CmHive.PinnedViews;
  1085. dprintf("%4u Pinned Views ; PinViewListHead = %p %p\n",Nr,(ULONG_PTR)CmHive.PinViewListHead.Flink,(ULONG_PTR)CmHive.PinViewListHead.Blink);
  1086. if( Nr ) {
  1087. dprintf("--------------------------------------------------------------------------------------------------------------\n");
  1088. dprintf("| ViewAddr |FileOffset| Size |ViewAddress| Bcb | LRUViewList | PinViewList | UseCount |\n");
  1089. dprintf("--------------------------------------------------------------------------------------------------------------\n");
  1090. ViewAddr = (ULONG_PTR)CmHive.PinViewListHead.Flink;
  1091. Offset = FIELD_OFFSET(CM_VIEW_OF_FILE, PinViewList);
  1092. for(;Nr;Nr--) {
  1093. ViewAddr -= Offset;
  1094. if( !ReadMemory(ViewAddr,
  1095. &CmView,
  1096. sizeof(CmView),
  1097. &BytesRead) ) {
  1098. dprintf("error reading view at %lx\n",ViewAddr);
  1099. break;
  1100. }
  1101. Tmp = ViewAddr;
  1102. dprintf("| %p ",Tmp);
  1103. dprintf("| %8lx ",CmView.FileOffset);
  1104. dprintf("| %8lx ",CmView.Size);
  1105. Tmp = (ULONG_PTR)CmView.ViewAddress;
  1106. dprintf("| %p ",Tmp);
  1107. Tmp = (ULONG_PTR)CmView.Bcb;
  1108. dprintf("| %p ",Tmp);
  1109. Tmp = (ULONG_PTR)CmView.LRUViewList.Flink;
  1110. dprintf("| %p",Tmp);
  1111. Tmp = (ULONG_PTR)CmView.LRUViewList.Blink;
  1112. dprintf(" %p ",Tmp);
  1113. Tmp = (ULONG_PTR)CmView.PinViewList.Flink;
  1114. dprintf("| %p",Tmp);
  1115. Tmp = (ULONG_PTR)CmView.PinViewList.Blink;
  1116. dprintf(" %p |",Tmp);
  1117. dprintf(" %8lx |\n",CmView.UseCount);
  1118. ViewAddr = (ULONG_PTR)CmView.PinViewList.Flink;
  1119. }
  1120. dprintf("--------------------------------------------------------------------------------------------------------------\n");
  1121. }
  1122. dprintf("\n");
  1123. Nr = CmHive.MappedViews;
  1124. dprintf("%4u Mapped Views ; LRUViewListHead = %p %p\n",Nr,(ULONG_PTR)CmHive.LRUViewListHead.Flink,(ULONG_PTR)CmHive.LRUViewListHead.Blink);
  1125. if( Nr ) {
  1126. dprintf("--------------------------------------------------------------------------------------------------------------\n");
  1127. dprintf("| ViewAddr |FileOffset| Size |ViewAddress| Bcb | LRUViewList | PinViewList | UseCount |\n");
  1128. dprintf("--------------------------------------------------------------------------------------------------------------\n");
  1129. ViewAddr = (ULONG_PTR)CmHive.LRUViewListHead.Flink;
  1130. Offset = FIELD_OFFSET(CM_VIEW_OF_FILE, LRUViewList);
  1131. for(;Nr;Nr--) {
  1132. ViewAddr -= Offset;
  1133. if( !ReadMemory(ViewAddr,
  1134. &CmView,
  1135. sizeof(CmView),
  1136. &BytesRead) ) {
  1137. dprintf("error reading view at %lx\n",ViewAddr);
  1138. break;
  1139. }
  1140. Tmp = ViewAddr;
  1141. dprintf("| %p ",Tmp);
  1142. dprintf("| %8lx ",CmView.FileOffset);
  1143. dprintf("| %8lx ",CmView.Size);
  1144. Tmp = (ULONG_PTR)CmView.ViewAddress;
  1145. dprintf("| %p ",Tmp);
  1146. Tmp = (ULONG_PTR)CmView.Bcb;
  1147. dprintf("| %p ",Tmp);
  1148. Tmp = (ULONG_PTR)CmView.LRUViewList.Flink;
  1149. dprintf("| %p",Tmp);
  1150. Tmp = (ULONG_PTR)CmView.LRUViewList.Blink;
  1151. dprintf(" %p ",Tmp);
  1152. Tmp = (ULONG_PTR)CmView.PinViewList.Flink;
  1153. dprintf("| %p",Tmp);
  1154. Tmp = (ULONG_PTR)CmView.PinViewList.Blink;
  1155. dprintf(" %8lx |",Tmp);
  1156. dprintf(" %8lx |\n",CmView.UseCount);
  1157. ViewAddr = (ULONG_PTR)CmView.LRUViewList.Flink;
  1158. }
  1159. dprintf("--------------------------------------------------------------------------------------------------------------\n");
  1160. }
  1161. dprintf("\n");
  1162. }
  1163. DECLARE_API( hivelist )
  1164. /*++
  1165. Routine Description:
  1166. dumps all the hives in the system
  1167. Called as:
  1168. !hivelist
  1169. Arguments:
  1170. Return Value:
  1171. .
  1172. --*/
  1173. {
  1174. CMHIVE CmHive;
  1175. ULONG_PTR HiveAddr;
  1176. ULONG_PTR AnchorAddr;
  1177. DWORD BytesRead;
  1178. ULONG Offset;
  1179. ULONG_PTR Tmp;
  1180. LIST_ENTRY CmpHiveListHead;
  1181. HBASE_BLOCK BaseBlock;
  1182. PWCHAR FileName;
  1183. AnchorAddr = GetExpression("CmpHiveListHead");
  1184. if( !ReadMemory(AnchorAddr,
  1185. &CmpHiveListHead,
  1186. sizeof(CmpHiveListHead),
  1187. &BytesRead)) {
  1188. dprintf("\ncannot read CmpHiveListHead\n");
  1189. return;
  1190. }
  1191. Offset = FIELD_OFFSET(CMHIVE, HiveList);
  1192. HiveAddr = (ULONG_PTR)CmpHiveListHead.Flink;
  1193. dprintf("-------------------------------------------------------------------------------------------------------------\n");
  1194. dprintf("| HiveAddr |Stable Length|Stable Map|Volatile Length|Volatile Map|MappedViews|PinnedViews|U(Cnt)| BaseBlock | FileName \n");
  1195. dprintf("-------------------------------------------------------------------------------------------------------------\n");
  1196. while( HiveAddr != AnchorAddr ) {
  1197. ExitIfCtrlC();
  1198. HiveAddr -= Offset;
  1199. if( !ReadMemory(HiveAddr,
  1200. &CmHive,
  1201. sizeof(CmHive),
  1202. &BytesRead) ) {
  1203. dprintf("cannot read hive at %lx\n",HiveAddr);
  1204. return;
  1205. }
  1206. if( CmHive.Hive.Signature != HHIVE_SIGNATURE ) {
  1207. dprintf("Invalid Hive signature: %lx\n",CmHive.Hive.Signature);
  1208. return;
  1209. }
  1210. Tmp = HiveAddr;
  1211. dprintf("| %p ",Tmp);
  1212. dprintf("| %8lx ",CmHive.Hive.Storage[0].Length);
  1213. Tmp = (ULONG_PTR)CmHive.Hive.Storage[0].Map;
  1214. dprintf("| %p ",Tmp);
  1215. dprintf("| %8lx ",CmHive.Hive.Storage[1].Length);
  1216. Tmp = (ULONG_PTR)CmHive.Hive.Storage[1].Map;
  1217. dprintf("| %p ",Tmp);
  1218. dprintf("| %8u ",CmHive.MappedViews);
  1219. dprintf("| %8u ",CmHive.PinnedViews);
  1220. dprintf("| %5u",CmHive.UseCount);
  1221. Tmp = (ULONG_PTR)CmHive.Hive.BaseBlock;
  1222. dprintf("| %p |",Tmp);
  1223. if( !ReadMemory(Tmp,
  1224. &BaseBlock,
  1225. sizeof(BaseBlock),
  1226. &BytesRead) ) {
  1227. dprintf(" could not read baseblock\n");
  1228. } else {
  1229. FileName = (PWCHAR)&(BaseBlock.FileName);
  1230. FileName[HBASE_NAME_ALLOC/sizeof(WCHAR)] = 0;
  1231. dprintf(" %ws\n",FileName);
  1232. }
  1233. HiveAddr = (ULONG_PTR)CmHive.HiveList.Flink;
  1234. }
  1235. dprintf("-------------------------------------------------------------------------------------------------------------\n");
  1236. dprintf("\n");
  1237. }
  1238. DECLARE_API( freebins )
  1239. /*++
  1240. Routine Description:
  1241. dumps all the free bins for the specified hive
  1242. Called as:
  1243. !freebins <HiveAddr>
  1244. Arguments:
  1245. args - hive.
  1246. Return Value:
  1247. .
  1248. --*/
  1249. {
  1250. HHIVE Hive;
  1251. ULONG_PTR HiveAddr;
  1252. DWORD BytesRead;
  1253. ULONG Offset;
  1254. ULONG_PTR BinAddr;
  1255. ULONG_PTR AnchorAddr;
  1256. ULONG_PTR Tmp;
  1257. USHORT Nr = 0;
  1258. FREE_HBIN FreeBin;
  1259. ULONG64 RecvAddr;
  1260. sscanf(args,"%I64lX",&RecvAddr);
  1261. HiveAddr = (ULONG_PTR)RecvAddr;
  1262. if( !ReadMemory(HiveAddr,
  1263. &Hive,
  1264. sizeof(Hive),
  1265. &BytesRead) ) {
  1266. dprintf("\tRead %lx bytes from %p\n",BytesRead,HiveAddr);
  1267. return;
  1268. }
  1269. if( Hive.Signature != HHIVE_SIGNATURE ) {
  1270. dprintf("Invalid Hive signature: %lx\n",Hive.Signature);
  1271. return;
  1272. }
  1273. Offset = FIELD_OFFSET(FREE_HBIN, ListEntry);
  1274. dprintf("Stable Storage ... \n");
  1275. dprintf("-------------------------------------------------------------------\n");
  1276. dprintf("| Address |FileOffset| Size | Flags | Flink | Blink |\n");
  1277. dprintf("-------------------------------------------------------------------\n");
  1278. Nr = 0;
  1279. AnchorAddr = HiveAddr + FIELD_OFFSET(HHIVE,Storage) + 5*sizeof(ULONG) + HHIVE_FREE_DISPLAY_SIZE*sizeof(RTL_BITMAP);
  1280. BinAddr = (ULONG_PTR)Hive.Storage[0].FreeBins.Flink;
  1281. while(BinAddr != AnchorAddr ) {
  1282. ExitIfCtrlC();
  1283. BinAddr -= Offset;
  1284. if( !ReadMemory(BinAddr,
  1285. &FreeBin,
  1286. sizeof(FreeBin),
  1287. &BytesRead)) {
  1288. dprintf("error reading FreeBin at %lx\n",BinAddr);
  1289. break;
  1290. }
  1291. Tmp = BinAddr;
  1292. dprintf("| %p ",Tmp);
  1293. dprintf("| %8lx ",FreeBin.FileOffset);
  1294. dprintf("| %8lx ",FreeBin.Size);
  1295. dprintf("| %8lx ",FreeBin.Flags);
  1296. Tmp = (ULONG_PTR)FreeBin.ListEntry.Flink;
  1297. dprintf("| %p ",Tmp);
  1298. Tmp = (ULONG_PTR)FreeBin.ListEntry.Blink;
  1299. dprintf("| %p |\n",Tmp);
  1300. BinAddr = (ULONG_PTR)FreeBin.ListEntry.Flink;
  1301. Nr++;
  1302. }
  1303. dprintf("-------------------------------------------------------------------\n");
  1304. dprintf("%4u FreeBins\n",Nr);
  1305. dprintf("\n");
  1306. dprintf("Volatile Storage ... \n");
  1307. dprintf("-------------------------------------------------------------------\n");
  1308. dprintf("| Address |FileOffset| Size | Flags | Flink | Blink |\n");
  1309. dprintf("-------------------------------------------------------------------\n");
  1310. Nr = 0;
  1311. AnchorAddr += (7*sizeof(ULONG) + HHIVE_FREE_DISPLAY_SIZE*sizeof(RTL_BITMAP));
  1312. BinAddr = (ULONG_PTR)Hive.Storage[1].FreeBins.Flink;
  1313. while(BinAddr != AnchorAddr ) {
  1314. ExitIfCtrlC();
  1315. BinAddr -= Offset;
  1316. if( !ReadMemory(BinAddr,
  1317. &FreeBin,
  1318. sizeof(FreeBin),
  1319. &BytesRead) ) {
  1320. dprintf("error reading FreeBin at %lx\n",BinAddr);
  1321. break;
  1322. }
  1323. Tmp = BinAddr;
  1324. dprintf("| %p ",Tmp);
  1325. dprintf("| %8lx ",FreeBin.FileOffset);
  1326. dprintf("| %8lx ",FreeBin.Size);
  1327. dprintf("| %8lx ",FreeBin.Flags);
  1328. Tmp = (ULONG_PTR)FreeBin.ListEntry.Flink;
  1329. dprintf("| %p ",Tmp);
  1330. Tmp = (ULONG_PTR)FreeBin.ListEntry.Blink;
  1331. dprintf("| %p |\n",Tmp);
  1332. BinAddr = (ULONG_PTR)FreeBin.ListEntry.Flink;
  1333. Nr++;
  1334. }
  1335. dprintf("-------------------------------------------------------------------\n");
  1336. dprintf("%4u FreeBins\n",Nr);
  1337. dprintf("\n");
  1338. }
  1339. DECLARE_API( dirtyvector )
  1340. /*++
  1341. Routine Description:
  1342. displays the dirty vector of the hive
  1343. Called as:
  1344. !dirtyvector <HiveAddr>
  1345. Arguments:
  1346. args - convkey.
  1347. Return Value:
  1348. .
  1349. --*/
  1350. {
  1351. HHIVE Hive;
  1352. ULONG_PTR HiveAddr;
  1353. DWORD BytesRead;
  1354. ULONG i;
  1355. ULONG_PTR Tmp;
  1356. ULONG SizeOfBitmap;
  1357. ULONG DirtyBuffer;
  1358. ULONG_PTR DirtyBufferAddr;
  1359. ULONG Mask;
  1360. ULONG BitsPerULONG;
  1361. ULONG BitsPerBlock;
  1362. ULONG64 RecvAddr;
  1363. sscanf(args,"%I64lX",&RecvAddr);
  1364. HiveAddr = (ULONG_PTR)RecvAddr;
  1365. if( !ReadMemory(HiveAddr,
  1366. &Hive,
  1367. sizeof(Hive),
  1368. &BytesRead)) {
  1369. dprintf("\tRead %lx bytes from %lx\n",BytesRead,HiveAddr);
  1370. return;
  1371. }
  1372. if( Hive.Signature != HHIVE_SIGNATURE ) {
  1373. dprintf("Invalid Hive signature: %lx\n",Hive.Signature);
  1374. return;
  1375. }
  1376. dprintf("HSECTOR_SIZE = %lx\n",HSECTOR_SIZE);
  1377. dprintf("HBLOCK_SIZE = %lx\n",HBLOCK_SIZE);
  1378. dprintf("PAGE_SIZE = %lx\n",PAGE_SIZE);
  1379. dprintf("\n");
  1380. dprintf("DirtyAlloc = : 0x%lx\n",Hive.DirtyAlloc);
  1381. dprintf("DirtyCount = : 0x%lx\n",Hive.DirtyCount);
  1382. Tmp = (ULONG_PTR)Hive.DirtyVector.Buffer;
  1383. dprintf("Buffer = : 0x%p\n",Tmp);
  1384. dprintf("\n");
  1385. SizeOfBitmap = Hive.DirtyVector.SizeOfBitMap;
  1386. DirtyBufferAddr = (ULONG_PTR)Hive.DirtyVector.Buffer;
  1387. BitsPerULONG = 8*sizeof(ULONG);
  1388. BitsPerBlock = HBLOCK_SIZE / HSECTOR_SIZE;
  1389. dprintf(" Address 32k 32k");
  1390. for(i=0;i<SizeOfBitmap;i++) {
  1391. ExitIfCtrlC();
  1392. if( !(i%(2*BitsPerULONG ) ) ){
  1393. dprintf("\n 0x%8lx ",i*HSECTOR_SIZE);
  1394. }
  1395. if( !(i%BitsPerBlock) ) {
  1396. dprintf(" ");
  1397. }
  1398. if( !(i%BitsPerULONG) ) {
  1399. //
  1400. // fetch in a new DWORD
  1401. //
  1402. if( !ReadMemory(DirtyBufferAddr,
  1403. &DirtyBuffer,
  1404. sizeof(DirtyBuffer),
  1405. &BytesRead)) {
  1406. dprintf("\tRead %lx bytes from %lx\n",BytesRead,DirtyBufferAddr);
  1407. return;
  1408. }
  1409. DirtyBufferAddr += sizeof(ULONG);
  1410. dprintf("\t");
  1411. }
  1412. Mask = ((DirtyBuffer >> (i%BitsPerULONG)) & 0x1);
  1413. //Mask <<= (BitsPerULONG - (i%BitsPerULONG) - 1);
  1414. //Mask &= DirtyBuffer;
  1415. dprintf("%s",Mask?"1":"0");
  1416. }
  1417. dprintf("\n\n");
  1418. }
  1419. CCHAR CmKDFindFirstSetLeft[256] = {
  1420. 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
  1421. 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
  1422. 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
  1423. 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
  1424. 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
  1425. 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
  1426. 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
  1427. 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
  1428. 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  1429. 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  1430. 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  1431. 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  1432. 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  1433. 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  1434. 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  1435. 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7};
  1436. #define CmKDComputeIndex(Index, Size) \
  1437. { \
  1438. Index = (Size >> HHIVE_FREE_DISPLAY_SHIFT) - 1; \
  1439. if (Index >= HHIVE_LINEAR_INDEX ) { \
  1440. \
  1441. /* \
  1442. ** Too big for the linear lists, compute the exponential \
  1443. ** list. \
  1444. */ \
  1445. \
  1446. if (Index > 255) { \
  1447. /* \
  1448. ** Too big for all the lists, use the last index. \
  1449. */ \
  1450. Index = HHIVE_FREE_DISPLAY_SIZE-1; \
  1451. } else { \
  1452. Index = CmKDFindFirstSetLeft[Index] + \
  1453. HHIVE_FREE_DISPLAY_BIAS; \
  1454. } \
  1455. } \
  1456. }
  1457. DECLARE_API( freecells )
  1458. /*++
  1459. Routine Description:
  1460. displays the free cells map in a bin
  1461. Called as:
  1462. !freecells <BinAddr>
  1463. Arguments:
  1464. args - convkey.
  1465. Return Value:
  1466. .
  1467. --*/
  1468. {
  1469. ULONG_PTR BinAddr;
  1470. ULONG Offset;
  1471. ULONG_PTR CurrentAddr;
  1472. LONG Current;
  1473. HBIN Bin;
  1474. ULONG Index;
  1475. ULONG CurrIndex;
  1476. DWORD BytesRead;
  1477. ULONG NrOfCellsPerIndex;
  1478. ULONG NrOfCellsTotal;
  1479. ULONG TotalFreeSize;
  1480. ULONG64 RecvAddr;
  1481. sscanf(args,"%I64lX",&RecvAddr);
  1482. BinAddr = (ULONG_PTR)RecvAddr;
  1483. if( !ReadMemory(BinAddr,
  1484. &Bin,
  1485. sizeof(Bin),
  1486. &BytesRead)) {
  1487. dprintf("\tRead %lx bytes from %lx\n",BytesRead,BinAddr);
  1488. return;
  1489. }
  1490. if( Bin.Signature != HBIN_SIGNATURE ) {
  1491. dprintf("\tInvalid Bin signature %lx \n",Bin.Signature);
  1492. return;
  1493. }
  1494. dprintf("Bin Offset = 0x%lx Size = 0x%lx\n",Bin.FileOffset,Bin.Size);
  1495. NrOfCellsTotal = 0;
  1496. TotalFreeSize = 0;
  1497. for(CurrIndex = 0;CurrIndex<HHIVE_FREE_DISPLAY_SIZE;CurrIndex++) {
  1498. dprintf("\n FreeDisplay[%2lu] :: ",CurrIndex);
  1499. NrOfCellsPerIndex = 0;
  1500. Offset = sizeof(Bin);
  1501. while( Offset < Bin.Size ) {
  1502. ExitIfCtrlC();
  1503. CurrentAddr = BinAddr + Offset;
  1504. if( !ReadMemory(CurrentAddr,
  1505. &Current,
  1506. sizeof(Current),
  1507. &BytesRead) ) {
  1508. dprintf("\tRead %lx bytes from %lx\n",BytesRead,CurrentAddr);
  1509. return;
  1510. }
  1511. if(Current>0) {
  1512. //
  1513. // free cell
  1514. //
  1515. CmKDComputeIndex(Index, Current);
  1516. if( Index == CurrIndex ) {
  1517. //
  1518. // dum it here as this is the right index
  1519. //
  1520. NrOfCellsTotal++;
  1521. NrOfCellsPerIndex++;
  1522. TotalFreeSize += Current;
  1523. dprintf(" %lx [%lx]",Offset,Current);
  1524. if( !(NrOfCellsPerIndex % 8) && ((Offset + Current) < Bin.Size) ) {
  1525. dprintf("\n");
  1526. }
  1527. }
  1528. } else {
  1529. Current *= -1;
  1530. }
  1531. Offset += Current;
  1532. }
  1533. }
  1534. dprintf("\nTotal: FreeCells = %lu, FreeSpace = 0x%lx BinUsage = %.2f%%\n",NrOfCellsTotal,TotalFreeSize,
  1535. (float)(((float)(Bin.Size-sizeof(Bin)-TotalFreeSize)/(float)(Bin.Size-sizeof(Bin)))*100.00)
  1536. );
  1537. }
  1538. DECLARE_API( freehints )
  1539. /*++
  1540. Routine Description:
  1541. displays the freehints information for the hive
  1542. Called as:
  1543. !freehints <HiveAddr>
  1544. Arguments:
  1545. args - convkey.
  1546. Return Value:
  1547. .
  1548. --*/
  1549. {
  1550. HHIVE Hive;
  1551. ULONG_PTR HiveAddr;
  1552. DWORD BytesRead;
  1553. ULONG i;
  1554. ULONG DisplayCount;
  1555. ULONG StorageCount;
  1556. ULONG SizeOfBitmap;
  1557. ULONG DirtyBuffer;
  1558. ULONG_PTR DirtyBufferAddr;
  1559. ULONG Mask;
  1560. ULONG BitsPerULONG;
  1561. ULONG BitsPerBlock;
  1562. ULONG BitsPerLine;
  1563. ULONG64 RecvAddr;
  1564. sscanf(args,"%I64lX %lu %lu",&RecvAddr,&StorageCount,&DisplayCount);
  1565. HiveAddr = (ULONG_PTR)RecvAddr;
  1566. if( !ReadMemory(HiveAddr,
  1567. &Hive,
  1568. sizeof(Hive),
  1569. &BytesRead) ) {
  1570. dprintf("\tRead %lx bytes from %lx\n",BytesRead,HiveAddr);
  1571. return;
  1572. }
  1573. if( Hive.Signature != HHIVE_SIGNATURE ) {
  1574. dprintf("Invalid Hive signature: %lx\n",Hive.Signature);
  1575. return;
  1576. }
  1577. dprintf("HSECTOR_SIZE = %lx\n",HSECTOR_SIZE);
  1578. dprintf("HBLOCK_SIZE = %lx\n",HBLOCK_SIZE);
  1579. dprintf("PAGE_SIZE = %lx\n",PAGE_SIZE);
  1580. dprintf("\n");
  1581. BitsPerULONG = 8*sizeof(ULONG);
  1582. BitsPerBlock = 0x10000 / HBLOCK_SIZE; // 64k blocks
  1583. BitsPerLine = 0x40000 / HBLOCK_SIZE; // 256k lines (vicinity reasons)
  1584. SizeOfBitmap = Hive.Storage[StorageCount].Length / HBLOCK_SIZE;
  1585. DirtyBufferAddr = (ULONG_PTR)Hive.Storage[StorageCount].FreeDisplay[DisplayCount].Buffer;
  1586. dprintf("Storage = %s , FreeDisplay[%lu]: \n",StorageCount?"Volatile":"Stable",DisplayCount);
  1587. dprintf("\n%8s %16s %16s %16s %16s","Address","64K (0x10000)","64K (0x10000)","64K (0x10000)","64K (0x10000)");
  1588. for(i=0;i<SizeOfBitmap;i++) {
  1589. ExitIfCtrlC();
  1590. if( !(i%BitsPerLine) ){
  1591. dprintf("\n 0x%8lx ",i*HBLOCK_SIZE);
  1592. }
  1593. if( !(i%BitsPerBlock) ) {
  1594. dprintf(" ");
  1595. }
  1596. if( !(i%BitsPerULONG) ) {
  1597. //
  1598. // fetch in a new DWORD
  1599. //
  1600. if( !ReadMemory(DirtyBufferAddr,
  1601. &DirtyBuffer,
  1602. sizeof(DirtyBuffer),
  1603. &BytesRead) ) {
  1604. dprintf("\tRead %lx bytes from %lx\n",BytesRead,DirtyBufferAddr);
  1605. return;
  1606. }
  1607. DirtyBufferAddr += sizeof(ULONG);
  1608. }
  1609. Mask = ((DirtyBuffer >> (i%BitsPerULONG)) & 0x1);
  1610. //Mask <<= (BitsPerULONG - (i%BitsPerULONG) - 1);
  1611. //Mask &= DirtyBuffer;
  1612. dprintf("%s",Mask?"1":"0");
  1613. }
  1614. dprintf("\n\n");
  1615. }
  1616. DECLARE_API( help )
  1617. /*++
  1618. Routine Description:
  1619. Called as:
  1620. !help
  1621. Arguments:
  1622. Return Value:
  1623. .
  1624. --*/
  1625. {
  1626. dprintf("\nkcb\t\t<kcb_address>\n"); //OK, moved to kdexts
  1627. dprintf("knode\t\t<knode_address>\n");//OK, moved to kdexts
  1628. dprintf("kbody\t\t<kbody_address>\n");//OK, moved to kdexts
  1629. dprintf("kvalue\t\t<kvalue_address>\n");//OK, moved to kdexts
  1630. dprintf("cellindex\t<HiveAddr> <HCELL_INDEX>\n"); //OK, moved to kdexts
  1631. dprintf("childlist\t<address>\n");// not worth moving, never used it
  1632. dprintf("hashindex\t<ConvKey>\n");//OK, moved to kdexts
  1633. dprintf("openkeys\t<HiveAddr|0>\n");//OK, moved to kdexts
  1634. dprintf("baseblock\t<BaseBlockAddr>\n");//OK, moved to kdexts
  1635. dprintf("findkcb\t\t<FullKeyPath>\n");//OK, moved to kdexts
  1636. dprintf("seccache\t<HiveAddr>\n");//OK, moved to kdexts
  1637. dprintf("viewlist\t<HiveAddr>\n");//OK, moved to kdexts
  1638. dprintf("hivelist\n");//OK, moved to kdexts
  1639. dprintf("freebins\t<HiveAddr>\n");//OK, moved to kdexts
  1640. dprintf("dirtyvector\t<HiveAddr>\n");//OK, moved to kdexts
  1641. dprintf("freecells\t<BinAddr>\n");//OK, moved to kdexts
  1642. dprintf("freehints\t<HiveAddr> <Storage> <Display>\n");//OK, moved to kdexts
  1643. dprintf("help\t\tThis screen\n\n");
  1644. return;
  1645. }