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.

3746 lines
107 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. NtfsKd.c
  5. Abstract:
  6. KD Extension Api for examining Ntfs specific data structures
  7. Author:
  8. Keith Kaplan [KeithKa] 24-Apr-1996
  9. Portions by Jeff Havens
  10. Ported to IA64 (wesw) 5-Aug-2000
  11. Environment:
  12. User Mode.
  13. Revision History:
  14. --*/
  15. #include "pch.h"
  16. #undef FlagOn
  17. #undef WordAlign
  18. #undef LongAlign
  19. #undef QuadAlign
  20. #undef DebugPrint
  21. #undef MAXULONGLONG
  22. #define KDEXT
  23. #include "gentable.h"
  24. #undef DebugTrace
  25. #include <cc.h>
  26. #undef UpdateSequenceStructureSize
  27. #undef UpdateSequenceArraySize
  28. #include <lfsdisk.h>
  29. #pragma hdrstop
  30. #define AVERAGE(TOTAL,COUNT) ((COUNT) != 0 ? (TOTAL)/(COUNT) : 0)
  31. const UCHAR FileSignature[4] = {'F', 'I', 'L', 'E'};
  32. VOID
  33. ResetFileSystemStatistics (
  34. IN ULONG64 VcbAddress,
  35. IN USHORT Processor,
  36. IN HANDLE hCurrentThread
  37. );
  38. VOID
  39. DumpFileSystemStatistics (
  40. IN ULONG64 VcbAddress,
  41. IN USHORT Processor,
  42. IN HANDLE hCurrentThread
  43. );
  44. /*
  45. * Dump structures
  46. */
  47. typedef struct _STATE {
  48. ULONG mask;
  49. ULONG value;
  50. CHAR *pszname;
  51. } STATE;
  52. STATE CcbState[] = {
  53. { CCB_FLAG_IGNORE_CASE, CCB_FLAG_IGNORE_CASE, "IgnoreCase"},
  54. { CCB_FLAG_OPEN_AS_FILE, CCB_FLAG_OPEN_AS_FILE, "OpenAsFile"},
  55. { CCB_FLAG_WILDCARD_IN_EXPRESSION, CCB_FLAG_WILDCARD_IN_EXPRESSION, "WildcardInExpression"},
  56. { CCB_FLAG_OPEN_BY_FILE_ID, CCB_FLAG_OPEN_BY_FILE_ID, "OpenByFileId"},
  57. { CCB_FLAG_USER_SET_LAST_MOD_TIME, CCB_FLAG_USER_SET_LAST_MOD_TIME, "SetLastModTime"},
  58. { CCB_FLAG_USER_SET_LAST_CHANGE_TIME, CCB_FLAG_USER_SET_LAST_CHANGE_TIME, "SetLastChangeTime"},
  59. { CCB_FLAG_USER_SET_LAST_ACCESS_TIME, CCB_FLAG_USER_SET_LAST_ACCESS_TIME, "SetLastAccessTime"},
  60. { CCB_FLAG_TRAVERSE_CHECK, CCB_FLAG_TRAVERSE_CHECK, "TraverseCheck"},
  61. { CCB_FLAG_RETURN_DOT, CCB_FLAG_RETURN_DOT, "ReturnDot"},
  62. { CCB_FLAG_RETURN_DOTDOT, CCB_FLAG_RETURN_DOTDOT, "ReturnDotDot"},
  63. { CCB_FLAG_DOT_RETURNED, CCB_FLAG_DOT_RETURNED, "DotReturned"},
  64. { CCB_FLAG_DOTDOT_RETURNED, CCB_FLAG_DOTDOT_RETURNED, "DotDotReturned"},
  65. { CCB_FLAG_DELETE_FILE, CCB_FLAG_DELETE_FILE, "DeleteFile"},
  66. { CCB_FLAG_DENY_DELETE, CCB_FLAG_DENY_DELETE, "DenyDelete"},
  67. { CCB_FLAG_ALLOCATED_FILE_NAME, CCB_FLAG_ALLOCATED_FILE_NAME, "AllocatedFileName"},
  68. { CCB_FLAG_CLEANUP, CCB_FLAG_CLEANUP, "Cleanup"},
  69. { CCB_FLAG_SYSTEM_HIVE, CCB_FLAG_SYSTEM_HIVE, "SystemHive"},
  70. { CCB_FLAG_PARENT_HAS_DOS_COMPONENT, CCB_FLAG_PARENT_HAS_DOS_COMPONENT, "ParentHasDosComponent"},
  71. { CCB_FLAG_DELETE_ON_CLOSE, CCB_FLAG_DELETE_ON_CLOSE, "DeleteOnClose"},
  72. { CCB_FLAG_CLOSE, CCB_FLAG_CLOSE, "Close"},
  73. { CCB_FLAG_UPDATE_LAST_MODIFY, CCB_FLAG_UPDATE_LAST_MODIFY, "UpdateLastModify"},
  74. { CCB_FLAG_UPDATE_LAST_CHANGE, CCB_FLAG_UPDATE_LAST_CHANGE, "UpdateLastChange"},
  75. { CCB_FLAG_SET_ARCHIVE, CCB_FLAG_SET_ARCHIVE, "SetArchive"},
  76. { CCB_FLAG_DIR_NOTIFY, CCB_FLAG_DIR_NOTIFY, "DirNotify"},
  77. { CCB_FLAG_ALLOW_XTENDED_DASD_IO, CCB_FLAG_ALLOW_XTENDED_DASD_IO, "AllowExtendedDasdIo"},
  78. { CCB_FLAG_READ_CONTEXT_ALLOCATED, CCB_FLAG_READ_CONTEXT_ALLOCATED, "ReadContextAllocated"},
  79. { CCB_FLAG_DELETE_ACCESS, CCB_FLAG_DELETE_ACCESS, "DeleteAccess"},
  80. { 0 }
  81. };
  82. STATE FcbState[] = {
  83. { FCB_STATE_FILE_DELETED, FCB_STATE_FILE_DELETED, "FileDeleted" },
  84. { FCB_STATE_NONPAGED, FCB_STATE_NONPAGED, "Nonpaged" },
  85. { FCB_STATE_PAGING_FILE, FCB_STATE_PAGING_FILE, "PagingFile" },
  86. { FCB_STATE_DUP_INITIALIZED, FCB_STATE_DUP_INITIALIZED, "DupInitialized" },
  87. { FCB_STATE_UPDATE_STD_INFO, FCB_STATE_UPDATE_STD_INFO, "UpdateStdInfo" },
  88. { FCB_STATE_PRIMARY_LINK_DELETED, FCB_STATE_PRIMARY_LINK_DELETED, "PrimaryLinkDeleted" },
  89. { FCB_STATE_IN_FCB_TABLE, FCB_STATE_IN_FCB_TABLE, "InFcbTable" },
  90. { FCB_STATE_SYSTEM_FILE, FCB_STATE_SYSTEM_FILE, "SystemFile" },
  91. { FCB_STATE_COMPOUND_DATA, FCB_STATE_COMPOUND_DATA, "CompoundData" },
  92. { FCB_STATE_COMPOUND_INDEX, FCB_STATE_COMPOUND_INDEX, "CompoundIndex" },
  93. { FCB_STATE_LARGE_STD_INFO, FCB_STATE_LARGE_STD_INFO, "LargeStdInfo" },
  94. { FCB_STATE_MODIFIED_SECURITY, FCB_STATE_MODIFIED_SECURITY, "ModifiedSecurity" },
  95. { FCB_STATE_DIRECTORY_ENCRYPTED, FCB_STATE_DIRECTORY_ENCRYPTED, "DirectoryEncrypted" },
  96. { FCB_STATE_VALID_USN_NAME, FCB_STATE_VALID_USN_NAME, "ValidUsnName" },
  97. { FCB_STATE_USN_JOURNAL, FCB_STATE_USN_JOURNAL, "UsnJournal" },
  98. { FCB_STATE_ENCRYPTION_PENDING, FCB_STATE_ENCRYPTION_PENDING, "EncryptionPending" },
  99. { 0 }
  100. };
  101. STATE NtfsFlags[] = {
  102. { NTFS_FLAGS_SMALL_SYSTEM, NTFS_FLAGS_SMALL_SYSTEM, "SmallSystem" },
  103. { NTFS_FLAGS_MEDIUM_SYSTEM, NTFS_FLAGS_MEDIUM_SYSTEM, "MediumSystem" },
  104. { NTFS_FLAGS_LARGE_SYSTEM, NTFS_FLAGS_LARGE_SYSTEM, "LargeSystem" },
  105. { NTFS_FLAGS_CREATE_8DOT3_NAMES, NTFS_FLAGS_CREATE_8DOT3_NAMES, "Create8dot3names" },
  106. { NTFS_FLAGS_ALLOW_EXTENDED_CHAR, NTFS_FLAGS_ALLOW_EXTENDED_CHAR, "AllowExtendedChar" },
  107. { NTFS_FLAGS_DISABLE_LAST_ACCESS, NTFS_FLAGS_DISABLE_LAST_ACCESS, "DisableLastAccess" },
  108. { NTFS_FLAGS_ENCRYPTION_DRIVER, NTFS_FLAGS_ENCRYPTION_DRIVER, "EncryptionDriver" },
  109. { 0 }
  110. };
  111. STATE ScbState[] = {
  112. { SCB_STATE_TRUNCATE_ON_CLOSE, SCB_STATE_TRUNCATE_ON_CLOSE, "TruncateOnClose" },
  113. { SCB_STATE_DELETE_ON_CLOSE, SCB_STATE_DELETE_ON_CLOSE, "DeleteOnClose" },
  114. { SCB_STATE_CHECK_ATTRIBUTE_SIZE, SCB_STATE_CHECK_ATTRIBUTE_SIZE, "CheckAttributeSize" },
  115. { SCB_STATE_ATTRIBUTE_RESIDENT, SCB_STATE_ATTRIBUTE_RESIDENT, "AttributeResident" },
  116. { SCB_STATE_UNNAMED_DATA, SCB_STATE_UNNAMED_DATA, "UnnamedData" },
  117. { SCB_STATE_HEADER_INITIALIZED, SCB_STATE_HEADER_INITIALIZED, "HeaderInitialized" },
  118. { SCB_STATE_NONPAGED, SCB_STATE_NONPAGED, "Nonpaged" },
  119. { SCB_STATE_USA_PRESENT, SCB_STATE_USA_PRESENT, "UsaPresent" },
  120. { SCB_STATE_ATTRIBUTE_DELETED, SCB_STATE_ATTRIBUTE_DELETED, "AttributeDeleted" },
  121. { SCB_STATE_FILE_SIZE_LOADED, SCB_STATE_FILE_SIZE_LOADED, "FileSizeLoaded" },
  122. { SCB_STATE_MODIFIED_NO_WRITE, SCB_STATE_MODIFIED_NO_WRITE, "ModifiedNoWrite" },
  123. { SCB_STATE_SUBJECT_TO_QUOTA, SCB_STATE_SUBJECT_TO_QUOTA, "SubjectToQuota" },
  124. { SCB_STATE_UNINITIALIZE_ON_RESTORE, SCB_STATE_UNINITIALIZE_ON_RESTORE, "UninitializeOnRestore" },
  125. { SCB_STATE_RESTORE_UNDERWAY, SCB_STATE_RESTORE_UNDERWAY, "RestoreUnderway" },
  126. { SCB_STATE_NOTIFY_ADD_STREAM, SCB_STATE_NOTIFY_ADD_STREAM, "NotifyAddStream" },
  127. { SCB_STATE_NOTIFY_REMOVE_STREAM, SCB_STATE_NOTIFY_REMOVE_STREAM, "NotifyRemoveStream" },
  128. { SCB_STATE_NOTIFY_RESIZE_STREAM, SCB_STATE_NOTIFY_RESIZE_STREAM, "NotifyResizeStream" },
  129. { SCB_STATE_NOTIFY_MODIFY_STREAM, SCB_STATE_NOTIFY_MODIFY_STREAM, "NotifyModifyStream" },
  130. { SCB_STATE_TEMPORARY, SCB_STATE_TEMPORARY, "Temporary" },
  131. { SCB_STATE_WRITE_COMPRESSED, SCB_STATE_WRITE_COMPRESSED, "Compressed" },
  132. { SCB_STATE_REALLOCATE_ON_WRITE, SCB_STATE_REALLOCATE_ON_WRITE, "DeallocateOnWrite" },
  133. { SCB_STATE_DELAY_CLOSE, SCB_STATE_DELAY_CLOSE, "DelayClose" },
  134. { SCB_STATE_WRITE_ACCESS_SEEN, SCB_STATE_WRITE_ACCESS_SEEN, "WriteAccessSeen" },
  135. { SCB_STATE_CONVERT_UNDERWAY, SCB_STATE_CONVERT_UNDERWAY, "ConvertUnderway" },
  136. { SCB_STATE_VIEW_INDEX, SCB_STATE_VIEW_INDEX, "ViewIndex" },
  137. { SCB_STATE_DELETE_COLLATION_DATA, SCB_STATE_DELETE_COLLATION_DATA, "DeleteCollationData" },
  138. { SCB_STATE_VOLUME_DISMOUNTED, SCB_STATE_VOLUME_DISMOUNTED, "VolumeDismounted" },
  139. { SCB_STATE_PROTECT_SPARSE_MCB, SCB_STATE_PROTECT_SPARSE_MCB, "ProtectSparseMcb" },
  140. { SCB_STATE_MULTIPLE_OPENS, SCB_STATE_MULTIPLE_OPENS, "MultipleOpens" },
  141. { 0 }
  142. };
  143. STATE ScbPersist[] = {
  144. { SCB_PERSIST_USN_JOURNAL, SCB_PERSIST_USN_JOURNAL, "UsnJournal" },
  145. { 0 }
  146. };
  147. STATE VcbState[] = {
  148. { VCB_STATE_VOLUME_MOUNTED, VCB_STATE_VOLUME_MOUNTED, "Mounted" },
  149. { VCB_STATE_LOCKED, VCB_STATE_LOCKED, "Locked" },
  150. { VCB_STATE_REMOVABLE_MEDIA, VCB_STATE_REMOVABLE_MEDIA, "RemovableMedia" },
  151. { VCB_STATE_VOLUME_MOUNTED_DIRTY, VCB_STATE_VOLUME_MOUNTED_DIRTY, "MountedDirty" },
  152. { VCB_STATE_RESTART_IN_PROGRESS, VCB_STATE_RESTART_IN_PROGRESS, "RestartInProgress" },
  153. { VCB_STATE_FLAG_SHUTDOWN, VCB_STATE_FLAG_SHUTDOWN, "FlagShutdown" },
  154. { VCB_STATE_NO_SECONDARY_AVAILABLE, VCB_STATE_NO_SECONDARY_AVAILABLE, "NoSecondaryAvailable" },
  155. { VCB_STATE_RELOAD_FREE_CLUSTERS, VCB_STATE_RELOAD_FREE_CLUSTERS, "ReloadFreeClusters" },
  156. { VCB_STATE_PRELOAD_MFT, VCB_STATE_PRELOAD_MFT, "PreloadMft" },
  157. { VCB_STATE_VOL_PURGE_IN_PROGRESS, VCB_STATE_VOL_PURGE_IN_PROGRESS, "VolPurgeInProgress" },
  158. { VCB_STATE_TEMP_VPB, VCB_STATE_TEMP_VPB, "TempVpb" },
  159. { VCB_STATE_PERFORMED_DISMOUNT, VCB_STATE_PERFORMED_DISMOUNT, "PerformedDismount" },
  160. { VCB_STATE_VALID_LOG_HANDLE, VCB_STATE_VALID_LOG_HANDLE, "ValidLogHandle" },
  161. { VCB_STATE_DELETE_UNDERWAY, VCB_STATE_DELETE_UNDERWAY, "DeleteUnderway" },
  162. { VCB_STATE_REDUCED_MFT, VCB_STATE_REDUCED_MFT, "ReducedMft" },
  163. { VCB_STATE_EXPLICIT_LOCK, VCB_STATE_EXPLICIT_LOCK, "ExplicitLock" },
  164. { VCB_STATE_DISALLOW_DISMOUNT, VCB_STATE_DISALLOW_DISMOUNT, "DisallowDismount" },
  165. { VCB_STATE_VALID_OBJECT_ID, VCB_STATE_VALID_OBJECT_ID, "ValidObjectId" },
  166. { VCB_STATE_OBJECT_ID_CLEANUP, VCB_STATE_OBJECT_ID_CLEANUP, "ObjectIdCleanup" },
  167. { VCB_STATE_USN_DELETE, VCB_STATE_USN_DELETE, "UsnDelete" },
  168. { VCB_STATE_USN_JOURNAL_PRESENT, VCB_STATE_USN_JOURNAL_PRESENT, "UsnJournalPresent" },
  169. { VCB_STATE_EXPLICIT_DISMOUNT, VCB_STATE_EXPLICIT_DISMOUNT, "ExplicitDismount" },
  170. { 0 }
  171. };
  172. STATE LcbState[] = {
  173. { LCB_STATE_DELETE_ON_CLOSE, LCB_STATE_DELETE_ON_CLOSE, "DeleteOnClose" },
  174. { LCB_STATE_LINK_IS_GONE, LCB_STATE_LINK_IS_GONE, "LinkIsGone" },
  175. { LCB_STATE_EXACT_CASE_IN_TREE, LCB_STATE_EXACT_CASE_IN_TREE, "ExactCaseInTree" },
  176. { LCB_STATE_IGNORE_CASE_IN_TREE, LCB_STATE_IGNORE_CASE_IN_TREE, "IgnoreCaseInTree" },
  177. { LCB_STATE_DESIGNATED_LINK, LCB_STATE_DESIGNATED_LINK, "DesignatedLink" },
  178. { LCB_STATE_VALID_HASH_VALUE, LCB_STATE_VALID_HASH_VALUE, "ValidHashValue" },
  179. { 0 }
  180. };
  181. char* LogOperation[] = {
  182. { "Noop " },
  183. { "CompensationLogRecord " },
  184. { "InitializeFileRecordSegment " },
  185. { "DeallocateFileRecordSegment " },
  186. { "WriteEndOfFileRecordSegment " },
  187. { "CreateAttribute " },
  188. { "DeleteAttribute " },
  189. { "UpdateResidentValue " },
  190. { "UpdateNonresidentValue " },
  191. { "UpdateMappingPairs " },
  192. { "DeleteDirtyClusters " },
  193. { "SetNewAttributeSizes " },
  194. { "AddIndexEntryRoot " },
  195. { "DeleteIndexEntryRoot " },
  196. { "AddIndexEntryAllocation " },
  197. { "DeleteIndexEntryAllocation " },
  198. { "WriteEndOfIndexBuffer " },
  199. { "SetIndexEntryVcnRoot " },
  200. { "SetIndexEntryVcnAllocation " },
  201. { "UpdateFileNameRoot " },
  202. { "UpdateFileNameAllocation " },
  203. { "SetBitsInNonresidentBitMap " },
  204. { "ClearBitsInNonresidentBitMap " },
  205. { "HotFix " },
  206. { "EndTopLevelAction " },
  207. { "PrepareTransaction " },
  208. { "CommitTransaction " },
  209. { "ForgetTransaction " },
  210. { "OpenNonresidentAttribute " },
  211. { "OpenAttributeTableDump " },
  212. { "AttributeNamesDump " },
  213. { "DirtyPageTableDump " },
  214. { "TransactionTableDump " },
  215. { "UpdateRecordDataRoot " },
  216. { "UpdateRecordDataAllocation " }
  217. };
  218. #define LastLogOperation 0x22
  219. char* AttributeTypeCode[] = {
  220. { "$UNUSED " }, // (0X0)
  221. { "$STANDARD_INFORMATION " }, // (0x10)
  222. { "$ATTRIBUTE_LIST " }, // (0x20)
  223. { "$FILE_NAME " }, // (0x30)
  224. { "$OBJECT_ID " }, // (0x40)
  225. { "$SECURITY_DESCRIPTOR " }, // (0x50)
  226. { "$VOLUME_NAME " }, // (0x60)
  227. { "$VOLUME_INFORMATION " }, // (0x70)
  228. { "$DATA " }, // (0x80)
  229. { "$INDEX_ROOT " }, // (0x90)
  230. { "$INDEX_ALLOCATION " }, // (0xA0)
  231. { "$BITMAP " }, // (0xB0)
  232. { "$REPARSE_POINT " }, // (0xC0)
  233. { "$EA_INFORMATION " }, // (0xD0)
  234. { "$EA " }, // (0xE0)
  235. { " INVALID TYPE CODE " }, // (0xF0)
  236. { "$LOGGED_UTILITY_STREAM " } // (0x100)
  237. };
  238. char * LogEvent[] =
  239. {
  240. "SCE_VDL_CHANGE",
  241. "SCE_ZERO_NC",
  242. "SCE_ZERO_C",
  243. "SCE_READ",
  244. "SCE_WRITE",
  245. "SCE_ZERO_CAV",
  246. "SCE_ZERO_MF",
  247. "SCE_ZERO_FST",
  248. "SCE_CC_FLUSH",
  249. "SCE_CC_FLUSH_AND_PURGE",
  250. "SCE_WRITE_FILE_SIZES",
  251. "SCE_ADD_ALLOCATION",
  252. "SCE_ADD_SP_ALLOCATION",
  253. "SCE_SETCOMP_ADD_ALLOCATION",
  254. "SCE_SETSPARSE_ADD_ALLOCATION",
  255. "SCE_MOD_ATTR_ADD_ALLOCATION",
  256. "SCE_REALLOC1",
  257. "SCE_REALLOC2",
  258. "SCE_REALLOC3",
  259. "SCE_SETCOMPRESS",
  260. "SCE_SETSPARSE",
  261. "SCE_ZERO_STREAM",
  262. "SCE_VDD_CHANGE",
  263. "SCE_CC_SET_SIZE",
  264. "SCE_ZERO_C_TAIL_COMPRESSION",
  265. "SCE_ZERO_C_HEAD_COMPRESSION",
  266. "SCE_MAX_EVENT"
  267. };
  268. struct {
  269. NODE_TYPE_CODE TypeCode;
  270. char *Text;
  271. } NodeTypeCodes[] = {
  272. { NTFS_NTC_DATA_HEADER, "Data Header" },
  273. { NTFS_NTC_VCB, "Vcb" },
  274. { NTFS_NTC_FCB, "Fcb" },
  275. { NTFS_NTC_SCB_INDEX, "ScbIndex" },
  276. { NTFS_NTC_SCB_ROOT_INDEX, "ScbRootIndex" },
  277. { NTFS_NTC_SCB_DATA, "ScbData" },
  278. { NTFS_NTC_SCB_MFT, "ScbMft" },
  279. { NTFS_NTC_SCB_NONPAGED, "ScbNonPaged" },
  280. { NTFS_NTC_CCB_INDEX, "CcbIndex" },
  281. { NTFS_NTC_CCB_DATA, "CcbData" },
  282. { NTFS_NTC_IRP_CONTEXT, "IrpContext" },
  283. { NTFS_NTC_LCB, "Lcb" },
  284. { NTFS_NTC_PREFIX_ENTRY, "PrefixEntry" },
  285. { NTFS_NTC_QUOTA_CONTROL, "QuotaControl" },
  286. { NTFS_NTC_USN_RECORD, "UsnRecord" },
  287. { 0, "Unknown" }
  288. };
  289. ULONG
  290. MyGetFieldData(
  291. IN ULONG64 TypeAddress,
  292. IN PUCHAR Type,
  293. IN PUCHAR Field,
  294. IN ULONG OutSize,
  295. OUT PULONG64 pOutValue,
  296. OUT PULONG64 pOutAddress
  297. )
  298. /*++
  299. Routine Description:
  300. Retrieves the symbol information for a field within a structure.
  301. Arguments:
  302. TypeAddress - Virtual address of the structure
  303. Type - Qualified type string
  304. Field - Field name
  305. OutSize - Size of the field
  306. pOutValue - Value of the vield
  307. pOutAddress - Virtual address of the field
  308. Return Value:
  309. Zero is success otherwise failure.
  310. --*/
  311. {
  312. ULONG RetVal = 0;
  313. FIELD_INFO flds = {
  314. Field,
  315. NULL,
  316. OutSize,
  317. DBG_DUMP_FIELD_FULL_NAME | DBG_DUMP_FIELD_COPY_FIELD_DATA | DBG_DUMP_FIELD_RETURN_ADDRESS,
  318. 0,
  319. pOutValue
  320. };
  321. SYM_DUMP_PARAM Sym = {
  322. sizeof(SYM_DUMP_PARAM),
  323. Type,
  324. DBG_DUMP_NO_PRINT,
  325. TypeAddress,
  326. NULL,
  327. NULL,
  328. NULL,
  329. 1,
  330. &flds
  331. };
  332. ZeroMemory( pOutValue, OutSize );
  333. RetVal = Ioctl( IG_DUMP_SYMBOL_INFO, &Sym, Sym.size );
  334. if (OutSize < flds.size) {
  335. if (OutSize == sizeof(ULONG64)) {
  336. *pOutValue = Sym.Fields->address;
  337. } else {
  338. memset( pOutValue, 0, OutSize );
  339. }
  340. }
  341. if (pOutAddress) {
  342. if (RetVal == 0) {
  343. *pOutAddress = Sym.Fields->address;
  344. } else {
  345. *pOutAddress = 0;
  346. }
  347. }
  348. return RetVal;
  349. }
  350. VOID
  351. DumpValue(
  352. IN ULONG64 Address,
  353. IN PCHAR Type,
  354. IN PCHAR Field
  355. )
  356. /*++
  357. Routine Description:
  358. Prints the value of a 64/32 bit value based on
  359. a symbol name and address.
  360. Arguments:
  361. Address - Virtual address of the value
  362. Type - Qualified type string
  363. Field - Field name
  364. Return Value:
  365. None.
  366. --*/
  367. {
  368. static ULONG64 ValueBuffer[128];
  369. ULONG64 Value,OutputAddress;
  370. if (MyGetFieldData( Address, Type, Field, sizeof(Value), (PVOID)ValueBuffer, &OutputAddress )) {
  371. Value = 0;
  372. } else {
  373. Value = ValueBuffer[0];
  374. }
  375. dprintf( "\n(%03x) ", (ULONG)(OutputAddress-Address) );
  376. dprintf( " %s", FormatValue(Value) );
  377. dprintf( " %s ", Field );
  378. }
  379. VOID
  380. DumpPtrValue(
  381. IN ULONG64 Address,
  382. IN PCHAR TextStr
  383. )
  384. /*++
  385. Routine Description:
  386. Prints the value of a pointer.
  387. Arguments:
  388. Address - Virtual address of the value
  389. TextStr - Tag to print with the pointer value
  390. Return Value:
  391. None.
  392. --*/
  393. {
  394. ULONG64 PtrValue;
  395. ULONG BytesRead;
  396. if (ReadMemory( Address, &PtrValue, sizeof(PtrValue), &BytesRead )) {
  397. dprintf( "\n %s %s", FormatValue(PtrValue), TextStr );
  398. }
  399. }
  400. ULONG64
  401. ReadValue(
  402. IN ULONG64 Address,
  403. IN PCHAR Type,
  404. IN PCHAR Field
  405. )
  406. /*++
  407. Routine Description:
  408. Reads the value of a 64/32 bit value
  409. Arguments:
  410. Address - Virtual address of the value
  411. Type - Qualified type string
  412. Field - Field name
  413. Return Value:
  414. The 64/32 bit value or zero.
  415. --*/
  416. {
  417. static ULONG64 ValueBuffer[128];
  418. ULONG64 Value,OutputAddress;
  419. if (MyGetFieldData( Address, Type, Field, sizeof(Value), (PVOID)ValueBuffer, &OutputAddress )) {
  420. Value = 0;
  421. } else {
  422. Value = ValueBuffer[0];
  423. }
  424. return Value;
  425. }
  426. ULONG
  427. ReadUlongValue(
  428. IN ULONG64 Address,
  429. IN PCHAR Type,
  430. IN PCHAR Field
  431. )
  432. /*++
  433. Routine Description:
  434. Reads the value of a 32 bit value
  435. Arguments:
  436. Address - Virtual address of the value
  437. Type - Qualified type string
  438. Field - Field name
  439. Return Value:
  440. The 32 bit value or zero.
  441. --*/
  442. {
  443. static ULONG ValueBuffer[128];
  444. ULONG Value;
  445. ULONG64 OutputAddress;
  446. if (MyGetFieldData( Address, Type, Field, sizeof(Value), (PVOID)ValueBuffer, &OutputAddress )) {
  447. Value = 0;
  448. } else {
  449. Value = ValueBuffer[0];
  450. }
  451. return Value;
  452. }
  453. USHORT
  454. ReadShortValue(
  455. IN ULONG64 Address,
  456. IN PCHAR Type,
  457. IN PCHAR Field
  458. )
  459. /*++
  460. Routine Description:
  461. Reads the value of a 16 bit value
  462. Arguments:
  463. Address - Virtual address of the value
  464. Type - Qualified type string
  465. Field - Field name
  466. Return Value:
  467. The 16 bit value or zero.
  468. --*/
  469. {
  470. static USHORT ValueBuffer[128];
  471. USHORT Value;
  472. ULONG64 OutputAddress;
  473. if (MyGetFieldData( Address, Type, Field, sizeof(Value), (PVOID)ValueBuffer, &OutputAddress )) {
  474. Value = 0;
  475. } else {
  476. Value = ValueBuffer[0];
  477. }
  478. return Value;
  479. }
  480. VOID
  481. DumpUnicodeString(
  482. IN ULONG64 Address,
  483. IN PCHAR Type,
  484. IN PCHAR Field
  485. )
  486. /*++
  487. Routine Description:
  488. Prints the value (the actual string) of a string
  489. contained in a UNICODE_STRING structure
  490. Arguments:
  491. Address - Virtual address of the structure
  492. Type - Qualified type string for the structure containing the string
  493. Field - Field name for the string
  494. Return Value:
  495. None.
  496. --*/
  497. {
  498. ULONG64 Value;
  499. ULONG64 OutputAddress;
  500. USHORT Length;
  501. ULONG64 BufferAddr;
  502. PWSTR Buffer;
  503. if (MyGetFieldData( Address, Type, Field, 0, (PVOID)&Value, &OutputAddress ) == 0) {
  504. if (ReadMemory( OutputAddress, &Length, sizeof(Length), (PULONG)&Value )) {
  505. if (Length) {
  506. GetFieldOffset( "UNICODE_STRING", "Buffer", (PULONG)&Value );
  507. OutputAddress += Value;
  508. if (ReadMemory( OutputAddress, &BufferAddr, GetTypeSize("PWSTR"), (PULONG)&Value )) {
  509. if (BufferAddr) {
  510. Buffer = (PWSTR) malloc( Length + sizeof(WCHAR) );
  511. if (Buffer) {
  512. if (ReadMemory( BufferAddr, Buffer, Length, (PULONG)&Value )) {
  513. Buffer[Length/sizeof(WCHAR)] = 0;
  514. dprintf( "\n(%03x) %s %s [%ws]",
  515. (ULONG)(OutputAddress-Address),
  516. FormatValue(BufferAddr),
  517. Field,
  518. Buffer
  519. );
  520. free( Buffer );
  521. return;
  522. }
  523. free( Buffer );
  524. }
  525. }
  526. }
  527. }
  528. }
  529. }
  530. dprintf( "\n(%03x) %16x %s",
  531. (ULONG)(OutputAddress-Address),
  532. 0,
  533. Field
  534. );
  535. return;
  536. }
  537. BOOL
  538. DumpString(
  539. IN ULONG64 Address,
  540. IN PCHAR Type,
  541. IN PCHAR LengthField,
  542. IN PCHAR StringField
  543. )
  544. /*++
  545. Routine Description:
  546. Prints the value (the actual string) of a string
  547. contained in a structure with a corresponding
  548. length field as another field member.
  549. Arguments:
  550. Address - Virtual address of the structure
  551. Type - Qualified type string for the structure containing the string
  552. LengthField - Field name for the length value
  553. StringField - Field name for the string
  554. Return Value:
  555. TRUE for success, FALSE for failure
  556. --*/
  557. {
  558. BOOL Result = FALSE;
  559. ULONG Length;
  560. PWSTR String;
  561. ULONG Offset;
  562. //
  563. // read in the length
  564. //
  565. if (LengthField == NULL) {
  566. Length = GetTypeSize(StringField) / sizeof(WCHAR);
  567. } else {
  568. Length = (ULONG)ReadValue( Address, Type, LengthField );
  569. }
  570. if (Length) {
  571. Length *= sizeof(WCHAR);
  572. //
  573. // allocate some memory to hold the file name
  574. //
  575. String = malloc( Length + sizeof(WCHAR) );
  576. if (String) {
  577. //
  578. // get the field offset of the string
  579. //
  580. if (!GetFieldOffset( Type, StringField, &Offset )) {
  581. //
  582. // compute the address of the string
  583. //
  584. Address += Offset;
  585. //
  586. // read the unicode characters for the string
  587. //
  588. if (ReadMemory( Address, String, Length, &Offset )) {
  589. //
  590. // zero terminate the string so we can print it out properly
  591. //
  592. String[Length/sizeof(WCHAR)] = 0;
  593. //
  594. // finally print the data
  595. //
  596. dprintf( "%ws", String );
  597. Result = TRUE;
  598. }
  599. }
  600. //
  601. // free the string memory
  602. //
  603. free( String );
  604. }
  605. }
  606. return Result;
  607. }
  608. ULONG64
  609. ReadArrayValue(
  610. IN ULONG64 Address,
  611. IN PCHAR Type,
  612. IN PCHAR Field,
  613. IN ULONG Index
  614. )
  615. /*++
  616. Routine Description:
  617. Reads a value/element contained in an array.
  618. Arguments:
  619. Address - Virtual address of the structure
  620. Type - Qualified type string for the structure containing the array
  621. Field - Field name for the array
  622. Index - The element that is requested
  623. Return Value:
  624. The element value or zero
  625. --*/
  626. {
  627. CHAR Buff[64];
  628. sprintf( Buff, "%s[%d]", Field, Index );
  629. return ReadValue( Address, Type, Buff );
  630. }
  631. ULONG
  632. GetOffset(
  633. IN LPSTR Type,
  634. IN LPSTR Field
  635. )
  636. /*++
  637. Routine Description:
  638. Gets the offset for a field within a structure
  639. Arguments:
  640. Type - Qualified type string for the structure containing the field
  641. Field - Field name
  642. Return Value:
  643. The offset value or zero
  644. --*/
  645. {
  646. FIELD_INFO flds = {
  647. (PUCHAR)Field,
  648. (PUCHAR)"",
  649. 0,
  650. DBG_DUMP_FIELD_FULL_NAME | DBG_DUMP_FIELD_RETURN_ADDRESS,
  651. 0,
  652. NULL};
  653. SYM_DUMP_PARAM Sym = {
  654. sizeof (SYM_DUMP_PARAM),
  655. (PUCHAR)Type,
  656. DBG_DUMP_NO_PRINT,
  657. 0,
  658. NULL,
  659. NULL,
  660. NULL,
  661. 1,
  662. &flds
  663. };
  664. ULONG Err;
  665. Sym.nFields = 1;
  666. Err = Ioctl( IG_DUMP_SYMBOL_INFO, &Sym, Sym.size );
  667. if (Err == 0) {
  668. return (ULONG) (flds.address - Sym.addr);
  669. }
  670. return -1;
  671. }
  672. PSTR
  673. FormatValue(
  674. ULONG64 addr
  675. )
  676. /*++
  677. Routine Description:
  678. Format a 64 bit address, showing the high bits or not
  679. according to various flags. This version does not print
  680. leading 0's.
  681. An array of static string buffers is used, returning a different
  682. buffer for each successive call so that it may be used multiple
  683. times in the same print.
  684. Arguments:
  685. addr - Supplies the value to format
  686. Return Value:
  687. A pointer to the string buffer containing the formatted number
  688. --*/
  689. {
  690. #define MAX_FORMAT_STRINGS 8
  691. static CHAR strings[MAX_FORMAT_STRINGS][18];
  692. static int next = 0;
  693. LPSTR string;
  694. string = strings[next];
  695. ++next;
  696. if (next >= MAX_FORMAT_STRINGS) {
  697. next = 0;
  698. }
  699. if ((KdDebuggerData.KernBase >> 32) != 0) {
  700. //
  701. // we're on a 64bit machines
  702. //
  703. sprintf( string, "%08x`%08x", (ULONG)(addr>>32), (ULONG)addr );
  704. } else {
  705. sprintf( string, "%08x", (ULONG)addr );
  706. }
  707. return string;
  708. }
  709. VOID
  710. PrintState(
  711. STATE *ps,
  712. ULONG state
  713. )
  714. /*++
  715. Routine Description:
  716. Prints a state string based on the provided state value
  717. Arguments:
  718. ps - State string array
  719. State - State value
  720. Return Value:
  721. None
  722. --*/
  723. {
  724. ULONG ul = 0;
  725. while (ps->mask != 0) {
  726. ul |= ps->mask;
  727. if ((state & ps->mask) == ps->value) {
  728. dprintf(" %s", ps->pszname);
  729. }
  730. ps++;
  731. }
  732. state &= ~ul;
  733. if (state != 0) {
  734. dprintf(" +%lx!!", state);
  735. }
  736. dprintf("\n");
  737. }
  738. const char *
  739. TypeCodeGuess (
  740. IN NODE_TYPE_CODE TypeCode
  741. )
  742. /*++
  743. Routine Description:
  744. Guess at a structure's type code
  745. Arguments:
  746. TypeCode - Type code from the data structure
  747. Return Value:
  748. None
  749. --*/
  750. {
  751. int i = 0;
  752. while (NodeTypeCodes[i].TypeCode != 0 &&
  753. NodeTypeCodes[i].TypeCode != TypeCode) {
  754. i++;
  755. }
  756. return NodeTypeCodes[i].Text;
  757. }
  758. VOID
  759. FindData(
  760. IN ULONG64 FileObjectAddress,
  761. IN ULONG64 Offset,
  762. IN BOOL Trace,
  763. OUT PULONG64 DataAddress
  764. )
  765. /*++
  766. Routine Description:
  767. Find the cache address for a given file object at the given offset.
  768. Arguments:
  769. FileObjectAddress - Gives the address of the file object to dump
  770. Offset - Gives the offset within the file to dump
  771. DataAddress - Where to store the address of the data. This will
  772. contain 0 if the data at the given offset is not mapped.
  773. Return Value:
  774. None.
  775. --*/
  776. {
  777. ULONG64 VacbAddr; // the address of the vacb
  778. ULONG64 VacbAddrAddr; // the address of the address of the vacb
  779. ULONG VacbNumber;
  780. ULONG OffsetWithinVacb;
  781. ULONG Level;
  782. ULONG Shift;
  783. ULONG OffsetForLevel;
  784. LONGLONG OriginalOffset = Offset;
  785. ULONG PtrSize = GetTypeSize("PVOID");
  786. ULONG Type, InVacbsOffset;
  787. ULONG64 SectionObjectPointer, SharedCacheMap, Vacbs, SectionSize_Quad;
  788. *DataAddress = 0;
  789. if (Trace) {
  790. dprintf( "\n FindData for FileObject %08p", FileObjectAddress );
  791. }
  792. if (GetFieldValue(FileObjectAddress, "FILE_OBJECT", "Type", Type)) {
  793. dprintf("Unable to read FILE_OBJECT at %p\n", FileObjectAddress);
  794. return;
  795. }
  796. //
  797. // Before we get into too much trouble, make sure this looks like a FileObject.
  798. //
  799. //
  800. // Type of a FileObject must be IO_TYPE_FILE.
  801. //
  802. if (Type != IO_TYPE_FILE) {
  803. dprintf( "\nFILE_OBJECT type signature does not match, type code is %s",
  804. TypeCodeGuess((USHORT) Type ));
  805. return;
  806. }
  807. GetFieldValue(FileObjectAddress, "FILE_OBJECT",
  808. "SectionObjectPointer", SectionObjectPointer);
  809. if (Trace) {
  810. dprintf( " Section Object Pointers: %08p", SectionObjectPointer );
  811. }
  812. if (GetFieldValue(SectionObjectPointer,
  813. "SECTION_OBJECT_POINTERS",
  814. "SharedCacheMap",
  815. SharedCacheMap)) {
  816. dprintf("Unable to read SECTION_OBJECT_POINTERS at %p\n", SectionObjectPointer);
  817. return;
  818. }
  819. if (Trace) {
  820. dprintf( "\n Shared Cache Map: %08p", SharedCacheMap );
  821. }
  822. if (GetFieldValue(SharedCacheMap,
  823. "SHARED_CACHE_MAP",
  824. "Vacbs",
  825. Vacbs)) {
  826. dprintf("Unable to read SHARED_CACHE_MAP at %p\n", SharedCacheMap);
  827. return;
  828. }
  829. GetFieldValue(SharedCacheMap, "SHARED_CACHE_MAP",
  830. "SectionSize.QuadPart", SectionSize_Quad);
  831. OffsetWithinVacb = (((ULONG) Offset) & (VACB_MAPPING_GRANULARITY - 1));
  832. GetFieldOffset("SHARED_CACHE_MAP", "InitialVacbs", &InVacbsOffset);
  833. if (Trace) {
  834. dprintf( " File Offset: %I64x ", Offset );
  835. }
  836. if (Vacbs == (SharedCacheMap + InVacbsOffset)) {
  837. //
  838. // Small file case -- we're using one of the Vacbs in the Shared Cache Map's
  839. // embedded array.
  840. //
  841. CHAR Buff[50];
  842. VacbNumber = (ULONG) (Offset >> VACB_OFFSET_SHIFT);
  843. if (VacbNumber >= PREALLOCATED_VACBS) {
  844. dprintf( "\nInvalid VacbNumber for resident Vacb" );
  845. return;
  846. }
  847. sprintf(Buff, "InitialVacbs[%d]", VacbNumber);
  848. GetFieldValue(SharedCacheMap, "SHARED_CACHE_MAP",
  849. Buff, VacbAddr);
  850. if (Trace) {
  851. dprintf( "in VACB number %x", VacbNumber );
  852. }
  853. } else if (SectionSize_Quad <= VACB_SIZE_OF_FIRST_LEVEL) {
  854. //
  855. // Medium file case -- we're using a single level (linear) structure to
  856. // store the Vacbs.
  857. //
  858. VacbNumber = (ULONG) (Offset >> VACB_OFFSET_SHIFT);
  859. VacbAddrAddr = Vacbs + (VacbNumber * PtrSize);
  860. if (ReadPtr(VacbAddrAddr, &VacbAddr)) {
  861. dprintf("Unable to read at %p\n", VacbAddrAddr);
  862. return;
  863. }
  864. if (Trace) {
  865. dprintf( "in VACB number %x", VacbNumber );
  866. }
  867. } else {
  868. //
  869. // Large file case -- multilevel Vacb storage.
  870. //
  871. Level = 0;
  872. Shift = VACB_OFFSET_SHIFT + VACB_LEVEL_SHIFT;
  873. //
  874. // Loop to calculate how many levels we have and how much we have to
  875. // shift to index into the first level.
  876. //
  877. do {
  878. Level += 1;
  879. Shift += VACB_LEVEL_SHIFT;
  880. } while (SectionSize_Quad > ((ULONG64)1 << Shift));
  881. //
  882. // Now descend the tree to the bottom level to get the caller's Vacb.
  883. //
  884. Shift -= VACB_LEVEL_SHIFT;
  885. // dprintf( "Shift: 0x%x\n", Shift );
  886. OffsetForLevel = (ULONG) (Offset >> Shift);
  887. VacbAddrAddr = Vacbs + (OffsetForLevel * PtrSize);
  888. if (ReadPtr(VacbAddrAddr, &VacbAddr)) {
  889. dprintf("Unable to read at %p\n", VacbAddrAddr);
  890. return;
  891. }
  892. while ((VacbAddr != 0) && (Level != 0)) {
  893. Level -= 1;
  894. Offset &= ((LONGLONG)1 << Shift) - 1;
  895. Shift -= VACB_LEVEL_SHIFT;
  896. // dprintf( "Shift: 0x%x\n", Shift );
  897. OffsetForLevel = (ULONG) (Offset >> Shift);
  898. VacbAddrAddr = VacbAddr + (OffsetForLevel * PtrSize);
  899. if (ReadPtr(VacbAddrAddr, &VacbAddr)) {
  900. dprintf("Unable to read at %p\n", VacbAddrAddr);
  901. return;
  902. }
  903. }
  904. }
  905. if (VacbAddr != 0) {
  906. ULONG64 Base;
  907. if (Trace) {
  908. dprintf( "\n Vacb: %08p", VacbAddr );
  909. }
  910. if (GetFieldValue(VacbAddr, "_VACB", "BaseAddress", Base)) {
  911. dprintf("Unable to read VACB base address at %p.", VacbAddr);
  912. return;
  913. }
  914. if (Trace) {
  915. dprintf( "\n Your data is at: %08p", (Base + OffsetWithinVacb) );
  916. }
  917. *DataAddress = Base + OffsetWithinVacb;
  918. } else {
  919. if (Trace) {
  920. dprintf( "\n Data at offset %I64x not mapped", OriginalOffset );
  921. }
  922. }
  923. return;
  924. }
  925. DECLARE_DUMP_FUNCTION( DumpCcb )
  926. /*++
  927. Routine Description:
  928. Dump a specific ccb.
  929. Arguments:
  930. Address - Gives the address of the fcb to dump
  931. Return Value:
  932. None
  933. --*/
  934. {
  935. ULONG64 Value;
  936. INIT_DUMP();
  937. Value = ReadValue( Address, SYM(CCB), "NodeTypeCode" );
  938. //
  939. // Before we get into too much trouble, make sure this looks like a ccb.
  940. //
  941. //
  942. // Type of an fcb record must be NTFS_NTC_CCB_DATA or NTFS_NTC_CCB_INDEX
  943. //
  944. if (Value != NTFS_NTC_CCB_DATA && Value != NTFS_NTC_CCB_INDEX) {
  945. dprintf( "\nCCB signature does not match, type code is %s", TypeCodeGuess( (NODE_TYPE_CODE)Value ));
  946. return;
  947. }
  948. //
  949. // Having established that this looks like a ccb, let's dump the
  950. // interesting parts.
  951. //
  952. dprintf( "\nCcb: %s", FormatValue(Address) );
  953. Value = ReadValue( Address, SYM(CCB), "Flags" );
  954. PrintState( CcbState, (ULONG)Value );
  955. DumpValue( Address, SYM(CCB), "Flags" );
  956. dprintf( "\n OpenType: " );
  957. Value = ReadValue( Address, SYM(CCB), "TypeOfOpen" );
  958. switch (Value) {
  959. case UserFileOpen :
  960. dprintf( "UserFileOpen" );
  961. break;
  962. case UserDirectoryOpen :
  963. dprintf( "UserDirectoryOpen" );
  964. break;
  965. case UserVolumeOpen :
  966. dprintf( "UserVolumeOpen" );
  967. break;
  968. case StreamFileOpen :
  969. dprintf( "StreamFileOpen" );
  970. break;
  971. case UserViewIndexOpen :
  972. dprintf( "UserViewIndexOpen" );
  973. break;
  974. }
  975. DumpUnicodeString( Address, SYM(CCB), "FullFileName" );
  976. DumpValue( Address, SYM(CCB), "LastFileNameOffset" );
  977. DumpValue( Address, SYM(CCB), "EaModificationCount" );
  978. DumpValue( Address, SYM(CCB), "NextEaOffset" );
  979. DumpValue( Address, SYM(CCB), "Lcb" );
  980. DumpValue( Address, SYM(CCB), "TypeOfOpen" );
  981. DumpValue( Address, SYM(CCB), "IndexContext" );
  982. DumpValue( Address, SYM(CCB), "QueryLength" );
  983. DumpValue( Address, SYM(CCB), "QueryBuffer" );
  984. DumpValue( Address, SYM(CCB), "IndexEntryLength" );
  985. DumpValue( Address, SYM(CCB), "IndexEntry" );
  986. DumpValue( Address, SYM(CCB), "LcbLinks.Flink" );
  987. DumpValue( Address, SYM(CCB), "FcbToAcquire" );
  988. dprintf( "\n" );
  989. }
  990. ULONG
  991. DumpFcbLinks(
  992. IN PFIELD_INFO ListElement,
  993. IN PVOID Context
  994. )
  995. /*++
  996. Routine Description:
  997. Enumeration callback function for FcbLinks
  998. Arguments:
  999. ListElement - Pointer to the containing record
  1000. Context - Opaque context passed from the origination function
  1001. Return Value:
  1002. TRUE to discontinue the enumeration
  1003. FALSE to continue the enumeration
  1004. --*/
  1005. {
  1006. ULONG64 Lcb = ListElement->address;
  1007. PDUMP_ENUM_CONTEXT dec = (PDUMP_ENUM_CONTEXT)Context;
  1008. if (CheckControlC()) {
  1009. return TRUE;
  1010. }
  1011. if (dec->Options >= 1) {
  1012. DumpLcb( Lcb, 0, dec->Options-1, dec->Processor, dec->hCurrentThread );
  1013. } else {
  1014. dprintf( "\n Lcb %s", FormatValue(Lcb) );
  1015. }
  1016. return FALSE;
  1017. }
  1018. ULONG
  1019. DumpScbLinks(
  1020. IN PFIELD_INFO ListElement,
  1021. IN PVOID Context
  1022. )
  1023. /*++
  1024. Routine Description:
  1025. Enumeration callback function for ScbLinks
  1026. Arguments:
  1027. ListElement - Pointer to the containing record
  1028. Context - Opaque context passed from the origination function
  1029. Return Value:
  1030. TRUE to discontinue the enumeration
  1031. FALSE to continue the enumeration
  1032. --*/
  1033. {
  1034. ULONG64 Scb = ListElement->address;
  1035. PDUMP_ENUM_CONTEXT dec = (PDUMP_ENUM_CONTEXT)Context;
  1036. ULONG Offset = 0;
  1037. if (CheckControlC()) {
  1038. return TRUE;
  1039. }
  1040. if (dec->Options >= 1) {
  1041. DumpScb( Scb, 0, dec->Options-1, dec->Processor, dec->hCurrentThread );
  1042. } else {
  1043. dprintf( "\n Scb %s", FormatValue(Scb) );
  1044. }
  1045. return FALSE;
  1046. }
  1047. DECLARE_DUMP_FUNCTION( DumpFcb )
  1048. /*++
  1049. Routine Description:
  1050. Dump a specific fcb.
  1051. Arguments:
  1052. Address - Gives the address of the fcb to dump
  1053. Return Value:
  1054. None
  1055. --*/
  1056. {
  1057. ULONG64 Value;
  1058. DUMP_ENUM_CONTEXT dec;
  1059. INIT_DUMP();
  1060. Value = ReadValue( Address, SYM(FCB), "NodeTypeCode" );
  1061. //
  1062. // Before we get into too much trouble, make sure this looks like an fcb.
  1063. //
  1064. //
  1065. // Type of an fcb record must be NTFS_NTC_FCB
  1066. //
  1067. if (Value != NTFS_NTC_FCB) {
  1068. dprintf( "\nFCB signature does not match, type code is %s", TypeCodeGuess( (NODE_TYPE_CODE)Value ) );
  1069. return;
  1070. }
  1071. dprintf( "\nFcb: %s", FormatValue(Address) );
  1072. //
  1073. // Having established that this looks like an fcb, let's dump the
  1074. // interesting parts.
  1075. //
  1076. PrintState( FcbState, (ULONG)ReadValue( Address, SYM(FCB), "FcbState" ) );
  1077. DumpValue( Address, SYM(FCB), "FcbState" );
  1078. DumpValue( Address, SYM(FCB), "FileReference" );
  1079. DumpValue( Address, SYM(FCB), "CleanupCount" );
  1080. DumpValue( Address, SYM(FCB), "CloseCount" );
  1081. DumpValue( Address, SYM(FCB), "ReferenceCount" );
  1082. DumpValue( Address, SYM(FCB), "FcbDenyDelete" );
  1083. DumpValue( Address, SYM(FCB), "FcbDeleteFile" );
  1084. DumpValue( Address, SYM(FCB), "BaseExclusiveCount" );
  1085. DumpValue( Address, SYM(FCB), "EaModificationCount" );
  1086. DumpValue( Address, SYM(FCB), "Vcb" );
  1087. DumpValue( Address, SYM(FCB), "FcbMutex" );
  1088. DumpValue( Address, SYM(FCB), "Resource" );
  1089. DumpValue( Address, SYM(FCB), "PagingIoResource" );
  1090. DumpValue( Address, SYM(FCB), "InfoFlags" );
  1091. DumpValue( Address, SYM(FCB), "LinkCount" );
  1092. DumpValue( Address, SYM(FCB), "TotalLinks" );
  1093. DumpValue( Address, SYM(FCB), "SharedSecurity" );
  1094. DumpValue( Address, SYM(FCB), "QuotaControl" );
  1095. DumpValue( Address, SYM(FCB), "ClassId" );
  1096. DumpValue( Address, SYM(FCB), "OwnerId" );
  1097. DumpValue( Address, SYM(FCB), "DelayedCloseCount" );
  1098. DumpValue( Address, SYM(FCB), "SecurityId" );
  1099. DumpValue( Address, SYM(FCB), "FcbUsnRecord" );
  1100. //
  1101. // walk the queue of links for this file
  1102. //
  1103. dec.hCurrentThread = hCurrentThread;
  1104. dec.Processor = Processor;
  1105. dec.Options = Options;
  1106. dprintf( "\n\nLinks:" );
  1107. Value = ReadValue( Address, SYM(FCB), "LcbQueue.Flink" );
  1108. if (Value) {
  1109. ListType( SYM(LCB), Value, TRUE, "FcbLinks.Flink", (PVOID)&dec, DumpFcbLinks );
  1110. }
  1111. dprintf( "\n\nStreams:" );
  1112. Value = ReadValue( Address, SYM(FCB), "ScbQueue.Flink" );
  1113. if (Value) {
  1114. ListType( SYM(SCB), Value, TRUE, "FcbLinks.Flink", (PVOID)&dec, DumpScbLinks );
  1115. }
  1116. dprintf( "\n" );
  1117. }
  1118. DECLARE_DUMP_FUNCTION( DumpFcbTable )
  1119. /*++
  1120. Routine Description:
  1121. Dump the fcb table.
  1122. Arguments:
  1123. Address - Gives the address of the fcb table to dump
  1124. Return Value:
  1125. None
  1126. --*/
  1127. {
  1128. ULONG64 Value;
  1129. ULONG64 TableElemAddr;
  1130. ULONG64 RestartKey;
  1131. ULONG64 FcbAddr;
  1132. ULONG Offset1;
  1133. ULONG Offset2;
  1134. PWSTR FileName;
  1135. BOOL GotIt;
  1136. INIT_DUMP();
  1137. //
  1138. // Dump the FcbTable
  1139. //
  1140. Value = ReadValue( Address, SYM(RTL_AVL_TABLE), "CompareRoutine" );
  1141. if (Value != GetExpression("NTFS!NtfsFcbTableCompare")) {
  1142. dprintf( "\nThe address [%s] does not seem to point to a FCB table", FormatValue(Address) );
  1143. return;
  1144. }
  1145. dprintf( "\n FcbTable %s", FormatValue(Address) );
  1146. dprintf( "\n FcbTable has %x elements", (ULONG)ReadValue( Address, SYM(RTL_AVL_TABLE), "NumberGenericTableElements" ) );
  1147. RestartKey = 0;
  1148. for (TableElemAddr = KdEnumerateGenericTableWithoutSplaying(Address, &RestartKey);
  1149. TableElemAddr != 0;
  1150. TableElemAddr = KdEnumerateGenericTableWithoutSplaying(Address, &RestartKey)) {
  1151. FcbAddr = ReadValue( TableElemAddr, SYM(FCB_TABLE_ELEMENT), "Fcb" );
  1152. if (Options >= 1) {
  1153. DumpFcb( FcbAddr, 0, Options - 2, Processor, hCurrentThread );
  1154. } else {
  1155. GotIt = FALSE;
  1156. //
  1157. // get the address of the FCB.LcbQueue LIST_ENTRY
  1158. //
  1159. Value = ReadValue( FcbAddr, SYM(FCB), "LcbQueue.Flink" );
  1160. if (Value) {
  1161. //
  1162. // get the offset of the LCB.FcbLinks LIST_ENTRY
  1163. //
  1164. if (!GetFieldOffset( SYM(LCB), "FcbLinks.Flink", &Offset1 )) {
  1165. //
  1166. // get the field offset of the FCB.LcbQueue LIST_ENTRY
  1167. //
  1168. if (!GetFieldOffset( SYM(FCB), "LcbQueue.Flink", &Offset2 )) {
  1169. //
  1170. // check to see if the list is empty
  1171. //
  1172. if (Value != FcbAddr+Offset2) {
  1173. //
  1174. // compute the address of the LCB
  1175. //
  1176. Value -= Offset1;
  1177. //
  1178. // get the length of the file name
  1179. //
  1180. Offset2 = (ULONG)(ReadValue( Value, SYM(LCB), "FileNameLength" ) * GetTypeSize("WCHAR"));
  1181. if (Offset2) {
  1182. //
  1183. // allocate some memory to hold the file name
  1184. //
  1185. FileName = malloc( Offset2 + GetTypeSize("WCHAR") );
  1186. if (FileName) {
  1187. //
  1188. // get the field offset of the LCB.FileName
  1189. //
  1190. if (!GetFieldOffset( SYM(LCB), "FileName", &Offset1 )) {
  1191. //
  1192. // compute the address of the file name character array
  1193. //
  1194. Value += Offset1;
  1195. //
  1196. // read the unicode characters for the file name
  1197. //
  1198. if (ReadMemory( Value, FileName, Offset2, (PULONG)&Offset1 )) {
  1199. //
  1200. // zero terminate the name so we can print it out properly
  1201. //
  1202. FileName[Offset2/GetTypeSize("WCHAR")] = 0;
  1203. //
  1204. // finally print the data
  1205. //
  1206. GotIt = TRUE;
  1207. dprintf( "\n Fcb %s for FileReference %08lx FcbTableElement %s %ws 0x%x",
  1208. FormatValue(FcbAddr),
  1209. (ULONG)ReadValue( TableElemAddr, SYM(FCB_TABLE_ELEMENT), "FileReference.SegmentNumberLowPart" ),
  1210. FormatValue(TableElemAddr),
  1211. FileName,
  1212. (ULONG)ReadValue( FcbAddr, SYM(FCB), "CleanupCount" )
  1213. );
  1214. }
  1215. }
  1216. //
  1217. // free the file name memory
  1218. //
  1219. free( FileName );
  1220. }
  1221. }
  1222. }
  1223. }
  1224. }
  1225. }
  1226. if (!GotIt) {
  1227. dprintf( "\n Fcb %s for FileReference %08lx FcbTableElement %s <filename unavailable> 0x%x",
  1228. FormatValue(FcbAddr),
  1229. (ULONG)ReadValue( TableElemAddr, SYM(FCB_TABLE_ELEMENT), "FileReference.SegmentNumberLowPart" ),
  1230. FormatValue(TableElemAddr),
  1231. (ULONG)ReadValue( FcbAddr, SYM(FCB), "CleanupCount" )
  1232. );
  1233. }
  1234. }
  1235. if (CheckControlC( )) {
  1236. break;
  1237. }
  1238. } // endfor
  1239. }
  1240. DECLARE_DUMP_FUNCTION( DumpFileObject )
  1241. /*++
  1242. Routine Description:
  1243. Dump a FileObject.
  1244. Arguments:
  1245. Address - Gives the address of the FileObject to dump
  1246. Return Value:
  1247. None
  1248. --*/
  1249. {
  1250. ULONG64 Value;
  1251. INIT_DUMP();
  1252. Value = ReadValue( Address, SYM(FILE_OBJECT), "Type" );
  1253. if (Value != IO_TYPE_FILE) {
  1254. dprintf( "Invalid signature, probably not a file object" );
  1255. return;
  1256. }
  1257. dprintf( "\nFileObject: %p", Address );
  1258. Value = ReadValue( Address, SYM(FILE_OBJECT), "FsContext" );
  1259. if (Value) {
  1260. DumpScb( Value, 0, Options, Processor, hCurrentThread );
  1261. Value = ReadValue( Address, SYM(FILE_OBJECT), "FsContext2" );
  1262. if (Value) {
  1263. DumpCcb( Value, 0, Options, Processor, hCurrentThread );
  1264. }
  1265. }
  1266. DumpValue( Address, SYM(FILE_OBJECT), "DeviceObject" );
  1267. DumpValue( Address, SYM(FILE_OBJECT), "Vpb" );
  1268. DumpValue( Address, SYM(FILE_OBJECT), "FsContext" );
  1269. DumpValue( Address, SYM(FILE_OBJECT), "FsContext2" );
  1270. DumpValue( Address, SYM(FILE_OBJECT), "SectionObjectPointer" );
  1271. DumpValue( Address, SYM(FILE_OBJECT), "PrivateCacheMap" );
  1272. DumpValue( Address, SYM(FILE_OBJECT), "FinalStatus" );
  1273. DumpValue( Address, SYM(FILE_OBJECT), "RelatedFileObject" );
  1274. DumpValue( Address, SYM(FILE_OBJECT), "LockOperation" );
  1275. DumpValue( Address, SYM(FILE_OBJECT), "DeletePending" );
  1276. DumpValue( Address, SYM(FILE_OBJECT), "ReadAccess" );
  1277. DumpValue( Address, SYM(FILE_OBJECT), "WriteAccess" );
  1278. DumpValue( Address, SYM(FILE_OBJECT), "DeleteAccess" );
  1279. DumpValue( Address, SYM(FILE_OBJECT), "SharedRead" );
  1280. DumpValue( Address, SYM(FILE_OBJECT), "SharedWrite" );
  1281. DumpValue( Address, SYM(FILE_OBJECT), "SharedDelete" );
  1282. DumpValue( Address, SYM(FILE_OBJECT), "Flags" );
  1283. DumpUnicodeString( Address, SYM(FILE_OBJECT), "FileName" );
  1284. DumpValue( Address, SYM(FILE_OBJECT), "CurrentByteOffset" );
  1285. DumpValue( Address, SYM(FILE_OBJECT), "Waiters" );
  1286. DumpValue( Address, SYM(FILE_OBJECT), "Busy" );
  1287. DumpValue( Address, SYM(FILE_OBJECT), "LastLock" );
  1288. DumpValue( Address, SYM(FILE_OBJECT), "Lock" );
  1289. DumpValue( Address, SYM(FILE_OBJECT), "Event" );
  1290. DumpValue( Address, SYM(FILE_OBJECT), "CompletionContext" );
  1291. dprintf( "\n" );
  1292. }
  1293. DECLARE_DUMP_FUNCTION( DumpFileObjectFromIrp )
  1294. /*++
  1295. Routine Description:
  1296. Dump a FileObject given an Irp.
  1297. Arguments:
  1298. Address - Gives the address of the Irp where the FileObject can be found
  1299. Return Value:
  1300. None
  1301. --*/
  1302. {
  1303. ULONG64 Value;
  1304. INIT_DUMP();
  1305. Value = ReadValue( Address, SYM(IRP), "Type" );
  1306. if (Value != IO_TYPE_IRP) {
  1307. dprintf( "IRP signature does not match, probably not an IRP\n" );
  1308. return;
  1309. }
  1310. dprintf( "\nIrp: %s", FormatValue(Address) );
  1311. //
  1312. // only the current irp stack is worth dumping
  1313. // the - 1 is there because irp.CurrentLocation is 1 based
  1314. //
  1315. Value = Address + GetTypeSize(NT(IRP)) + (GetTypeSize(NT(IO_STACK_LOCATION)) * (ReadValue( Address, NT(IRP), "CurrentLocation" ) - 1));
  1316. Value = ReadValue( Value, NT(IO_STACK_LOCATION), "FileObject" );
  1317. DumpFileObject( Value, 0, Options, Processor, hCurrentThread );
  1318. }
  1319. DECLARE_DUMP_FUNCTION( DumpFileRecord )
  1320. /*++
  1321. Routine Description:
  1322. Dump a FileRecord given a FileObject or Fcb.
  1323. Arguments:
  1324. Address - Gives the address of a FileObject or Fcb.
  1325. Return Value:
  1326. None
  1327. --*/
  1328. {
  1329. ULONG64 Value;
  1330. ULONG64 DataAddress;
  1331. ULONG64 ScbAddress;
  1332. ULONG64 FcbAddress;
  1333. ULONG64 VcbAddress;
  1334. ULONG64 FoAddress;
  1335. INIT_DUMP();
  1336. Value = ReadValue( Address, NT(FILE_OBJECT), "Type" );
  1337. switch (Value) {
  1338. case IO_TYPE_FILE:
  1339. dprintf( "\nFileObject: %s", FormatValue(Address) );
  1340. ScbAddress = ReadValue( Address, NT(FILE_OBJECT), "FsContext" );
  1341. if (ScbAddress == 0) {
  1342. dprintf( "No FsContext in the file object" );
  1343. return;
  1344. }
  1345. FcbAddress = ReadValue( ScbAddress, SYM(SCB), "Fcb" );
  1346. break;
  1347. case NTFS_NTC_FCB:
  1348. dprintf( "\nFcb: %s", FormatValue(Address) );
  1349. FcbAddress = Address;
  1350. ScbAddress = 0;
  1351. break;
  1352. case NTFS_NTC_SCB_DATA:
  1353. case NTFS_NTC_SCB_INDEX:
  1354. dprintf( "\nScb: %s", FormatValue(Address) );
  1355. ScbAddress = Address;
  1356. FcbAddress = ReadValue( ScbAddress, SYM(SCB), "Fcb" );
  1357. break;
  1358. default:
  1359. dprintf( "Invalid signature, not a file object or Fcb" );
  1360. return;
  1361. }
  1362. VcbAddress = ReadValue( FcbAddress, SYM(FCB), "Vcb" );
  1363. dprintf( " Vcb: %s", FormatValue(VcbAddress) );
  1364. dprintf( " FRS: %08lx,%04lx",
  1365. ReadValue( FcbAddress, SYM(FCB), "FileReference.SegmentNumberLowPart" ),
  1366. ReadValue( FcbAddress, SYM(FCB), "FileReference.SequenceNumber" ));
  1367. ScbAddress = ReadValue( VcbAddress, SYM(VCB), "MftScb" );
  1368. dprintf( " MftScb: %s", FormatValue(ScbAddress) );
  1369. dprintf( "reading fo in mftscb 0x%x 0x%x\n", GetOffset( SYM(SCB), "Header.FilterContexts" ), GetOffset( SYM(SCB), "Header.PendingEofAdvances" ) );
  1370. FoAddress = ReadValue( ScbAddress, SYM(SCB), "FileObject" );
  1371. dprintf( "finding data in mft fo 0x%s\n", FormatValue(FoAddress) );
  1372. FindData( FoAddress,
  1373. ReadValue( FcbAddress, SYM(FCB), "FileReference.SegmentNumberLowPart" ) * ReadValue( VcbAddress, SYM(VCB), "BytesPerFileRecordSegment" ),
  1374. Options,
  1375. &DataAddress
  1376. );
  1377. if (DataAddress == 0) {
  1378. dprintf( "\nFileRecord is not mapped" );
  1379. } else {
  1380. dprintf( "\nFileRecord at: %s", FormatValue(DataAddress) );
  1381. DumpFileRecordContents( DataAddress, 0, Options, Processor, hCurrentThread );
  1382. }
  1383. }
  1384. DECLARE_DUMP_FUNCTION( DumpFileRecordContents )
  1385. /*++
  1386. Routine Description:
  1387. Dump a FileObject's contents given a pointer to where the FR is cached.
  1388. Arguments:
  1389. Address - Gives the address where the FR is cached.
  1390. Return Value:
  1391. None
  1392. --*/
  1393. {
  1394. ULONG64 Value;
  1395. ULONG64 AttrAddress;
  1396. INIT_DUMP();
  1397. Value = ReadValue( Address, SYM(FILE_RECORD_SEGMENT_HEADER), "MultiSectorHeader.Signature" );
  1398. if ((ULONG)Value != *(PULONG)FileSignature) {
  1399. dprintf( "Not a file record %x", (ULONG)Value );
  1400. return;
  1401. }
  1402. AttrAddress = Address + ReadValue( Address, SYM(FILE_RECORD_SEGMENT_HEADER), "FirstAttributeOffset" );
  1403. while ((Value = ReadValue( AttrAddress, SYM(ATTRIBUTE_RECORD_HEADER), "TypeCode" )) != 0xffffffff) {
  1404. dprintf( "\nAttribute type %x %s", (ULONG)Value, AttributeTypeCode[Value/0x10] );
  1405. dprintf( " at offset %x", AttrAddress - Address );
  1406. AttrAddress += ReadValue( AttrAddress, SYM(ATTRIBUTE_RECORD_HEADER), "RecordLength" );
  1407. if (CheckControlC()) {
  1408. break;
  1409. }
  1410. }
  1411. }
  1412. DECLARE_DUMP_FUNCTION( DumpIrpContext )
  1413. /*++
  1414. Routine Description:
  1415. Dump an IrpContext.
  1416. Arguments:
  1417. Address - Gives the address of the IrpContext to dump
  1418. Return Value:
  1419. None
  1420. --*/
  1421. {
  1422. ULONG64 Value;
  1423. INIT_DUMP();
  1424. dprintf( "\nIrpContext: %s", FormatValue(Address) );
  1425. Value = ReadValue( Address, SYM(IRP_CONTEXT), "NodeTypeCode" );
  1426. if (Value != NTFS_NTC_IRP_CONTEXT) {
  1427. dprintf( "\nIRP_CONTEXT signature does not match, type code is %s", TypeCodeGuess( (NODE_TYPE_CODE)Value ) );
  1428. return;
  1429. }
  1430. Value = ReadValue( Address, SYM(IRP_CONTEXT), "OriginatingIrp" );
  1431. if (Value) {
  1432. DumpFileObjectFromIrp( Value, 0, Options, Processor, hCurrentThread );
  1433. }
  1434. dprintf( "\n" );
  1435. }
  1436. DECLARE_DUMP_FUNCTION( DumpIrpContextFromThread )
  1437. /*++
  1438. Routine Description:
  1439. Dump an IrpContext given a Thread.
  1440. Arguments:
  1441. Address - Gives the address of the Thread where the IrpContext can be found
  1442. Return Value:
  1443. None
  1444. --*/
  1445. {
  1446. ULONG64 Value;
  1447. INIT_DUMP();
  1448. //
  1449. // Lookup the current thread if the user didn't specify one.
  1450. //
  1451. if (Address == 0) {
  1452. GetCurrentThreadAddr( Processor, &Address );
  1453. }
  1454. Value = ReadValue( Address, NT(ETHREAD), "TopLevelIrp" );
  1455. if (Value) {
  1456. dprintf( "\nThread %s", FormatValue(Address) );
  1457. Value = ReadValue( Value, SYM(TOP_LEVEL_CONTEXT), "ThreadIrpContext" );
  1458. DumpIrpContext( Value, 0, Options, Processor, hCurrentThread );
  1459. }
  1460. dprintf( "\n" );
  1461. }
  1462. DECLARE_DUMP_FUNCTION( DumpLcb )
  1463. /*++
  1464. Routine Description:
  1465. Dump an Lcb.
  1466. Arguments:
  1467. Address - Gives the address of the Lcb to dump
  1468. Return Value:
  1469. None
  1470. --*/
  1471. {
  1472. ULONG64 Value;
  1473. INIT_DUMP();
  1474. Value = ReadValue( Address, SYM(LCB), "NodeTypeCode" );
  1475. if (Value != NTFS_NTC_LCB) {
  1476. dprintf( "\nLCB signature does not match, type code is %s", TypeCodeGuess( (NODE_TYPE_CODE)Value ) );
  1477. return;
  1478. }
  1479. dprintf( "\nLcb: %s", FormatValue(Address) );
  1480. PrintState( LcbState, (ULONG)ReadValue( Address, SYM(LCB), "LcbState" ) );
  1481. DumpUnicodeString( Address, SYM(LCB), "FileName" );
  1482. DumpValue( Address, SYM(LCB), "Scb" );
  1483. DumpValue( Address, SYM(LCB), "Fcb" );
  1484. }
  1485. DECLARE_DUMP_FUNCTION( DumpLogFile )
  1486. /*++
  1487. Routine Description:
  1488. Dump a log file.
  1489. Arguments:
  1490. Address - Gives the address of the Vcb whose log file should be dumped
  1491. Return Value:
  1492. None
  1493. --*/
  1494. {
  1495. ULONG64 Value;
  1496. ULONG64 VcbAddress;
  1497. ULONG64 LogFileSize;
  1498. ULONG64 LogFileScb;
  1499. ULONG SeqNumberBits;
  1500. ULONG64 LogFileOffset;
  1501. LONG LogFileMask;
  1502. USHORT RedoOperation;
  1503. USHORT UndoOperation;
  1504. ULONG64 LogDataAddress;
  1505. INIT_DUMP();
  1506. LogFileOffset = Options;
  1507. Value = ReadValue( Address, SYM(VCB), "NodeTypeCode" );
  1508. switch (Value) {
  1509. case NTFS_NTC_FCB:
  1510. dprintf( "\nFcb: %s", FormatValue(Address) );
  1511. VcbAddress = ReadValue( Address, SYM(FCB), "Vcb" );
  1512. break;
  1513. case NTFS_NTC_VCB:
  1514. dprintf( "\nVcb: %s", FormatValue(Address) );
  1515. VcbAddress = Address;
  1516. break;
  1517. default:
  1518. dprintf( "\nSignature is not an FCB or VCB, type code is %s", TypeCodeGuess( (NODE_TYPE_CODE)Value) );
  1519. return;
  1520. }
  1521. if (LogFileOffset == 0) {
  1522. LogFileOffset = ReadValue( VcbAddress, SYM(VCB), "LastRestartArea.QuadPart" );
  1523. }
  1524. dprintf( " Starting at LSN: 0x%016I64x", LogFileOffset );
  1525. LogFileScb = ReadValue( VcbAddress, SYM(VCB), "LogFileScb" );
  1526. LogFileSize = ReadValue( LogFileScb, SYM(SCB), "Header.FileSize.QuadPart" );
  1527. for (SeqNumberBits=0; LogFileSize!=0; SeqNumberBits+=1,LogFileSize=((ULONGLONG)(LogFileSize)) >> 1 ) {
  1528. }
  1529. LogFileMask = (1 << (SeqNumberBits - 3)) - 1;
  1530. while (TRUE) {
  1531. LogFileOffset &= LogFileMask; // clear some bits
  1532. LogFileOffset = LogFileOffset << 3; // multiply by 8
  1533. Value = ReadValue( VcbAddress, SYM(VCB), "LogFileObject" );
  1534. FindData( Value, LogFileOffset, FALSE, &LogDataAddress );
  1535. if (LogDataAddress != 0) {
  1536. //
  1537. // It's mapped.
  1538. //
  1539. RedoOperation = ReadShortValue( LogDataAddress+GetTypeSize(SYM(LFS_RECORD_HEADER)), SYM(NTFS_LOG_RECORD_HEADER), "RedoOperation" );
  1540. UndoOperation = ReadShortValue( LogDataAddress+GetTypeSize(SYM(LFS_RECORD_HEADER)), SYM(NTFS_LOG_RECORD_HEADER), "UndoOperation" );
  1541. if (RedoOperation <= LastLogOperation && UndoOperation <= LastLogOperation) {
  1542. dprintf( "\nRedo: %s", LogOperation[RedoOperation] );
  1543. dprintf( " Undo: %s", LogOperation[UndoOperation] );
  1544. dprintf( " Lsn: 0x%08lx", (ULONG)ReadValue( LogDataAddress, SYM(LFS_RECORD_HEADER), "ThisLsn.LowPart" ) );
  1545. }
  1546. } else {
  1547. break;
  1548. }
  1549. if (CheckControlC()) {
  1550. break;
  1551. }
  1552. LogFileOffset = (ULONG)ReadValue( LogDataAddress, SYM(LFS_RECORD_HEADER), "ClientUndoNextLsn.LowPart" );
  1553. if (LogFileOffset == 0) {
  1554. break;
  1555. }
  1556. }
  1557. }
  1558. DECLARE_DUMP_FUNCTION( DumpTransaction )
  1559. /*++
  1560. Routine Description:
  1561. Dump a log file.
  1562. Arguments:
  1563. Address - Gives the address of the irpcontext to trace the transaction for
  1564. Return Value:
  1565. None
  1566. --*/
  1567. { ULONG64 TransactionId;
  1568. ULONG64 VcbAddress;
  1569. ULONG64 TransactionTable;
  1570. LSN FirstLsn;
  1571. LSN CurrentLsn;
  1572. ULONG64 LogFileObject;
  1573. ULONG64 LogFileSize;
  1574. ULONG64 LogFileScb;
  1575. ULONG SeqNumberBits;
  1576. ULONG64 LogFileOffset;
  1577. LONG LogFileMask;
  1578. USHORT RedoOperation;
  1579. USHORT UndoOperation;
  1580. ULONG64 LogDataAddress;
  1581. ULONG64 MftScbAddress;
  1582. ULONG64 MftFileObject;
  1583. ULONG64 DataAddress;
  1584. USHORT Type;
  1585. INIT_DUMP();
  1586. //
  1587. // Determine what type of input it is
  1588. //
  1589. Type = (USHORT) ReadValue( Address, SYM(IRP_CONTEXT), "NodeTypeCode" );
  1590. if (Type == NTFS_NTC_FCB) {
  1591. //
  1592. // Its an Fcb so read the filerecord and find the last LSN on disk from it
  1593. //
  1594. VcbAddress = ReadValue( Address, SYM(FCB), "Vcb" );
  1595. MftScbAddress = ReadValue( VcbAddress, SYM(VCB), "MftScb" );
  1596. MftFileObject = ReadValue( MftScbAddress, SYM(SCB), "FileObject" );
  1597. FindData( MftFileObject,
  1598. ReadValue( Address, SYM(FCB), "FileReference.SegmentNumberLowPart" ) * ReadValue( VcbAddress, SYM(VCB), "BytesPerFileRecordSegment" ),
  1599. 0,
  1600. &DataAddress
  1601. );
  1602. CurrentLsn.QuadPart = ReadValue( DataAddress, SYM(FILE_RECORD_SEGMENT_HEADER), "Lsn" );
  1603. dprintf( "Searching for last LSN: 0x%I64x on disk for file: 0x%I64x\n\n", CurrentLsn,
  1604. ReadValue( Address, SYM(FCB), "FileReference.SegmentNumberLowPart" ));
  1605. } else if (Type == NTFS_NTC_VCB ) {
  1606. //
  1607. // Its a vcb and filerecord so directly get the last LSN from it
  1608. //
  1609. VcbAddress = Address;
  1610. CurrentLsn.QuadPart = ReadValue( Options, SYM(FILE_RECORD_SEGMENT_HEADER), "Lsn" );
  1611. dprintf( "0x%x\n", Options );
  1612. dprintf( "Searching for last LSN: 0x%I64x on disk for file: 0x%I64x\n\n", CurrentLsn,
  1613. ReadValue( Options, SYM(FILE_RECORD_SEGMENT_HEADER), "SegmentNumberLowPart" ));
  1614. } else if (Type == NTFS_NTC_IRP_CONTEXT) {
  1615. //
  1616. // Read in the transaction id and then find the transaction entry in the table
  1617. //
  1618. TransactionId = ReadValue( Address, SYM(IRP_CONTEXT), "TransactionId" );
  1619. VcbAddress = ReadValue( Address, SYM(IRP_CONTEXT), "Vcb" );
  1620. TransactionTable = ReadValue( VcbAddress, SYM(VCB), "TransactionTable.Table" );
  1621. FirstLsn.QuadPart = ReadValue( TransactionTable + TransactionId, SYM( TRANSACTION_ENTRY), "FirstLsn.QuadPart" );
  1622. CurrentLsn.QuadPart = ReadValue( TransactionTable + TransactionId, SYM( TRANSACTION_ENTRY), "PreviousLsn.QuadPart" );
  1623. if (TransactionId == 0) {
  1624. dprintf( "No transaction active for this irpcontext\n" );
  1625. return;
  1626. }
  1627. dprintf( "Transaction: 0x%I64x from Lsn: 0x%I64x to 0x%I64x\n\n", TransactionId, FirstLsn, CurrentLsn );
  1628. } else {
  1629. dprintf( "Unknown type 0x%x for ptr 0x%p\n", Type, Address );
  1630. return;
  1631. }
  1632. LogFileScb = ReadValue( VcbAddress, SYM(VCB), "LogFileScb" );
  1633. LogFileSize = ReadValue( LogFileScb, SYM(SCB), "Header.FileSize.QuadPart" );
  1634. LogFileObject = ReadValue( VcbAddress, SYM(VCB), "LogFileObject" );
  1635. for (SeqNumberBits=0; LogFileSize!=0; SeqNumberBits+=1,LogFileSize=((ULONGLONG)(LogFileSize)) >> 1 ) {
  1636. }
  1637. LogFileMask = (1 << (SeqNumberBits - 3)) - 1;
  1638. LogFileOffset = CurrentLsn.QuadPart;
  1639. while (TRUE) {
  1640. LogFileOffset &= LogFileMask; // clear some bits
  1641. LogFileOffset = LogFileOffset << 3; // multiply by 8
  1642. FindData( LogFileObject, LogFileOffset, FALSE, &LogDataAddress );
  1643. if (LogDataAddress != 0) {
  1644. //
  1645. // It's mapped.
  1646. //
  1647. RedoOperation = ReadShortValue( LogDataAddress+GetTypeSize(SYM(LFS_RECORD_HEADER)), SYM(NTFS_LOG_RECORD_HEADER), "RedoOperation" );
  1648. UndoOperation = ReadShortValue( LogDataAddress+GetTypeSize(SYM(LFS_RECORD_HEADER)), SYM(NTFS_LOG_RECORD_HEADER), "UndoOperation" );
  1649. if (RedoOperation <= LastLogOperation && UndoOperation <= LastLogOperation) {
  1650. dprintf( "Record: %p Lsn: %I64x Prev: %I64x Undo: %I64x\n",
  1651. LogDataAddress,
  1652. ReadValue( LogDataAddress, SYM(LFS_RECORD_HEADER), "ThisLsn.QuadPart" ),
  1653. ReadValue( LogDataAddress, SYM(LFS_RECORD_HEADER), "ClientPreviousLsn.QuadPart" ),
  1654. ReadValue( LogDataAddress, SYM(LFS_RECORD_HEADER), "ClientUndoNextLsn.QuadPart" ) );
  1655. dprintf( "Redo: %s Undo: %s\n\n", LogOperation[RedoOperation], LogOperation[UndoOperation] );
  1656. }
  1657. } else {
  1658. dprintf( "Data not mapped in log for offset: 0x%I64x\n", LogFileOffset );
  1659. break;
  1660. }
  1661. if (CheckControlC()) {
  1662. break;
  1663. }
  1664. LogFileOffset = (ULONG)ReadValue( LogDataAddress, SYM(LFS_RECORD_HEADER), "ClientPreviousLsn.QuadPart" );
  1665. if (LogFileOffset == 0) {
  1666. break;
  1667. }
  1668. }
  1669. }
  1670. DECLARE_DUMP_FUNCTION( DumpMcb )
  1671. /*++
  1672. Routine Description:
  1673. Dump an Mcb.
  1674. Arguments:
  1675. Address - Gives the address of the Mcb to dump
  1676. Return Value:
  1677. None
  1678. --*/
  1679. {
  1680. ULONG64 NtfsMcbArray;
  1681. ULONG64 MappingPairsAddress;
  1682. ULONG RangeIdx;
  1683. ULONG NtfsMcbArraySizeInUse;
  1684. INIT_DUMP();
  1685. dprintf( "\nNtfsMcb: %s", FormatValue(Address) );
  1686. DumpValue( Address, SYM(NTFS_MCB), "FcbHeader" );
  1687. DumpValue( Address, SYM(NTFS_MCB), "PoolType" );
  1688. DumpValue( Address, SYM(NTFS_MCB), "NtfsMcbArraySizeInUse" );
  1689. DumpValue( Address, SYM(NTFS_MCB), "NtfsMcbArraySize" );
  1690. DumpValue( Address, SYM(NTFS_MCB), "NtfsMcbArray" );
  1691. DumpValue( Address, SYM(NTFS_MCB), "FastMutex" );
  1692. NtfsMcbArray = ReadValue( Address, SYM(NTFS_MCB), "NtfsMcbArray" );
  1693. NtfsMcbArraySizeInUse = (ULONG)ReadValue( Address, SYM(NTFS_MCB), "NtfsMcbArraySizeInUse" );
  1694. for (RangeIdx=0; RangeIdx<NtfsMcbArraySizeInUse; RangeIdx++) {
  1695. dprintf( "\n Range %d", RangeIdx );
  1696. DumpValue( NtfsMcbArray, SYM(NTFS_MCB_ARRAY), "StartingVcn" );
  1697. DumpValue( NtfsMcbArray, SYM(NTFS_MCB_ARRAY), "EndingVcn" );
  1698. DumpValue( NtfsMcbArray, SYM(NTFS_MCB_ARRAY), "NtfsMcbEntry" );
  1699. MappingPairsAddress = ReadValue( NtfsMcbArray, SYM(NTFS_MCB_ARRAY), "NtfsMcbEntry" ) +
  1700. GetOffset(SYM(NTFS_MCB_ENTRY),"LargeMcb") +
  1701. GetOffset(SYM(LARGE_MCB),"Mapping");
  1702. DumpPtrValue( MappingPairsAddress, "MappingPairs" );
  1703. //
  1704. // Go on to the next range.
  1705. //
  1706. NtfsMcbArray += GetTypeSize(SYM(NTFS_MCB_ARRAY));
  1707. if (CheckControlC()) {
  1708. break;
  1709. }
  1710. }
  1711. dprintf( "\n" );
  1712. }
  1713. ULONG
  1714. DumpVcbQueue(
  1715. IN PFIELD_INFO ListElement,
  1716. IN PVOID Context
  1717. )
  1718. /*++
  1719. Routine Description:
  1720. Enumeration callback function for the Vcb Queue
  1721. Arguments:
  1722. ListElement - Pointer to the containing record
  1723. Context - Opaque context passed from the origination function
  1724. Return Value:
  1725. TRUE to discontinue the enumeration
  1726. FALSE to continue the enumeration
  1727. --*/
  1728. {
  1729. ULONG64 Vcb = ListElement->address;
  1730. PDUMP_ENUM_CONTEXT dec = (PDUMP_ENUM_CONTEXT)Context;
  1731. ULONG64 Vpb;
  1732. if (CheckControlC()) {
  1733. return TRUE;
  1734. }
  1735. if (dec->Options >= 1) {
  1736. DumpVcb( Vcb, 0, dec->Options-1, dec->Processor, dec->hCurrentThread );
  1737. } else {
  1738. Vpb = ReadValue( Vcb, SYM(VCB), "Vpb" );
  1739. dprintf( "\n Vcb %s label: ", FormatValue(Vcb) );
  1740. if (!DumpString( Vpb, NT(VPB), "VolumeLabelLength", "VolumeLabel" )) {
  1741. dprintf( "<label unavailable>" );
  1742. }
  1743. }
  1744. return FALSE;
  1745. }
  1746. DECLARE_DUMP_FUNCTION( DumpNtfsData )
  1747. /*++
  1748. Routine Description:
  1749. Dump the list of Vcbs for the global NtfsData.
  1750. Arguments:
  1751. Options - If 1, we recurse into the Vcbs and dump them
  1752. Return Value:
  1753. None
  1754. --*/
  1755. {
  1756. ULONG64 Value;
  1757. DUMP_ENUM_CONTEXT dec;
  1758. INIT_DUMP();
  1759. Address = GetExpression( "Ntfs!NtfsData" );
  1760. dprintf( "\nNtfsData: %s", FormatValue(Address) );
  1761. Value = ReadValue( Address, SYM(NTFS_DATA), "NodeTypeCode" );
  1762. if (Value != NTFS_NTC_DATA_HEADER) {
  1763. dprintf( "\nNtfsData signature does not match, type code is %s", TypeCodeGuess( (NODE_TYPE_CODE)Value ) );
  1764. return;
  1765. }
  1766. PrintState( NtfsFlags, (ULONG)ReadValue( Address, SYM(NTFS_DATA), "Flags" ) );
  1767. //
  1768. // dump the vcb queue (mounted volumes)
  1769. //
  1770. dec.hCurrentThread = hCurrentThread;
  1771. dec.Processor = Processor;
  1772. dec.Options = Options;
  1773. Value = ReadValue( Address, SYM(NTFS_DATA), "VcbQueue.Flink" );
  1774. if (Value) {
  1775. ListType( SYM(VCB), Value, TRUE, "VcbLinks.Flink", (PVOID)&dec, DumpVcbQueue );
  1776. }
  1777. dprintf( "\n" );
  1778. DumpValue( Address, SYM(NTFS_DATA), "DriverObject" );
  1779. DumpValue( Address, SYM(NTFS_DATA), "Resource" );
  1780. DumpValue( Address, SYM(NTFS_DATA), "AsyncCloseActive" );
  1781. DumpValue( Address, SYM(NTFS_DATA), "ReduceDelayedClose" );
  1782. DumpValue( Address, SYM(NTFS_DATA), "AsyncCloseCount" );
  1783. DumpValue( Address, SYM(NTFS_DATA), "OurProcess" );
  1784. DumpValue( Address, SYM(NTFS_DATA), "DelayedCloseCount" );
  1785. DumpValue( Address, SYM(NTFS_DATA), "FreeFcbTableSize" );
  1786. DumpValue( Address, SYM(NTFS_DATA), "FreeEresourceSize" );
  1787. DumpValue( Address, SYM(NTFS_DATA), "FreeEresourceTotal" );
  1788. DumpValue( Address, SYM(NTFS_DATA), "FreeEresourceMiss" );
  1789. DumpValue( Address, SYM(NTFS_DATA), "FreeEresourceArray" );
  1790. DumpValue( Address, SYM(NTFS_DATA), "Flags" );
  1791. }
  1792. DECLARE_DUMP_FUNCTION( DumpScb )
  1793. /*++
  1794. Routine Description:
  1795. Dump an Scb.
  1796. Arguments:
  1797. Address - Gives the address of the Scb to dump
  1798. Options - If 1, we dump the Fcb & Vcb for this Scb
  1799. Return Value:
  1800. None
  1801. --*/
  1802. {
  1803. ULONG64 Value = 0;
  1804. INIT_DUMP();
  1805. _try {
  1806. Value = ReadValue( Address, SYM(SCB), "ScbState" );
  1807. if (!Value) {
  1808. _leave;
  1809. }
  1810. dprintf( "\nScb: %s", FormatValue(Address) );
  1811. PrintState( ScbState, (ULONG)Value );
  1812. dprintf( "\nScbPersist:" );
  1813. PrintState( ScbPersist, (ULONG)ReadValue( Address, SYM(SCB), "ScbPersist" ) );
  1814. Value = ReadValue( Address, SYM(FSRTL_COMMON_FCB_HEADER), "NodeTypeCode" );
  1815. if (!Value) {
  1816. _leave;
  1817. }
  1818. dprintf( "\n ScbType: " );
  1819. switch ( Value ) {
  1820. case NTFS_NTC_SCB_INDEX:
  1821. dprintf( "Index" );
  1822. break;
  1823. case NTFS_NTC_SCB_ROOT_INDEX:
  1824. dprintf( "RootIndex" );
  1825. break;
  1826. case NTFS_NTC_SCB_DATA:
  1827. dprintf( "Data" );
  1828. break;
  1829. case NTFS_NTC_SCB_MFT:
  1830. dprintf( "Mft" );
  1831. break;
  1832. default:
  1833. dprintf( "!!!UNKNOWN SCBTYPE!!!, type code is %s", TypeCodeGuess( (NODE_TYPE_CODE)Value ) );
  1834. break;
  1835. }
  1836. if (Options >= 1) {
  1837. Value = ReadValue( Address, SYM(SCB), "Fcb" );
  1838. if (Value) {
  1839. DumpFcb( Value, 0, Options - 1, Processor, hCurrentThread );
  1840. }
  1841. Value = ReadValue( Address, SYM(SCB), "Vcb" );
  1842. if (Value) {
  1843. DumpVcb( Value, 0, Options - 1, Processor, hCurrentThread );
  1844. }
  1845. } else {
  1846. DumpValue( Address, SYM(SCB), "Fcb" );
  1847. DumpValue( Address, SYM(SCB), "Vcb" );
  1848. DumpValue( Address, SYM(SCB), "Mcb" );
  1849. DumpValue( Address, SYM(SCB), "NonCachedCleanupCount" );
  1850. DumpValue( Address, SYM(SCB), "CleanupCount" );
  1851. DumpValue( Address, SYM(SCB), "CloseCount" );
  1852. DumpValue( Address, SYM(SCB), "ShareAccess" );
  1853. DumpValue( Address, SYM(SCB), "AttributeTypeCode" );
  1854. DumpValue( Address, SYM(SCB), "AttributeName.Length" );
  1855. DumpValue( Address, SYM(SCB), "AttributeName.Buffer" );
  1856. DumpValue( Address, SYM(SCB), "AttributeFlags" );
  1857. DumpValue( Address, SYM(SCB), "CompressionUnit" );
  1858. DumpValue( Address, SYM(SCB), "FileObject" );
  1859. DumpValue( Address, SYM(SCB), "NonpagedScb" );
  1860. DumpValue( Address, SYM(SCB), "EncryptionContext" );
  1861. }
  1862. } finally {
  1863. }
  1864. dprintf( "\n" );
  1865. }
  1866. DECLARE_DUMP_FUNCTION( DumpVcb )
  1867. /*++
  1868. Routine Description:
  1869. Dump a Vcb.
  1870. Arguments:
  1871. Address - Gives the address of the Vcb to dump
  1872. Options - If 1, we also dump the root Lcb and the Fcb table
  1873. If 2, we dump everything for option 1, and also dump the Fcbs in the Fcb table
  1874. Return Value:
  1875. None
  1876. --*/
  1877. {
  1878. ULONG64 Value = 0;
  1879. INIT_DUMP();
  1880. Value = ReadValue( Address, SYM(VCB), "NodeTypeCode" );
  1881. dprintf( "\n Vcb: %s", FormatValue(Address) );
  1882. if (Value != NTFS_NTC_VCB) {
  1883. dprintf( "\nVCB signature does not match, type code is %s", TypeCodeGuess( (NODE_TYPE_CODE)Value ) );
  1884. return;
  1885. }
  1886. PrintState( VcbState, (ULONG)ReadValue( Address, SYM(VCB), "VcbState" ) );
  1887. DumpValue( Address, SYM(VCB), "CleanupCount" );
  1888. DumpValue( Address, SYM(VCB), "CloseCount" );
  1889. DumpValue( Address, SYM(VCB), "ReadOnlyCloseCount" );
  1890. DumpValue( Address, SYM(VCB), "SystemFileCloseCount" );
  1891. DumpValue( Address, SYM(VCB), "UsnJournal" );
  1892. DumpValue( Address, SYM(VCB), "MftScb" );
  1893. DumpValue( Address, SYM(VCB), "Mft2Scb" );
  1894. DumpValue( Address, SYM(VCB), "LogFileScb" );
  1895. DumpValue( Address, SYM(VCB), "VolumeDasdScb" );
  1896. DumpValue( Address, SYM(VCB), "RootIndexScb" );
  1897. DumpValue( Address, SYM(VCB), "BitmapScb" );
  1898. DumpValue( Address, SYM(VCB), "AttributeDefTableScb" );
  1899. DumpValue( Address, SYM(VCB), "UpcaseTableScb" );
  1900. DumpValue( Address, SYM(VCB), "BadClusterFileScb" );
  1901. DumpValue( Address, SYM(VCB), "QuotaTableScb" );
  1902. DumpValue( Address, SYM(VCB), "ReparsePointTableScb" );
  1903. DumpValue( Address, SYM(VCB), "OwnerIdTableScb" );
  1904. DumpValue( Address, SYM(VCB), "SecurityDescriptorStream" );
  1905. DumpValue( Address, SYM(VCB), "SecurityIdIndex" );
  1906. DumpValue( Address, SYM(VCB), "SecurityDescriptorHashIndex" );
  1907. DumpValue( Address, SYM(VCB), "ExtendDirectory" );
  1908. DumpValue( Address, SYM(VCB), "ObjectIdTableScb" );
  1909. DumpValue( Address, SYM(VCB), "MftBitmapScb" );
  1910. DumpValue( Address, SYM(VCB), "RootLcb" );
  1911. DumpValue( Address, SYM(VCB), "FcbTable" );
  1912. DumpValue( Address, SYM(VCB), "Statistics" );
  1913. DumpValue( Address, SYM(VCB), "Resource" );
  1914. if (Options < 0) {
  1915. ResetFileSystemStatistics( Address, Processor, hCurrentThread );
  1916. } else if (Options >= 2) {
  1917. DumpFileSystemStatistics( Address, Processor, hCurrentThread );
  1918. } else if (Options >= 1) {
  1919. DumpLcb( ReadValue( Address, SYM(VCB), "RootLcb" ), 0, Options - 1, Processor, hCurrentThread );
  1920. DumpFcbTable( ReadValue( Address, SYM(VCB), "FcbTable" ), 0, Options - 1, Processor, hCurrentThread );
  1921. }
  1922. dprintf( "\n" );
  1923. }
  1924. VOID
  1925. ResetFileSystemStatistics (
  1926. IN ULONG64 VcbAddress,
  1927. IN USHORT Processor,
  1928. IN HANDLE hCurrentThread
  1929. )
  1930. /*++
  1931. Routine Description:
  1932. Dump the file system statitics of a vcb
  1933. Arguments:
  1934. Vcb - Suppplies a pointer to a vcb that the debugger has already loaded.
  1935. Return Value:
  1936. None
  1937. --*/
  1938. {
  1939. ULONG Result;
  1940. PUCHAR Stat;
  1941. ULONG64 StatsAddr;
  1942. dprintf( "\n" );
  1943. dprintf( "\n" );
  1944. //
  1945. // Write the Statistics structure based on the processor, but
  1946. // skip over the file system type and version field.
  1947. //
  1948. Result = GetTypeSize(SYM(FILE_SYSTEM_STATISTICS));
  1949. Stat = malloc( Result );
  1950. if (Stat) {
  1951. StatsAddr = ReadValue( VcbAddress, SYM(VCB), "Statistics" );
  1952. if (StatsAddr) {
  1953. if (!WriteMemory( StatsAddr + (Result * Processor) + GetOffset(SYM(FILE_SYSTEM_STATISTICS),"Common.UserFileReads"),
  1954. &Stat,
  1955. Result - GetOffset(SYM(FILE_SYSTEM_STATISTICS),"Common.UserFileReads"),
  1956. &Result) ) {
  1957. dprintf( "%s: Unable to reset Statistics\n", FormatValue(StatsAddr) );
  1958. }
  1959. }
  1960. free( Stat );
  1961. dprintf( "**** %s: Resetting Filesystem Statistics complete ****\n", FormatValue(StatsAddr) );
  1962. }
  1963. DumpFileSystemStatistics( VcbAddress, Processor, hCurrentThread );
  1964. }
  1965. VOID
  1966. DumpFileSystemStatistics (
  1967. IN ULONG64 VcbAddress,
  1968. IN USHORT Processor,
  1969. IN HANDLE hCurrentThread
  1970. )
  1971. /*++
  1972. Routine Description:
  1973. Dump the file system statitics of a vcb
  1974. Arguments:
  1975. Vcb - Suppplies a pointer to a vcb that the debugger has already loaded.
  1976. Return Value:
  1977. None
  1978. --*/
  1979. {
  1980. ULONG Result;
  1981. ULONG64 StatsAddr;
  1982. FILE_SYSTEM_STATISTICS Stat;
  1983. ULONG TotalReads;
  1984. ULONG TotalReadBytes;
  1985. ULONG TotalWrites;
  1986. ULONG TotalWriteBytes;
  1987. ULONG TotalClustersReturned;
  1988. ULONG AverageRequestSize;
  1989. ULONG AverageRunSize;
  1990. ULONG AverageHintSize;
  1991. ULONG AverageCacheSize;
  1992. ULONG AverageCacheMissSize;
  1993. UNREFERENCED_PARAMETER( hCurrentThread );
  1994. //
  1995. // Read in the Statistics structure based on the processor
  1996. //
  1997. StatsAddr = ReadValue( VcbAddress, SYM(VCB), "Statistics" );
  1998. if ( !ReadMemory( StatsAddr + (GetTypeSize(SYM(FILE_SYSTEM_STATISTICS)) * Processor),
  1999. &Stat,
  2000. GetTypeSize(SYM(FILE_SYSTEM_STATISTICS)),
  2001. &Result) ) {
  2002. dprintf( "%08lx: Unable to read Statistics\n", StatsAddr );
  2003. return;
  2004. }
  2005. //
  2006. // Sum up all the paging i/o reads and writes
  2007. //
  2008. TotalReads = Stat.Common.UserFileReads + Stat.Common.MetaDataReads + Stat.Ntfs.UserIndexReads + Stat.Ntfs.LogFileReads;
  2009. TotalReadBytes = Stat.Common.UserFileReadBytes + Stat.Common.MetaDataReadBytes + Stat.Ntfs.UserIndexReadBytes + Stat.Ntfs.LogFileReadBytes;
  2010. TotalWrites = Stat.Common.UserFileWrites + Stat.Common.MetaDataWrites + Stat.Ntfs.UserIndexWrites + Stat.Ntfs.LogFileWrites;
  2011. TotalWriteBytes = Stat.Common.UserFileWriteBytes + Stat.Common.MetaDataWriteBytes + Stat.Ntfs.UserIndexWriteBytes + Stat.Ntfs.LogFileWriteBytes;
  2012. //
  2013. // Sum up the total number of clusters returned
  2014. //
  2015. TotalClustersReturned = Stat.Ntfs.Allocate.HintsClusters + Stat.Ntfs.Allocate.CacheClusters + Stat.Ntfs.Allocate.CacheMissClusters;
  2016. //
  2017. // Compute the average cluster count requested, returned, from hints, and from the cache, and cache misses.
  2018. //
  2019. AverageRequestSize = AVERAGE(Stat.Ntfs.Allocate.Clusters, Stat.Ntfs.Allocate.Calls);
  2020. AverageRunSize = AVERAGE(TotalClustersReturned, Stat.Ntfs.Allocate.RunsReturned);
  2021. AverageHintSize = AVERAGE(Stat.Ntfs.Allocate.HintsClusters, Stat.Ntfs.Allocate.HintsHonored);
  2022. AverageCacheSize = AVERAGE(Stat.Ntfs.Allocate.CacheClusters, Stat.Ntfs.Allocate.Cache);
  2023. AverageCacheMissSize = AVERAGE(Stat.Ntfs.Allocate.CacheMissClusters, Stat.Ntfs.Allocate.CacheMiss);
  2024. dprintf( "\n" );
  2025. dprintf( "\n File System Statistics @ %s for Processor = %d", FormatValue(StatsAddr), Processor );
  2026. dprintf( "\n FileSystemType / Version = %d / %d", Stat.Common.FileSystemType, Stat.Common.Version );
  2027. dprintf( "\n" );
  2028. dprintf( "\n Exceptions LogFileFull = %ld Other = %ld", Stat.Ntfs.LogFileFullExceptions, Stat.Ntfs.OtherExceptions );
  2029. dprintf( "\n" );
  2030. dprintf( "\n Reads Bytes Writes Bytes" );
  2031. dprintf( "\n ----- ----- ------ -----" );
  2032. dprintf( "\n" );
  2033. dprintf( "\n UserFile %10ld (%10ld)%10ld (%10ld)", Stat.Common.UserFileReads, Stat.Common.UserFileReadBytes, Stat.Common.UserFileWrites, Stat.Common.UserFileWriteBytes );
  2034. dprintf( "\n UserDisk %10ld %10ld", Stat.Common.UserDiskReads, Stat.Common.UserDiskWrites );
  2035. dprintf( "\n" );
  2036. dprintf( "\n MetaData %10ld (%10ld)%10ld (%10ld)", Stat.Common.MetaDataReads, Stat.Common.MetaDataReadBytes, Stat.Common.MetaDataWrites, Stat.Common.MetaDataWriteBytes );
  2037. dprintf( "\n MetaDisk %10ld %10ld", Stat.Common.MetaDataDiskReads, Stat.Common.MetaDataDiskWrites );
  2038. dprintf( "\n" );
  2039. dprintf( "\n Mft %10ld (%10ld)%10ld (%10ld)", Stat.Ntfs.MftReads, Stat.Ntfs.MftReadBytes, Stat.Ntfs.MftWrites, Stat.Ntfs.MftWriteBytes );
  2040. dprintf( "\n Mft2 %10ld (%10lx)", Stat.Ntfs.Mft2Writes, Stat.Ntfs.Mft2WriteBytes );
  2041. dprintf( "\n RootIndex%10ld (%10ld)%10ld (%10ld)", Stat.Ntfs.RootIndexReads, Stat.Ntfs.RootIndexReadBytes, Stat.Ntfs.RootIndexWrites, Stat.Ntfs.RootIndexWriteBytes );
  2042. dprintf( "\n Bitmap %10ld (%10ld)%10ld (%10ld)", Stat.Ntfs.BitmapReads, Stat.Ntfs.BitmapReadBytes, Stat.Ntfs.BitmapWrites, Stat.Ntfs.BitmapWriteBytes );
  2043. dprintf( "\n MftBitmap%10ld (%10ld)%10ld (%10ld)", Stat.Ntfs.MftBitmapReads, Stat.Ntfs.MftBitmapReadBytes, Stat.Ntfs.MftBitmapWrites, Stat.Ntfs.MftBitmapWriteBytes );
  2044. dprintf( "\n" );
  2045. dprintf( "\n UserIndex %10ld (%10ld)%10ld (%10ld)", Stat.Ntfs.UserIndexReads, Stat.Ntfs.UserIndexReadBytes, Stat.Ntfs.UserIndexWrites, Stat.Ntfs.UserIndexWriteBytes );
  2046. dprintf( "\n" );
  2047. dprintf( "\n LogFile %10ld (%10ld)%10ld (%10ld)", Stat.Ntfs.LogFileReads, Stat.Ntfs.LogFileReadBytes, Stat.Ntfs.LogFileWrites, Stat.Ntfs.LogFileWriteBytes );
  2048. dprintf( "\n" );
  2049. dprintf( "\n TOTAL %10ld (%10ld)%10ld (%10ld)", TotalReads, TotalReadBytes, TotalWrites, TotalWriteBytes );
  2050. dprintf( "\n" );
  2051. dprintf( "\n Write Create SetInfo Flush" );
  2052. dprintf( "\n ----- ------ ------- -----" );
  2053. dprintf( "\n MftWritesUserLevel %5d %5d %5d %5d", Stat.Ntfs.MftWritesUserLevel.Write, Stat.Ntfs.MftWritesUserLevel.Create, Stat.Ntfs.MftWritesUserLevel.SetInfo, Stat.Ntfs.MftWritesUserLevel.Flush );
  2054. dprintf( "\n Mft2WritesUserLevel %5d %5d %5d %5d", Stat.Ntfs.Mft2WritesUserLevel.Write, Stat.Ntfs.Mft2WritesUserLevel.Create, Stat.Ntfs.Mft2WritesUserLevel.SetInfo, Stat.Ntfs.Mft2WritesUserLevel.Flush );
  2055. dprintf( "\n BitmapWritesUserLevel %5d %5d %5d", Stat.Ntfs.BitmapWritesUserLevel.Write, Stat.Ntfs.BitmapWritesUserLevel.Create, Stat.Ntfs.BitmapWritesUserLevel.SetInfo );
  2056. dprintf( "\n MftBitmapWritesUserLevel %5d %5d %5d %5d", Stat.Ntfs.MftBitmapWritesUserLevel.Write, Stat.Ntfs.MftBitmapWritesUserLevel.Create, Stat.Ntfs.MftBitmapWritesUserLevel.SetInfo, Stat.Ntfs.MftBitmapWritesUserLevel.Flush );
  2057. dprintf( "\n" );
  2058. dprintf( "\n FlushForLogFileFull LazyWriter UserRequest" );
  2059. dprintf( "\n ------------------- ---------- -----------" );
  2060. dprintf( "\n MftWrites %5d %5d %5d", Stat.Ntfs.MftWritesFlushForLogFileFull, Stat.Ntfs.MftWritesLazyWriter, Stat.Ntfs.MftWritesUserRequest );
  2061. dprintf( "\n Mft2Writes %5d %5d %5d", Stat.Ntfs.Mft2WritesFlushForLogFileFull, Stat.Ntfs.Mft2WritesLazyWriter, Stat.Ntfs.Mft2WritesUserRequest );
  2062. dprintf( "\n BitmapWrites %5d %5d %5d", Stat.Ntfs.BitmapWritesFlushForLogFileFull, Stat.Ntfs.BitmapWritesLazyWriter, Stat.Ntfs.BitmapWritesUserRequest );
  2063. dprintf( "\n MftBitmapWrites %5d %5d %5d", Stat.Ntfs.MftBitmapWritesFlushForLogFileFull, Stat.Ntfs.MftBitmapWritesLazyWriter, Stat.Ntfs.MftBitmapWritesUserRequest );
  2064. dprintf( "\n" );
  2065. dprintf( "\n Allocate Total Average" );
  2066. dprintf( "\n Clusters Runs Hints Clusters RunSize" );
  2067. dprintf( "\n ---- ----- -------- -------" );
  2068. dprintf( "\n Requested %10ld %10ld %10ld %10ld", Stat.Ntfs.Allocate.Calls, Stat.Ntfs.Allocate.Hints, Stat.Ntfs.Allocate.Clusters, AverageRequestSize );
  2069. dprintf( "\n Returned %10ld %10ld %10ld %10ld", Stat.Ntfs.Allocate.RunsReturned, Stat.Ntfs.Allocate.HintsHonored, TotalClustersReturned, AverageRunSize );
  2070. dprintf( "\n" );
  2071. dprintf( "\n FromHints %10ld %10ld %10ld", Stat.Ntfs.Allocate.HintsHonored, Stat.Ntfs.Allocate.HintsClusters, AverageHintSize );
  2072. dprintf( "\n CacheHit %10ld %10ld %10ld", Stat.Ntfs.Allocate.Cache, Stat.Ntfs.Allocate.CacheClusters, AverageCacheSize );
  2073. dprintf( "\n CacheMiss %10ld %10ld %10ld", Stat.Ntfs.Allocate.CacheMiss, Stat.Ntfs.Allocate.CacheMissClusters, AverageCacheMissSize );
  2074. dprintf( "\n" );
  2075. }
  2076. DECLARE_DUMP_FUNCTION( DumpSysCache )
  2077. /*++
  2078. Routine Description:
  2079. Dump the syscache buffers. The target system must have been
  2080. built with syscache enabled.
  2081. Arguments:
  2082. Address - Gives the address of the Vcb to dump
  2083. Return Value:
  2084. None
  2085. --*/
  2086. {
  2087. ULONG SyscacheLogEntryCount;
  2088. ULONG CurrentSyscacheLogEntry;
  2089. PSYSCACHE_LOG pLog = NULL;
  2090. int iEnd;
  2091. int iStart;
  2092. int iTemp;
  2093. int iIndex;
  2094. INIT_DUMP();
  2095. if (GetOffset( SYM(VCB), "SyscacheScb" ) == -1) {
  2096. //
  2097. // the system was not built with syscache debug
  2098. //
  2099. dprintf( "\nthe target system does not have syscache debug enabled\n" );
  2100. return;
  2101. }
  2102. if (Options != 0) {
  2103. dprintf( "Direct buffer dump\n" );
  2104. dprintf("Num Entries: 0x%x\n", Options );
  2105. dprintf("Current Entry: 0x%x\n", Options );
  2106. CurrentSyscacheLogEntry = Options;
  2107. SyscacheLogEntryCount = Options;
  2108. pLog = (PSYSCACHE_LOG) malloc( GetTypeSize(SYM(SYSCACHE_LOG)) * SyscacheLogEntryCount );
  2109. if (!pLog) {
  2110. return;
  2111. }
  2112. if (!ReadMemory( Address, pLog, GetTypeSize(SYM(SYSCACHE_LOG)) * SyscacheLogEntryCount, &iTemp )) {
  2113. dprintf( "Unable to read SCB.SyscacheLog\n" );
  2114. return;
  2115. }
  2116. } else {
  2117. SyscacheLogEntryCount = ReadUlongValue(Address,SYM(SCB),"SyscacheLogEntryCount");
  2118. CurrentSyscacheLogEntry = ReadUlongValue(Address,SYM(SCB),"CurrentSyscacheLogEntry");
  2119. dprintf("Num Entries: 0x%x\n", SyscacheLogEntryCount );
  2120. dprintf("Current Entry: 0x%x\n", ReadUlongValue(Address,SYM(SCB),"CurrentSyscacheLogEntry") );
  2121. pLog = (PSYSCACHE_LOG) malloc( GetTypeSize(SYM(SYSCACHE_LOG)) * SyscacheLogEntryCount );
  2122. if (!pLog) {
  2123. return;
  2124. }
  2125. if (!ReadMemory( ReadValue(Address,SYM(SCB),"SyscacheLog"), pLog,
  2126. GetTypeSize(SYM(SYSCACHE_LOG)) * SyscacheLogEntryCount, &iTemp )) {
  2127. dprintf( "Unable to read SCB.SyscacheLog\n" );
  2128. return;
  2129. }
  2130. }
  2131. if (CurrentSyscacheLogEntry > SyscacheLogEntryCount) {
  2132. iStart = CurrentSyscacheLogEntry;
  2133. iEnd = CurrentSyscacheLogEntry + SyscacheLogEntryCount;;
  2134. } else {
  2135. iStart = 0;
  2136. iEnd = CurrentSyscacheLogEntry;
  2137. }
  2138. for (iIndex= iStart; iIndex < iEnd; iIndex++) {
  2139. iTemp = iIndex % SyscacheLogEntryCount;
  2140. if (iStart == 0) {
  2141. dprintf("Entry: 0x%x\n", iIndex);
  2142. } else {
  2143. dprintf("Entry: 0x%x\n", iIndex - SyscacheLogEntryCount);
  2144. }
  2145. dprintf("Event: 0x%x ", pLog[iTemp ].Event);
  2146. if (pLog[iTemp].Event < SCE_MAX_EVENT) {
  2147. dprintf("(%s)\n", LogEvent[pLog[iTemp].Event]);
  2148. } else {
  2149. dprintf("\n");
  2150. }
  2151. dprintf("Flags: 0x%x (", pLog[iTemp].Flags);
  2152. if (pLog[iTemp].Flags & SCE_FLAG_WRITE) {
  2153. dprintf("write ");
  2154. }
  2155. if (pLog[iTemp].Flags & SCE_FLAG_READ) {
  2156. dprintf("read ");
  2157. }
  2158. if (pLog[iTemp].Flags & SCE_FLAG_PAGING) {
  2159. dprintf("paging io ");
  2160. }
  2161. if (pLog[iTemp].Flags & SCE_FLAG_ASYNC) {
  2162. dprintf("asyncfileobj ");
  2163. }
  2164. if (pLog[iTemp].Flags & SCE_FLAG_SET_ALLOC) {
  2165. dprintf("setalloc ");
  2166. }
  2167. if (pLog[iTemp].Flags & SCE_FLAG_SET_EOF) {
  2168. dprintf("seteof ");
  2169. }
  2170. if (pLog[iTemp].Flags & SCE_FLAG_CANT_WAIT) {
  2171. dprintf("cantwait ");
  2172. }
  2173. if (pLog[iTemp].Flags & SCE_FLAG_SYNC_PAGING) {
  2174. dprintf("synchpaging ");
  2175. }
  2176. if (pLog[iTemp].Flags & SCE_FLAG_LAZY_WRITE) {
  2177. dprintf("lazywrite ");
  2178. }
  2179. if (pLog[iTemp].Flags & SCE_FLAG_CACHED) {
  2180. dprintf("cached ");
  2181. }
  2182. if (pLog[iTemp].Flags & SCE_FLAG_ON_DISK_READ) {
  2183. dprintf("fromdisk ");
  2184. }
  2185. if (pLog[iTemp].Flags & SCE_FLAG_RECURSIVE) {
  2186. dprintf("recursive ");
  2187. }
  2188. if (pLog[iTemp].Flags & SCE_FLAG_NON_CACHED) {
  2189. dprintf("noncached ");
  2190. }
  2191. if (pLog[iTemp].Flags & SCE_FLAG_UPDATE_FROM_DISK) {
  2192. dprintf("updatefromdisk ");
  2193. }
  2194. if (pLog[iTemp].Flags & SCE_FLAG_COMPRESSED) {
  2195. dprintf("compressed ");
  2196. }
  2197. if (pLog[iTemp].Flags & SCE_FLAG_SET_VDL) {
  2198. dprintf("setvdl ");
  2199. }
  2200. if (pLog[iTemp].Flags & SCE_FLAG_FASTIO) {
  2201. dprintf("fastio ");
  2202. }
  2203. if (pLog[iTemp].Flags & SCE_FLAG_ZERO) {
  2204. dprintf("zero ");
  2205. }
  2206. if (pLog[iTemp].Flags & SCE_FLAG_PREPARE_BUFFERS) {
  2207. dprintf("prepare buffers ");
  2208. }
  2209. if (pLog[iTemp].Flags & SCE_FLAG_END_BUFFER) {
  2210. dprintf("end buffers ");
  2211. }
  2212. if (pLog[iTemp].Flags & SCE_FLAG_MDL) {
  2213. dprintf("mdl ");
  2214. }
  2215. if (pLog[iTemp].Flags & SCE_FLAG_SUB_WRITE) {
  2216. dprintf("subwrite ");
  2217. }
  2218. dprintf(")\n");
  2219. dprintf("Start: 0x%I64x Range: 0x%I64x Result: 0x%I64x\n",
  2220. pLog[iTemp].Start, pLog[iTemp].Range, pLog[iTemp].Result);
  2221. dprintf("\n");
  2222. }
  2223. if (pLog) {
  2224. free(pLog);
  2225. }
  2226. }
  2227. DECLARE_DUMP_FUNCTION( DumpExtents )
  2228. /*++
  2229. Routine Description:
  2230. Dump the extents for a file
  2231. Arguments:
  2232. Address - Gives the address of the Vcb to dump
  2233. Return Value:
  2234. None
  2235. --*/
  2236. {
  2237. UCHAR FormCode;
  2238. PVOID Buffer;
  2239. PBYTE TempByte;
  2240. ULONG ChangedLCNBytes;
  2241. ULONG ChangedVCNBytes;
  2242. ULONG Increment;
  2243. ULONG Index;
  2244. ULONG Increment2;
  2245. ULONG LCN = 0;
  2246. ULONG VCN = 0;
  2247. ULONG RecordLength;
  2248. USHORT MappingPairsOffset;
  2249. INIT_DUMP();
  2250. FormCode = (UCHAR)ReadValue( Address, SYM(ATTRIBUTE_RECORD_HEADER), "FormCode" );
  2251. if (!(FormCode & NONRESIDENT_FORM)) {
  2252. dprintf( "resident attribute\n" );
  2253. return;
  2254. }
  2255. DumpValue( Address, SYM(ATTRIBUTE_RECORD_HEADER), "Form.Nonresident.MappingPairsOffset" );
  2256. DumpValue( Address, SYM(ATTRIBUTE_RECORD_HEADER), "Form.Nonresident.LowestVcn" );
  2257. DumpValue( Address, SYM(ATTRIBUTE_RECORD_HEADER), "Form.Nonresident.HighestVcn" );
  2258. DumpValue( Address, SYM(ATTRIBUTE_RECORD_HEADER), "Form.Nonresident.AllocatedLength" );
  2259. dprintf( "\n" );
  2260. RecordLength = ReadUlongValue( Address, SYM(ATTRIBUTE_RECORD_HEADER), "RecordLength" );
  2261. if (!RecordLength) {
  2262. return;
  2263. }
  2264. MappingPairsOffset = ReadShortValue( Address, SYM(ATTRIBUTE_RECORD_HEADER), "Form.Nonresident.MappingPairsOffset" );
  2265. if (!MappingPairsOffset) {
  2266. return;
  2267. }
  2268. RecordLength -= MappingPairsOffset;
  2269. Buffer = malloc( RecordLength );
  2270. if (!ReadMemory( Address+MappingPairsOffset, Buffer, RecordLength, &RecordLength )) {
  2271. dprintf( "Unable to read memory at %s\n", FormatValue(Address+MappingPairsOffset) );
  2272. free( Buffer );
  2273. return;
  2274. }
  2275. TempByte = Buffer;
  2276. //
  2277. // walk byte stream
  2278. //
  2279. while(*TempByte != 0) {
  2280. ChangedLCNBytes = *TempByte >> 4;
  2281. ChangedVCNBytes = *TempByte & (0x0f);
  2282. TempByte++;
  2283. for (Increment=0, Index=0; Index < ChangedVCNBytes; Index++) {
  2284. Increment+= *TempByte++ << (8 * Index);
  2285. }
  2286. for (Increment2 =0, Index=0; Index < ChangedLCNBytes; Index++) {
  2287. Increment2+= *TempByte++ << (8 * Index);
  2288. }
  2289. //
  2290. // if last bit is set (this is a neg) extend with 0xff
  2291. //
  2292. if (0x80 & (*(TempByte-1))) {
  2293. for(; Index < GetTypeSize("ULONG"); Index++) {
  2294. Increment2 += 0xff << (8 * Index);
  2295. }
  2296. }
  2297. LCN += Increment2;
  2298. dprintf( "LCN: 0x%x VCN: 0x%x Clusters: 0x%x ", LCN, VCN, Increment );
  2299. for (Index = ChangedLCNBytes + ChangedVCNBytes + 1; Index > 0; Index--) {
  2300. dprintf( "%02x", *(TempByte - Index));
  2301. }
  2302. dprintf( "\n" );
  2303. VCN += Increment;
  2304. }
  2305. free( Buffer );
  2306. }
  2307. ULONG
  2308. ThreadListCallback(
  2309. IN PFIELD_INFO listElement,
  2310. IN PVOID Context
  2311. )
  2312. /*++
  2313. Routine Description:
  2314. Enumeration callback function for cachedrecords to check for cached file records
  2315. Arguments:
  2316. ListElement - Pointer to the containing record
  2317. Context - Opaque context passed from the origination function
  2318. Return Value:
  2319. TRUE to discontinue the enumeration
  2320. FALSE to continue the enumeration
  2321. --*/
  2322. {
  2323. PDUMP_ENUM_CONTEXT dec = (PDUMP_ENUM_CONTEXT)Context;
  2324. ULONG64 ThreadAddress=listElement->address;
  2325. ULONG64 TopLevelIrp;
  2326. ULONG NtfsSig;
  2327. ULONG64 ThreadIrpContext;
  2328. int Index;
  2329. ULONG RecordSize;
  2330. ULONG64 RecordAddress;
  2331. ULONG64 FileRecordBcb;
  2332. ULONG64 FileRecord;
  2333. ULONG UnsafeSegmentNumber;
  2334. TopLevelIrp = ReadValue( ThreadAddress, NT(ETHREAD), "TopLevelIrp" );
  2335. if (TopLevelIrp) {
  2336. NtfsSig = ReadUlongValue( TopLevelIrp, SYM(TOP_LEVEL_CONTEXT), "Ntfs" );
  2337. if (NtfsSig == 0x5346544e) {
  2338. ThreadIrpContext = ReadValue( TopLevelIrp, SYM(TOP_LEVEL_CONTEXT), "ThreadIrpContext" );
  2339. if (ThreadIrpContext) {
  2340. RecordSize = GetTypeSize(SYM(IRP_FILE_RECORD_CACHE_ENTRY));
  2341. RecordAddress = ThreadIrpContext + GetOffset(SYM(IRP_CONTEXT),"FileRecordCache");
  2342. dprintf ("record: 0x%x\n", RecordAddress );
  2343. for (Index=0; Index<IRP_FILE_RECORD_MAP_CACHE_SIZE; Index++) {
  2344. FileRecord = ReadValue( RecordAddress, SYM(IRP_FILE_RECORD_CACHE_ENTRY), "FileRecord" );
  2345. FileRecordBcb = ReadValue( RecordAddress, SYM(IRP_FILE_RECORD_CACHE_ENTRY), "FileRecordBcb" );
  2346. if (FileRecord) {
  2347. UnsafeSegmentNumber = ReadUlongValue( RecordAddress, SYM(IRP_FILE_RECORD_CACHE_ENTRY), "UnsafeSegmentNumber" );
  2348. dprintf( "Thread: 0x%s FileRecord: 0x%s Bcb: 0x%s SegmentNum: 0x%x\n",
  2349. FormatValue(ThreadAddress),
  2350. FormatValue(FileRecord),
  2351. FormatValue(FileRecordBcb),
  2352. UnsafeSegmentNumber
  2353. );
  2354. }
  2355. RecordAddress += RecordSize;
  2356. }
  2357. }
  2358. }
  2359. }
  2360. return FALSE;
  2361. }
  2362. ULONG
  2363. ProcessListCallback(
  2364. IN PFIELD_INFO listElement,
  2365. IN PVOID Context
  2366. )
  2367. /*++
  2368. Routine Description:
  2369. Enumeration callback function for cachedrecords to check for cached file records
  2370. Arguments:
  2371. ListElement - Pointer to the containing record
  2372. Context - Opaque context passed from the origination function
  2373. Return Value:
  2374. TRUE to discontinue the enumeration
  2375. FALSE to continue the enumeration
  2376. --*/
  2377. {
  2378. PDUMP_ENUM_CONTEXT dec = (PDUMP_ENUM_CONTEXT)Context;
  2379. ULONG64 ProcAddress=listElement->address;
  2380. ULONG64 FirstThread;
  2381. FirstThread = ReadValue( ProcAddress, NT(EPROCESS), "Pcb.ThreadListHead.Flink" );
  2382. if (FirstThread) {
  2383. ListType( NT(ETHREAD), FirstThread, 1, "Tcb.ThreadListEntry.Flink", (PVOID)dec, &ThreadListCallback );
  2384. }
  2385. return FALSE;
  2386. }
  2387. DECLARE_DUMP_FUNCTION( DumpCachedRecords )
  2388. /*++
  2389. Routine Description:
  2390. Walk all processes and dump any which are holding filerecords cached in
  2391. irpcontexts
  2392. Arguments:
  2393. arg - none
  2394. Return Value:
  2395. None
  2396. --*/
  2397. {
  2398. ULONG64 FirstProcess;
  2399. DUMP_ENUM_CONTEXT dec;
  2400. INIT_DUMP();
  2401. FirstProcess = ReadValue( KdDebuggerData.PsActiveProcessHead, NT(LIST_ENTRY), "Flink" );
  2402. if (FirstProcess == 0) {
  2403. dprintf( "Unable to read _LIST_ENTRY @ %s \n", FormatValue(KdDebuggerData.PsActiveProcessHead) );
  2404. return;
  2405. }
  2406. dec.hCurrentThread = hCurrentThread;
  2407. dec.Processor = Processor;
  2408. dec.Options = Options;
  2409. ListType( NT(EPROCESS), FirstProcess, 1, "ActiveProcessLinks.Flink", (PVOID)&dec, &ProcessListCallback );
  2410. }
  2411. DECLARE_DUMP_FUNCTION( DumpHashTable )
  2412. /*++
  2413. Routine Description:
  2414. Dump a prefix hash table
  2415. Arguments:
  2416. arg - none
  2417. Return Value:
  2418. None
  2419. --*/
  2420. {
  2421. ULONG64 HashSegmentsOffset;
  2422. ULONG64 HashSegmentAddress;
  2423. ULONG64 HashSegmentPtr;
  2424. ULONG HashEntrySize;
  2425. DWORD Index;
  2426. DWORD Index2;
  2427. ULONG BytesRead;
  2428. ULONG64 NextAddr;
  2429. ULONG PtrSize;
  2430. INIT_DUMP();
  2431. dprintf( "Hash Table: 0x%s\n", FormatValue(Address) );
  2432. dprintf( "Max Buckets: 0x%x Splitpoint: 0x%x\n",
  2433. ReadUlongValue( Address, SYM(NTFS_HASH_TABLE), "MaxBucket" ),
  2434. ReadUlongValue( Address, SYM(NTFS_HASH_TABLE), "SplitPoint" ) );
  2435. HashSegmentsOffset = GetOffset(SYM(NTFS_HASH_TABLE),"HashSegments");
  2436. HashEntrySize = GetTypeSize(SYM(NTFS_HASH_ENTRY));
  2437. PtrSize = GetTypeSize(SYM(PVOID));
  2438. HashSegmentAddress = Address + HashSegmentsOffset;
  2439. for (Index=0; Index<HASH_MAX_SEGMENT_COUNT; Index++) {
  2440. HashSegmentAddress += (Index * PtrSize);
  2441. if (ReadMemory( HashSegmentAddress, &HashSegmentPtr, PtrSize, &BytesRead ) && HashSegmentPtr) {
  2442. for (Index2=0; Index2<HASH_MAX_INDEX_COUNT; Index2++) {
  2443. NextAddr = HashSegmentPtr + (Index2 * PtrSize);
  2444. while (NextAddr) {
  2445. if (Address2 == 0 || ReadValue( NextAddr, SYM(NTFS_HASH_ENTRY), "HashLcb" ) == Address2) {
  2446. dprintf( "Lcb: 0x%s Hash: 0x%x\n",
  2447. FormatValue(ReadValue( NextAddr, SYM(NTFS_HASH_ENTRY), "HashLcb" )),
  2448. ReadUlongValue( NextAddr, SYM(NTFS_HASH_ENTRY), "HashValue" ) );
  2449. }
  2450. NextAddr = ReadValue( NextAddr, SYM(NTFS_HASH_ENTRY), "NextEntry" );
  2451. if (CheckControlC()) {
  2452. return;
  2453. }
  2454. }
  2455. if (CheckControlC()) {
  2456. return;
  2457. }
  2458. }
  2459. }
  2460. if (CheckControlC()) {
  2461. return;
  2462. }
  2463. }
  2464. }
  2465. ULONG
  2466. FindIndexScb(
  2467. IN PFIELD_INFO ListElement,
  2468. IN PVOID Context
  2469. )
  2470. /*++
  2471. Routine Description:
  2472. Enumeration callback function to locate the index scb
  2473. Arguments:
  2474. ListElement - Pointer to the containing record
  2475. Context - Opaque context passed from the origination function
  2476. Return Value:
  2477. TRUE to discontinue the enumeration
  2478. FALSE to continue the enumeration
  2479. --*/
  2480. {
  2481. ULONG64 Scb = ListElement->address;
  2482. PDUMP_ENUM_CONTEXT dec = (PDUMP_ENUM_CONTEXT)Context;
  2483. if (CheckControlC()) {
  2484. return TRUE;
  2485. }
  2486. if (ReadValue( Scb, SYM(SCB), "AttributeTypeCode" ) == $INDEX_ALLOCATION) {
  2487. dec->ReturnValue = Scb;
  2488. return TRUE;
  2489. }
  2490. return FALSE;
  2491. }
  2492. DECLARE_DUMP_FUNCTION( DumpFcbLcbChain )
  2493. /*++
  2494. Routine Description:
  2495. Dump a fcb - lcb - chain to find the bottom
  2496. Arguments:
  2497. arg - the initial fcb
  2498. Return Value:
  2499. None
  2500. --*/
  2501. {
  2502. ULONG64 FcbAddress = Address;
  2503. ULONG64 ScbAddress = 0;
  2504. ULONG64 LcbAddress = 0;
  2505. ULONG64 Link = 0;
  2506. DUMP_ENUM_CONTEXT dec;
  2507. ULONG64 Value;
  2508. INIT_DUMP();
  2509. do {
  2510. if (ReadValue( FcbAddress, SYM(FCB), "NodeTypeCode" ) != NTFS_NTC_FCB) {
  2511. dprintf( "Not an FCB at 0x%s\n", FormatValue(FcbAddress) );
  2512. return;
  2513. }
  2514. //
  2515. // initialize the enum context for all out enumerations
  2516. //
  2517. dec.hCurrentThread = hCurrentThread;
  2518. dec.Processor = Processor;
  2519. dec.Options = Options;
  2520. dec.ReturnValue = 0;
  2521. //
  2522. // Find the index SCB
  2523. //
  2524. Value = ReadValue( FcbAddress, SYM(FCB), "ScbQueue.Flink" );
  2525. if (Value) {
  2526. ListType( SYM(SCB), Value, TRUE, "FcbLinks.Flink", (PVOID)&dec, FindIndexScb );
  2527. if (dec.ReturnValue) {
  2528. ScbAddress = dec.ReturnValue;
  2529. }
  2530. }
  2531. if (ScbAddress == 0) {
  2532. dprintf( "unable to find index scb in fcb: 0x%s\n", FormatValue(FcbAddress) );
  2533. return;
  2534. }
  2535. dprintf( "Scb: 0x%s, NameLen: 0x%x Counts: 0x%x 0x%x\n",
  2536. FormatValue(ScbAddress),
  2537. ReadShortValue( ScbAddress, SYM(SCB), "ScbType.Index.NormalizedName.MaximumLength" ),
  2538. ReadUlongValue( ScbAddress, SYM(SCB), "CleanupCount" ),
  2539. ReadUlongValue( ScbAddress, SYM(SCB), "CloseCount" )
  2540. );
  2541. Value = ReadValue( ScbAddress, SYM(SCB), "ScbType.Index.LcbQueue.Flink" );
  2542. if (Value != (ScbAddress + GetOffset(SYM(SCB),"Index.LcbQueue.Flink"))) {
  2543. //
  2544. // Read the 1st lcb
  2545. //
  2546. LcbAddress = Value - GetOffset(SYM(LCB),"ScbLinks");
  2547. dprintf( "lcb: 0x%s Cleanup: 0x%x fcb: 0x%s\n",
  2548. FormatValue(LcbAddress),
  2549. ReadUlongValue( LcbAddress, SYM(LCB), "CleanupCount" ),
  2550. FormatValue(ReadValue( LcbAddress, SYM(LCB), "Fcb" ))
  2551. );
  2552. FcbAddress = ReadValue( LcbAddress, SYM(LCB), "Fcb" );
  2553. } else {
  2554. dprintf( "lcbqueue empty: 0x%s\n", FormatValue(ScbAddress) );
  2555. return;
  2556. }
  2557. if (CheckControlC()) {
  2558. return;
  2559. }
  2560. } while ( TRUE );
  2561. }
  2562. ULONG
  2563. EnumOverflow(
  2564. IN PFIELD_INFO ListElement,
  2565. IN PVOID Context
  2566. )
  2567. /*++
  2568. Routine Description:
  2569. Enumeration callback function to dump the overflow queue
  2570. Arguments:
  2571. ListElement - Pointer to the containing record
  2572. Context - Opaque context passed from the origination function
  2573. Return Value:
  2574. TRUE to discontinue the enumeration
  2575. FALSE to continue the enumeration
  2576. --*/
  2577. {
  2578. ULONG64 IrpContext = ListElement->address;
  2579. PDUMP_ENUM_CONTEXT dec = (PDUMP_ENUM_CONTEXT)Context;
  2580. ULONG64 OriginatingIrp;
  2581. ULONG64 MdlAddress;
  2582. if (CheckControlC()) {
  2583. return TRUE;
  2584. }
  2585. OriginatingIrp = ReadValue( IrpContext, SYM(IRP_CONTEXT), "OriginatingIrp" );
  2586. if (OriginatingIrp) {
  2587. dprintf( "0x%s 0x%x ", FormatValue(OriginatingIrp), ReadValue( OriginatingIrp, SYM(IRP), "Cancel" ) );
  2588. MdlAddress = ReadValue( OriginatingIrp, SYM(IRP), "MdlAddress" );
  2589. if (MdlAddress) {
  2590. dprintf( "0x%s", FormatValue(ReadValue( MdlAddress, NT(MDL), "Process" )) );
  2591. }
  2592. }
  2593. return FALSE;
  2594. }
  2595. DECLARE_DUMP_FUNCTION( DumpOverflow )
  2596. /*++
  2597. Routine Description:
  2598. Dump the overflow queue
  2599. Arguments:
  2600. arg - Vcb
  2601. Return Value:
  2602. None
  2603. --*/
  2604. {
  2605. ULONG64 VcbAddress;
  2606. ULONG64 VdoAddress;
  2607. ULONG64 Value;
  2608. DUMP_ENUM_CONTEXT dec;
  2609. INIT_DUMP();
  2610. VcbAddress = Address;
  2611. VdoAddress = VcbAddress - GetOffset(SYM(VOLUME_DEVICE_OBJECT),"Vcb");
  2612. dprintf( "Volume Device: 0x%s Vcb: 0x%s OverflowCount: 0x%x\n",
  2613. FormatValue(VdoAddress), FormatValue(VcbAddress),
  2614. ReadUlongValue( VdoAddress, SYM(VOLUME_DEVICE_OBJECT), "OverflowQueueCount" ) );
  2615. dprintf("\nIrpContext Irp Cancelled Process\n");
  2616. Value = ReadValue( VdoAddress, SYM(VOLUME_DEVICE_OBJECT), "OverflowQueue.Flink" );
  2617. if (Value && Value != VdoAddress + GetOffset(SYM(VOLUME_DEVICE_OBJECT),"OverflowQueue.Flink")) {
  2618. dec.hCurrentThread = hCurrentThread;
  2619. dec.Processor = Processor;
  2620. dec.Options = Options;
  2621. dec.ReturnValue = 0;
  2622. ListType( SYM(IRP_CONTEXT), Value, TRUE, "ListEntry.Flink", (PVOID)&dec, EnumOverflow );
  2623. }
  2624. }
  2625. DECLARE_DUMP_FUNCTION( DumpCachedRuns )
  2626. /*++
  2627. Routine Description:
  2628. Dumps the cached runs array
  2629. Arguments:
  2630. Address - Gives the address of the cached runs array to be dumped
  2631. Return Value:
  2632. None
  2633. --*/
  2634. {
  2635. ULONG64 AvailRuns;
  2636. ULONG64 MaxUsed;
  2637. ULONG64 ClusterRunSize;
  2638. int Index;
  2639. LCN Lcn;
  2640. LONGLONG Length;
  2641. ULONG64 LcnArray;
  2642. USHORT LenIndex;
  2643. ULONG64 LengthArray;
  2644. ULONG BytesRead;
  2645. USHORT WindowStart;
  2646. USHORT WindowEnd;
  2647. ULONG DelWindowIndex = 0;
  2648. ULONG64 DelArray;
  2649. ULONG64 DelWindowSize;
  2650. ULONG64 DelLengthCount;
  2651. LONGLONG PrevLength = -1;
  2652. INIT_DUMP();
  2653. dprintf( "CachedRun: %p ", Address );
  2654. AvailRuns = ReadValue( Address, SYM(NTFS_CACHED_RUNS), "Avail" );
  2655. MaxUsed = ReadValue( Address, SYM(NTFS_CACHED_RUNS), "Used" );
  2656. ClusterRunSize = GetTypeSize( SYM(NTFS_LCN_CLUSTER_RUN) );
  2657. LcnArray = ReadValue( Address, SYM(NTFS_CACHED_RUNS), "LcnArray" );
  2658. LengthArray = ReadValue( Address, SYM(NTFS_CACHED_RUNS), "LengthArray" );
  2659. DelLengthCount = ReadValue( Address, SYM(NTFS_CACHED_RUNS), "DelLengthCount" );
  2660. DelArray = ReadValue( Address, SYM(NTFS_CACHED_RUNS), "DeletedLengthWindows" );
  2661. DelWindowSize = GetTypeSize( SYM(NTFS_DELETED_RUNS) );
  2662. if (DelWindowIndex < DelLengthCount) {
  2663. WindowStart = (USHORT)ReadValue( DelArray + DelWindowSize * DelWindowIndex, SYM(NTFS_DELETED_RUNS), "StartIndex" );
  2664. WindowEnd = (USHORT)ReadValue( DelArray + DelWindowSize * DelWindowIndex, SYM(NTFS_DELETED_RUNS), "EndIndex" );
  2665. DelWindowIndex++;
  2666. }
  2667. dprintf( "Avail: 0x%I64x Used: 0x%I64x\n", AvailRuns, MaxUsed );
  2668. dprintf( "Lcns ranges sorted by length\n\n" );
  2669. for (Index=0; Index < MaxUsed; Index++) {
  2670. if (Index == WindowStart) {
  2671. dprintf( "DeleteWindow: 0x%x to 0x%x\n", WindowStart, WindowEnd );
  2672. Index = WindowEnd;
  2673. if (DelWindowIndex < DelLengthCount) {
  2674. WindowStart = (USHORT)ReadValue( DelArray + DelWindowSize * DelWindowIndex, SYM(NTFS_DELETED_RUNS), "StartIndex" );
  2675. WindowEnd = (USHORT)ReadValue( DelArray + DelWindowSize * DelWindowIndex, SYM(NTFS_DELETED_RUNS), "EndIndex" );
  2676. DelWindowIndex++;
  2677. }
  2678. continue;
  2679. }
  2680. ReadMemory( LengthArray + Index * sizeof( USHORT ), &LenIndex, sizeof( USHORT ), &BytesRead );
  2681. if (NTFS_CACHED_RUNS_DEL_INDEX != LenIndex) {
  2682. Lcn = ReadValue( LcnArray + LenIndex * (ClusterRunSize), SYM(NTFS_LCN_CLUSTER_RUN), "Lcn" );
  2683. Length = ReadValue( LcnArray + LenIndex * (ClusterRunSize), SYM(NTFS_LCN_CLUSTER_RUN), "RunLength" );
  2684. if (Length < PrevLength) {
  2685. dprintf( "WARNING: OUT OF ORDER ENTRY\n" );
  2686. }
  2687. PrevLength = Length;
  2688. dprintf( "0x%x: LcnIndex: 0x%x Lcn: 0x%I64x Length: 0x%I64x\n", Index, LenIndex, Lcn, Length );
  2689. }
  2690. if (CheckControlC()) {
  2691. return;
  2692. }
  2693. }
  2694. }