Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3099 lines
82 KiB

  1. #ifndef DBG
  2. #define DBG 1
  3. #endif
  4. #define SRVDBG 1
  5. #define SRVKD 1
  6. #include "precomp.h"
  7. #include <ntverp.h>
  8. #include <windows.h>
  9. #include <wdbgexts.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. WINDBG_EXTENSION_APIS ExtensionApis;
  13. EXT_API_VERSION ApiVersion = { 5, 0, EXT_API_VERSION_NUMBER, 0 };
  14. #define ERRPRT dprintf
  15. #ifndef MIN
  16. #define MIN(a,b) ( ((a) < (b)) ? (a) : (b) )
  17. #endif
  18. #define NL 1
  19. #define NONL 0
  20. USHORT SavedMajorVersion;
  21. USHORT SavedMinorVersion;
  22. BOOL ChkTarget; // is debuggee a CHK build?
  23. /*
  24. * The help strings printed out
  25. */
  26. static LPSTR Extensions[] = {
  27. "Lan Manager Server Debugger Extensions:\n",
  28. "buffer address Dump the BUFFER structure",
  29. "client Dump the clients + CONNECTION structs",
  30. "connection address Dump the CONNECTION structure",
  31. "context address Dump the WORK_CONTEXT structure",
  32. "df address Follow an entire LIST_ENTRY to end",
  33. "endpoint [ address ] Dump the ENDPOINT structure(s)",
  34. "errcodes Dump the error log code filter",
  35. "globals Print out srv's global variables",
  36. "help",
  37. "lfcb address Dump the LFCB structure",
  38. "lock [ address ] Dump the ERESOURCE structure(s)",
  39. "mfcb address Dump the LFCB structure",
  40. "pagedconnection address Dump the PAGED_CONNECTION structure",
  41. "queue [ address ] Dump the WORK_QUEUE structure",
  42. "rfcb [ address ] Dump the RFCB structure(s)",
  43. "scavenger Dump scavenger info",
  44. "search address Dump the SEARCH structure",
  45. "session address Dump the SESSION structure",
  46. "share [ address | disk | print | comm | pipe ] Dump the SHARE structure(s)",
  47. "share =name Dump the SHARE structure for 'name'",
  48. "smb address Dump the SMB_HEADER",
  49. #if SRVDBG == 1
  50. "smbdebug [ t | f | #'s ] Get or set SMB debug flags",
  51. #endif
  52. "srv Turn target into a Server",
  53. #if SRVDBG == 1
  54. "srvdebug [ t | f | #'s ] Get or set server debug flags",
  55. #endif
  56. "statistics Dump the SrvStatistics structure",
  57. "tcon address Dump the TREE_CONNECT structure",
  58. "transaction address Dump the TRANSACTION structure",
  59. "version",
  60. "wksta Turn target into a Workstation",
  61. 0
  62. };
  63. static LPSTR BlockState[] = {
  64. "BlockStateDead",
  65. "BlockStateInitializing",
  66. "BlockStateActive",
  67. "BlockStateClosing"
  68. };
  69. static LPSTR BlockType[] = {
  70. "BlockTypeGarbage",
  71. "BlockTypeBuffer",
  72. "BlockTypeConnection",
  73. "BlockTypeEndpoint",
  74. "BlockTypeLfcb",
  75. "BlockTypeMfcb",
  76. "BlockTypeRfcb",
  77. "BlockTypeSearch",
  78. "BlockTypeSearchCore",
  79. "BlockTypeByteRangeLock",
  80. "BlockTypeSession",
  81. "BlockTypeShare",
  82. "BlockTypeTransaction",
  83. "BlockTypeTreeConnect",
  84. "BlockTypeWaitForOplockBreak",
  85. "BlockTypeCommDevice",
  86. "BlockTypeWorkContextInitial",
  87. "BlockTypeWorkContextNormal",
  88. "BlockTypeWorkContextRaw",
  89. "BlockTypeDataBuffer",
  90. "BlockTypeTable",
  91. "BlockTypeNonpagedHeader",
  92. "BlockTypePagedConnection",
  93. "BlockTypePagedRfcb",
  94. "BlockTypeNonpagedMfcb",
  95. "BlockTypeTimer",
  96. "BlockTypeAdminCheck",
  97. "BlockTypeWorkQueue",
  98. #ifdef INCLUDE_SMB_PERSISTENT
  99. "BlockTypeDfs",
  100. "BlockTypePersistentState",
  101. "BlockTypePersistentBitMap",
  102. "BlockTypePersistentShareState",
  103. #else
  104. "BlockTypeDfs"
  105. #endif
  106. };
  107. /*
  108. * The locks that we'd like to dump
  109. */
  110. static LPSTR SrvLocks[] = {
  111. "SrvConfigurationLock",
  112. "SrvEndpointLock",
  113. "SrvShareLock",
  114. "SrvOrderedListLock",
  115. "SrvOplockBreakListLock",
  116. "SrvUnlockableCodeLock",
  117. 0
  118. };
  119. /*
  120. * The globals that we'd like to dump
  121. */
  122. static LPSTR GlobalBool[] = {
  123. "SrvProductTypeServer",
  124. "SrvMultiProcessorDriver",
  125. "SrvEnableOplocks",
  126. "SrvEnableFcbOpens",
  127. "SrvEnableSoftCompatibility",
  128. "SrvEnableRawMode",
  129. "SrvSmbSecuritySignaturesRequired",
  130. "SrvSmbSecuritySignaturesEnabled",
  131. "SrvEnableW9xSecuritySignatures",
  132. "SrvSupportsCompression",
  133. "SrvRemoveDuplicateSearches",
  134. "SrvRestrictNullSessionAccess",
  135. "SrvEnableWfW311DirectIpx",
  136. "SrvEnableOplockForceClose",
  137. "SrvEnableForcedLogoff",
  138. "SrvFspActive",
  139. "SrvXsActive",
  140. "SrvPaused",
  141. "SrvCompletedPNPRegistration",
  142. "SrvFspTransitioning",
  143. "SrvResourceThreadRunning",
  144. "SrvResourceDisconnectPending",
  145. "SrvResourceFreeConnection",
  146. "SrvResourceOrphanedBlocks",
  147. 0
  148. };
  149. static LPSTR GlobalShort[] = {
  150. "SrvInitialSessionTableSize",
  151. "SrvMaxSessionTableSize",
  152. "SrvInitialTreeTableSize",
  153. "SrvInitialTreeTableSize",
  154. "SrvMaxTreeTableSize",
  155. "SrvInitialFileTableSize",
  156. "SrvMaxFileTableSize",
  157. "SrvInitialSearchTableSize",
  158. "SrvMaxSearchTableSize",
  159. "SrvMaxMpxCount",
  160. 0
  161. };
  162. static LPSTR GlobalLong[] = {
  163. "SrvServerSize",
  164. "SrvNumberOfProcessors",
  165. "SrvMinNT5Client",
  166. "SrvAbortiveDisconnects",
  167. "SrvBalanceCount",
  168. "SrvReBalanced",
  169. "SrvOtherQueueAffinity",
  170. "SrvPreferredAffinity",
  171. "SrvMaxFreeRfcbs",
  172. "SrvMaxFreeMfcbs",
  173. "SrvReceiveBufferLength",
  174. "SrvInitialReceiveWorkItemCount",
  175. "SrvMaxReceiveWorkItemCount",
  176. "SrvInitialRawModeWorkItemCount",
  177. "SrvMaxRawModeWorkItemCount",
  178. "SrvFreeConnectionMinimum",
  179. "SrvFreeConnectionMaximum",
  180. "SrvScavengerTimeoutInSeconds",
  181. "SrvMaxNumberVcs",
  182. "SrvMinReceiveQueueLength",
  183. "SrvMinFreeWorkItemsBlockingIo",
  184. "SrvIpxAutodisconnectTimeout",
  185. "SrvConnectionNoSessionsTimeout",
  186. "SrvMaxUsers",
  187. "SrvMaxPagedPoolUsage",
  188. "SrvMaxNonPagedPoolUsage",
  189. "SrvScavengerUpdateQosCount",
  190. "SrvWorkItemMaxIdleTime",
  191. "SrvAlertMinutes",
  192. "SrvFreeDiskSpaceThreshold",
  193. "SrvSharingViolationRetryCount",
  194. "SrvLockViolationDelay",
  195. "SrvLockViolationOffset",
  196. "SrvMaxOpenSearches",
  197. "SrvMaxFsctlBufferSize",
  198. "SrvMdlReadSwitchover",
  199. "SrvMpxMdlReadSwitchover",
  200. "SrvCachedOpenLimit",
  201. "SrvXsSharedMemoryReference",
  202. "SrvEndpointCount",
  203. "SrvBlockingOpsInProgress",
  204. "SrvFastWorkAllocation",
  205. "SrvSlowWorkAllocation",
  206. "SrvMinClientBufferSize",
  207. "SrvMaxFsctlBufferSize",
  208. "SrvMaxReadSize",
  209. "SrvMaxCompressedDataLength",
  210. "SrvMaxWriteChunk",
  211. "SrvNT5SecuritySigBuildNumber",
  212. 0
  213. };
  214. static LPSTR GlobalLongHex[] = {
  215. "SrvNamedPipeHandle",
  216. "SrvNamedPipeDeviceObject",
  217. "SrvNamedPipeFileObject",
  218. "SrvDfsDeviceObject",
  219. "SrvDfsFileObject",
  220. "SrvDfsFastIoDeviceControl",
  221. "SrvDiskConfiguration",
  222. "SrvSvcProcess",
  223. // "SrvWorkQueuesBase",
  224. "SrvWorkQueues",
  225. "eSrvWorkQueues",
  226. "SrvIpxSmartCard",
  227. 0
  228. };
  229. static LPSTR GlobalStringVector[] = {
  230. "SrvNullSessionPipes",
  231. "SrvNullSessionShares",
  232. "SrvPipesNeedLicense",
  233. "SrvNoRemapPipeNames",
  234. 0
  235. };
  236. static LPSTR GlobalStrings[] = {
  237. "SrvComputerName",
  238. "SrvNativeOS",
  239. "SrvNativeLanMan",
  240. "SrvSystemRoot",
  241. 0
  242. };
  243. static LPSTR ScavengerLong[] = {
  244. "LastNonPagedPoolLimitHitCount",
  245. "LastNonPagedPoolFailureCount",
  246. "LastPagedPoolLimitHitCount",
  247. "LastPagedPoolFailureCount",
  248. "SrvScavengerCheckRfcbActive",
  249. "ScavengerUpdateQosCount",
  250. "ScavengerCheckRfcbActive",
  251. "FailedWorkItemAllocations",
  252. 0
  253. };
  254. static LPSTR ScavengerBool[] = {
  255. "RunShortTermAlgorithm",
  256. "RunScavengerAlgorithm",
  257. "RunAlerterAlgorithm",
  258. "EventSwitch",
  259. 0
  260. };
  261. struct BitFields {
  262. PCSTR name;
  263. ULONGLONG value;
  264. };
  265. #if defined( SRVDBG ) && SRVDBG == 1
  266. #define DF( name ) { #name, DEBUG_ ## name }
  267. struct BitFields SrvDebugFlags[] = {
  268. DF( TRACE1 ),
  269. DF( TRACE2 ),
  270. DF( REFCNT ),
  271. DF( HEAP ),
  272. DF( WORKER1 ),
  273. DF( WORKER2 ),
  274. DF( NET1 ),
  275. DF( NET2 ),
  276. DF( FSP1 ),
  277. DF( FSP2 ),
  278. DF( FSD1 ),
  279. DF( FSD2 ),
  280. DF( SCAV1 ),
  281. DF( SCAV2 ),
  282. DF( BLOCK1 ),
  283. DF( IPX_PIPES ),
  284. DF( HANDLES ),
  285. DF( IPX ),
  286. DF( TDI ),
  287. DF( OPLOCK ),
  288. DF( NETWORK_ERRORS ),
  289. DF( FILE_CACHE ),
  290. DF( IPX2 ),
  291. DF( LOCKS ),
  292. DF( SEARCH ),
  293. DF( BRUTE_FORCE_REWIND ),
  294. DF( COMM ),
  295. DF( XACTSRV ),
  296. DF( LICENSE ),
  297. DF( API_ERRORS ),
  298. DF( STOP_ON_ERRORS ),
  299. DF( ERRORS ),
  300. DF( SMB_ERRORS ),
  301. DF( WORKITEMS ),
  302. DF( IPXNAMECLAIM ),
  303. DF( SENDS2OTHERCPU ),
  304. DF( REBALANCE ),
  305. DF( PNP ),
  306. DF( DFS ),
  307. DF( SIPX ),
  308. DF( COMPRESSION ),
  309. DF( CREATE ),
  310. DF( SECSIG ),
  311. DF( STUCK_OPLOCK ),
  312. 0
  313. };
  314. #undef DF
  315. #define DF( name ) { #name, DEBUG_SMB_ ## name }
  316. struct BitFields SmbDebugFlags[] = {
  317. DF( ERRORS ),
  318. DF( ADMIN1 ),
  319. DF( ADMIN2 ),
  320. DF( TREE1 ),
  321. DF( TREE2 ),
  322. DF( DIRECTORY1 ),
  323. DF( DIRECTORY2 ),
  324. DF( OPEN_CLOSE1 ),
  325. DF( OPEN_CLOSE2 ),
  326. DF( FILE_CONTROL1 ),
  327. DF( FILE_CONTROL2 ),
  328. DF( READ_WRITE1 ),
  329. DF( READ_WRITE2 ),
  330. DF( LOCK1 ),
  331. DF( LOCK2 ),
  332. DF( RAW1 ),
  333. DF( RAW2 ),
  334. DF( MPX1 ),
  335. DF( MPX2 ),
  336. DF( SEARCH1 ),
  337. DF( SEARCH2 ),
  338. DF( TRANSACTION1 ),
  339. DF( TRANSACTION2 ),
  340. DF( PRINT1 ),
  341. DF( PRINT2 ),
  342. DF( MESSAGE1 ),
  343. DF( MESSAGE2 ),
  344. DF( MISC1 ),
  345. DF( MISC2 ),
  346. DF( QUERY_SET1 ),
  347. DF( QUERY_SET2 ),
  348. DF( TRACE ),
  349. 0
  350. };
  351. #endif // SRVDBG
  352. /*
  353. * The MEMBERLIST structure, and the macros that follow, give an easy way to declare
  354. * the members of a structure to be printed. Once you set up a MEMBERLIST[] for a
  355. * particular structure, you call PrintMemberList() to do a formatted dump of the struct
  356. */
  357. typedef struct _MEMBERLIST {
  358. LPSTR name; // The name of the field
  359. ULONG offset; // The offset of the field in the structure
  360. UCHAR type; // The type of variable to be printed
  361. LONG extra; // Any other extra info needed for this type
  362. } MEMBERLIST;
  363. // BE -> BOOL
  364. // HE -> HEX ULONG
  365. // PE -> POINTER
  366. // UE -> Unsigned ULONG
  367. // HC -> Unsigned char as hex
  368. // DE -> Decimal Long
  369. // SE -> Decimal Short
  370. // WE -> UNICODE_STRING
  371. // AE -> ANSI_STRING
  372. // IE -> Symbol Address
  373. // CE -> Character
  374. // TE -> TABLE_HEADER structure, and follow the table
  375. // LE -> LIST_ENTRY list
  376. // BT -> BLOCK_HEADER 'Type' field
  377. // BS -> BLOCK_HEADER 'State' field
  378. // BC -> BLOCK_HEADER 'ReferenceCount' field
  379. // U64-> LONGLONG
  380. // IA -> IP Address
  381. #define ROOT( StructureName ) { "@" #StructureName, 0, 'R' }
  382. #define BE( StructureName, FieldName ) { #FieldName, FIELD_OFFSET( StructureName, FieldName ), 'B' }
  383. #define CE( StructureName, FieldName ) { #FieldName, FIELD_OFFSET( StructureName, FieldName ), 'C' }
  384. #define HE( StructureName, FieldName) { #FieldName, FIELD_OFFSET( StructureName, FieldName ), 'H' }
  385. #define PE( StructureName, FieldName) { #FieldName, FIELD_OFFSET( StructureName, FieldName ), 'P' }
  386. #define UE( StructureName, FieldName) { #FieldName, FIELD_OFFSET( StructureName, FieldName ), 'U' }
  387. #define U64( StructureName, FieldName) { #FieldName, FIELD_OFFSET( StructureName, FieldName ), '6' }
  388. #define DE( StructureName, FieldName) { #FieldName, FIELD_OFFSET( StructureName, FieldName ), 'L' }
  389. #define SE( StructureName, FieldName) { #FieldName, FIELD_OFFSET( StructureName, FieldName ), 'S' }
  390. #define WE( StructureName, FieldName) { #FieldName, FIELD_OFFSET( StructureName, FieldName ), 'W' }
  391. #define AE( StructureName, FieldName) { #FieldName, FIELD_OFFSET( StructureName, FieldName ), 'A' }
  392. #define IE( StructureName, FieldName) { #FieldName, FIELD_OFFSET( StructureName, FieldName ), 'I' }
  393. #define TE( StructureName, FieldName) { #FieldName, FIELD_OFFSET( StructureName, FieldName ), 'T' }
  394. #define LE( StructureName, FieldName, PointedToStructure, PointedToMemberName ) \
  395. { #FieldName, FIELD_OFFSET( StructureName, FieldName##.Flink ), 'Z', \
  396. FIELD_OFFSET( PointedToStructure, PointedToMemberName ## .Flink ) }
  397. #define BT() { "BlockHeader.Type", FIELD_OFFSET( BLOCK_HEADER, Type) , 'K' }
  398. #define BS() { "BlockHeader.State", FIELD_OFFSET( BLOCK_HEADER, State), 'Q' }
  399. #define BC() { "BlockHeader.ReferenceCount", FIELD_OFFSET( BLOCK_HEADER, ReferenceCount), 'L' }
  400. #define IA( StructureName, FieldName) { #FieldName, FIELD_OFFSET( StructureName, FieldName ), 'N' }
  401. /*
  402. * The members of an SMB_HEADER
  403. */
  404. MEMBERLIST ML_SMB_HEADER[] = {
  405. CE( NT_SMB_HEADER, Command ),
  406. HE( NT_SMB_HEADER, Status.NtStatus ),
  407. CE( NT_SMB_HEADER, Flags ),
  408. SE( NT_SMB_HEADER, Flags2 ),
  409. SE( NT_SMB_HEADER, Tid ),
  410. SE( NT_SMB_HEADER, Pid ),
  411. SE( NT_SMB_HEADER, Uid ),
  412. SE( NT_SMB_HEADER, Mid ),
  413. 0
  414. };
  415. /*
  416. * The members in an MFCB
  417. */
  418. MEMBERLIST ML_MFCB[] = {
  419. PE( MFCB, NonpagedMfcb ),
  420. UE( MFCB, ActiveRfcbCount ),
  421. BE( MFCB, CompatibilityOpen ),
  422. HE( MFCB, FileNameHashValue ),
  423. WE( MFCB, FileName ),
  424. PE( MFCB, MfcbHashTableEntry.Flink ),
  425. LE( MFCB, LfcbList, LFCB, MfcbListEntry ),
  426. 0
  427. };
  428. /*
  429. * The members in the SrvStatistics structure
  430. */
  431. MEMBERLIST ML_SRV_STATISTICS[] = {
  432. U64( SRV_STATISTICS, TotalBytesReceived ),
  433. U64( SRV_STATISTICS, TotalBytesSent ),
  434. DE( SRV_STATISTICS, SessionLogonAttempts ),
  435. DE( SRV_STATISTICS, SessionsTimedOut ),
  436. DE( SRV_STATISTICS, SessionsErroredOut ),
  437. DE( SRV_STATISTICS, SessionsLoggedOff ),
  438. DE( SRV_STATISTICS, SessionsForcedLogOff ),
  439. DE( SRV_STATISTICS, LogonErrors ),
  440. DE( SRV_STATISTICS, AccessPermissionErrors ),
  441. DE( SRV_STATISTICS, GrantedAccessErrors ),
  442. DE( SRV_STATISTICS, SystemErrors ),
  443. DE( SRV_STATISTICS, BlockingSmbsRejected ),
  444. DE( SRV_STATISTICS, WorkItemShortages ),
  445. DE( SRV_STATISTICS, TotalFilesOpened ),
  446. DE( SRV_STATISTICS, CurrentNumberOfOpenFiles ),
  447. DE( SRV_STATISTICS, CurrentNumberOfSessions ),
  448. DE( SRV_STATISTICS, CurrentNumberOfOpenSearches ),
  449. DE( SRV_STATISTICS, CurrentNonPagedPoolUsage ),
  450. DE( SRV_STATISTICS, NonPagedPoolFailures ),
  451. DE( SRV_STATISTICS, PeakNonPagedPoolUsage ),
  452. DE( SRV_STATISTICS, CurrentPagedPoolUsage ),
  453. DE( SRV_STATISTICS, PagedPoolFailures ),
  454. DE( SRV_STATISTICS, PeakPagedPoolUsage ),
  455. DE( SRV_STATISTICS, CompressedReads ),
  456. DE( SRV_STATISTICS, CompressedReadsRejected ),
  457. DE( SRV_STATISTICS, CompressedReadsFailed ),
  458. DE( SRV_STATISTICS, CompressedWrites ),
  459. DE( SRV_STATISTICS, CompressedWritesRejected ),
  460. DE( SRV_STATISTICS, CompressedWritesFailed ),
  461. DE( SRV_STATISTICS, CompressedWritesExpanded ),
  462. 0
  463. };
  464. /*
  465. * The members in a NONPAGED_MFCB
  466. */
  467. MEMBERLIST ML_NONPAGED_MFCB[] = {
  468. UE( NONPAGED_MFCB, Type ),
  469. PE( NONPAGED_MFCB, PagedBlock ),
  470. PE( NONPAGED_MFCB, Lock ),
  471. HE( NONPAGED_MFCB, OpenFileAttributes ),
  472. 0
  473. };
  474. /*
  475. * The members in an LFCB
  476. */
  477. MEMBERLIST ML_LFCB[] = {
  478. UE( LFCB, HandleCount ),
  479. PE( LFCB, Mfcb ),
  480. PE( LFCB, Connection ),
  481. PE( LFCB, Session ),
  482. PE( LFCB, TreeConnect ),
  483. HE( LFCB, GrantedAccess ),
  484. HE( LFCB, FileHandle ),
  485. PE( LFCB, FileObject ),
  486. PE( LFCB, DeviceObject ),
  487. HE( LFCB, FileMode ),
  488. HE( LFCB, JobId ),
  489. IE( LFCB, FastIoRead ),
  490. IE( LFCB, FastIoWrite ),
  491. IE( LFCB, FastIoUnlockSingle ),
  492. BE( LFCB, CompatibilityOpen ),
  493. 0
  494. };
  495. /*
  496. * The members in an RFCB
  497. */
  498. MEMBERLIST ML_RFCB[] = {
  499. BE( RFCB, BlockingModePipe ),
  500. BE( RFCB, ByteModePipe ),
  501. BE( RFCB, CachedOpen ),
  502. PE( RFCB, CachedOpenListEntry ),
  503. PE( RFCB, Connection ),
  504. BE( RFCB, DeferredOplockBreak ),
  505. SE( RFCB, Fid ),
  506. HE( RFCB, FileMode ),
  507. PE( RFCB, GlobalRfcbListEntry ),
  508. HE( RFCB, GrantedAccess ),
  509. PE( RFCB, Irp ),
  510. BE( RFCB, IsActive ),
  511. BE( RFCB, IsCacheable ),
  512. PE( RFCB, Lfcb ),
  513. BE( RFCB, LockAccessGranted ),
  514. PE( RFCB, Mfcb ),
  515. BE( RFCB, MpxGlommingAllowed ),
  516. CE( RFCB, NewOplockLevel ),
  517. DE( RFCB, NumberOfLocks ),
  518. BE( RFCB, OnOplockBreaksInProgressList ),
  519. BE( RFCB, OpenResponseSent ),
  520. UE( RFCB, OplockState ),
  521. PE( RFCB, PagedRfcb ),
  522. SE( RFCB, Pid ),
  523. UE( RFCB, RawWriteCount ),
  524. LE( RFCB, RawWriteSerializationList, WORK_CONTEXT, ListEntry ),
  525. BE( RFCB, ReadAccessGranted ),
  526. PE( RFCB, RetryOplockRequest ),
  527. HE( RFCB, SavedError ),
  528. HE( RFCB, ShareAccess ),
  529. HE( RFCB, ShiftedFid ),
  530. SE( RFCB, Tid ),
  531. SE( RFCB, Uid ),
  532. BE( RFCB, UnlockAccessGranted ),
  533. BE( RFCB, WriteAccessGranted ),
  534. BE( RFCB, AppendAccessGranted ),
  535. BE( RFCB, WrittenTo ),
  536. DE( RFCB, WriteMpx.ReferenceCount ),
  537. HE( RFCB, WriteMpx.Mask ),
  538. PE( RFCB, WriteMpx.FileObject ),
  539. SE( RFCB, WriteMpx.Mid ),
  540. SE( RFCB, WriteMpx.PreviousMid ),
  541. SE( RFCB, WriteMpx.SequenceNumber ),
  542. BE( RFCB, WriteMpx.Glomming ),
  543. BE( RFCB, WriteMpx.GlomPending ),
  544. PE( RFCB, WriteMpx.GlomDelayList ),
  545. DE( RFCB, WriteMpx.StartOffset ),
  546. SE( RFCB, WriteMpx.Length ),
  547. BE( RFCB, WriteMpx.GlomComplete ),
  548. BE( RFCB, WriteMpx.MpxGlommingAllowed ),
  549. PE( RFCB, WriteMpx.MdlChain ),
  550. DE( RFCB, WriteMpx.NumberOfRuns ),
  551. 0
  552. };
  553. /*
  554. * The members in a PAGED_RFCB
  555. */
  556. MEMBERLIST ML_PAGED_RFCB[] = {
  557. UE( PAGED_RFCB, FcbOpenCount ),
  558. HE( PAGED_RFCB, IpxSmartCardContext ),
  559. PE( PAGED_RFCB, LfcbListEntry.Flink ),
  560. 0
  561. };
  562. /*
  563. * The members in an RFCB for quick display
  564. */
  565. MEMBERLIST ML_RFCB_QUICK[] = {
  566. ROOT( RFCB ),
  567. PE( RFCB, Connection ),
  568. HE( RFCB, GlobalRfcbListEntry.ResumeHandle ),
  569. 0
  570. };
  571. /*
  572. * The members in a SESSION
  573. */
  574. MEMBERLIST ML_SESSION[] = {
  575. ROOT( SESSION ),
  576. WE( SESSION, NtUserName ),
  577. WE( SESSION, NtUserDomain ),
  578. UE( SESSION, CurrentFileOpenCount ),
  579. UE( SESSION, CurrentSearchOpenCount ),
  580. HE( SESSION, UserHandle.dwUpper ),
  581. HE( SESSION, UserHandle.dwLower ),
  582. PE( SESSION, Connection ),
  583. PE( SESSION, GlobalSessionListEntry.ListEntry.Flink ),
  584. SE( SESSION, MaxBufferSize ),
  585. SE( SESSION, MaxMpxCount ),
  586. SE( SESSION, Uid ),
  587. BE( SESSION, UsingUppercasePaths ),
  588. BE( SESSION, GuestLogon ),
  589. BE( SESSION, EncryptedLogon ),
  590. BE( SESSION, LogoffAlertSent ),
  591. BE( SESSION, TwoMinuteWarningSent ),
  592. BE( SESSION, FiveMinuteWarningSent ),
  593. BE( SESSION, IsNullSession ),
  594. BE( SESSION, IsAdmin ),
  595. BE( SESSION, IsLSNotified ),
  596. PE( SESSION, hLicense ),
  597. BE( SESSION, LogonSequenceInProgress ),
  598. 0
  599. };
  600. /*
  601. * The members in a TRANSACTION
  602. */
  603. MEMBERLIST ML_TRANSACTION[] = {
  604. BT(),
  605. BS(),
  606. BC(),
  607. PE( TRANSACTION, NonpagedHeader ),
  608. PE( TRANSACTION, Connection ),
  609. PE( TRANSACTION, Session ),
  610. PE( TRANSACTION, TreeConnect ),
  611. UE( TRANSACTION, StartTime ),
  612. UE( TRANSACTION, Timeout ),
  613. UE( TRANSACTION, cMaxBufferSize ),
  614. PE( TRANSACTION, InSetup ),
  615. PE( TRANSACTION, OutSetup ),
  616. PE( TRANSACTION, InParameters ),
  617. PE( TRANSACTION, OutParameters ),
  618. PE( TRANSACTION, InData ),
  619. PE( TRANSACTION, OutData ),
  620. UE( TRANSACTION, SetupCount ),
  621. UE( TRANSACTION, MaxSetupCount ),
  622. UE( TRANSACTION, ParameterCount ),
  623. UE( TRANSACTION, TotalParameterCount ),
  624. UE( TRANSACTION, MaxParameterCount ),
  625. UE( TRANSACTION, DataCount ),
  626. UE( TRANSACTION, TotalDataCount ),
  627. UE( TRANSACTION, MaxDataCount ),
  628. SE( TRANSACTION, Category ),
  629. SE( TRANSACTION, Function ),
  630. BE( TRANSACTION, InputBufferCopied ),
  631. BE( TRANSACTION, OutputBufferCopied ),
  632. BE( TRANSACTION, OutDataAllocated ),
  633. SE( TRANSACTION, Flags ),
  634. SE( TRANSACTION, Tid ),
  635. SE( TRANSACTION, Pid ),
  636. SE( TRANSACTION, Uid ),
  637. SE( TRANSACTION, OtherInfo ),
  638. UE( TRANSACTION, FileHandle ),
  639. PE( TRANSACTION, FileObject ),
  640. UE( TRANSACTION, ParameterDisplacement ),
  641. UE( TRANSACTION, DataDisplacement ),
  642. BE( TRANSACTION, PipeRequest ),
  643. BE( TRANSACTION, RemoteApiRequest ),
  644. BE( TRANSACTION, Inserted ),
  645. BE( TRANSACTION, MultipieceIpxSend ),
  646. BE( TRANSACTION, Executing ),
  647. 0
  648. };
  649. /*
  650. * The members in a WORK_CONTEXT
  651. */
  652. MEMBERLIST ML_WORK_CONTEXT[] = {
  653. BT(),
  654. BS(),
  655. BC(),
  656. PE( WORK_CONTEXT, Endpoint ),
  657. PE( WORK_CONTEXT, Connection ),
  658. PE( WORK_CONTEXT, Rfcb ),
  659. PE( WORK_CONTEXT, Share ),
  660. PE( WORK_CONTEXT, Session ),
  661. PE( WORK_CONTEXT, TreeConnect ),
  662. PE( WORK_CONTEXT, Irp ),
  663. UE( WORK_CONTEXT, SpinLock ),
  664. PE( WORK_CONTEXT, RequestBuffer ),
  665. PE( WORK_CONTEXT, ResponseBuffer ),
  666. PE( WORK_CONTEXT, RequestHeader ),
  667. PE( WORK_CONTEXT, RequestParameters ),
  668. PE( WORK_CONTEXT, ResponseHeader ),
  669. PE( WORK_CONTEXT, ResponseParameters ),
  670. CE( WORK_CONTEXT, NextCommand ),
  671. UE( WORK_CONTEXT, ProcessingCount ),
  672. IE( WORK_CONTEXT, FsdRestartRoutine ),
  673. IE( WORK_CONTEXT, FspRestartRoutine ),
  674. LE( WORK_CONTEXT, InProgressListEntry, WORK_CONTEXT, InProgressListEntry ),
  675. UE( WORK_CONTEXT, PartOfInitialAllocation ),
  676. // BE( WORK_CONTEXT, BlockingOperation ),
  677. // BE( WORK_CONTEXT, UsingExtraSmbBuffer ),
  678. // BE( WORK_CONTEXT, OplockOpen ),
  679. PE( WORK_CONTEXT, ClientAddress ),
  680. PE( WORK_CONTEXT, WaitForOplockBreak ),
  681. UE( WORK_CONTEXT, BytesAvailable ),
  682. 0
  683. };
  684. /*
  685. * The members in a BUFFER
  686. */
  687. MEMBERLIST ML_BUFFER[] = {
  688. PE( BUFFER, Buffer ),
  689. UE( BUFFER, BufferLength ),
  690. PE( BUFFER, Mdl ),
  691. PE( BUFFER, PartialMdl ),
  692. UE( BUFFER, DataLength ),
  693. 0
  694. };
  695. /*
  696. * The members in an ENDPOINT
  697. */
  698. MEMBERLIST ML_ENDPOINT[] = {
  699. WE( ENDPOINT, NetworkName ),
  700. WE( ENDPOINT, TransportName ),
  701. AE( ENDPOINT, TransportAddress ),
  702. WE( ENDPOINT, ServerName ),
  703. WE( ENDPOINT, DomainName ),
  704. WE( ENDPOINT, NetworkAddress ),
  705. PE( ENDPOINT, EndpointHandle ),
  706. PE( ENDPOINT, FileObject ),
  707. PE( ENDPOINT, DeviceObject ),
  708. PE( ENDPOINT, IpxMaxPacketSizeArray ),
  709. UE( ENDPOINT, MaxAdapters ),
  710. HE( ENDPOINT, NameSocketHandle ),
  711. PE( ENDPOINT, NameSocketFileObject ),
  712. PE( ENDPOINT, NameSocketDeviceObject ),
  713. UE( ENDPOINT, FreeConnectionCount ),
  714. UE( ENDPOINT, TotalConnectionCount ),
  715. TE( ENDPOINT, ConnectionTable ),
  716. PE( ENDPOINT, FreeConnectionList ),
  717. 0
  718. };
  719. /*
  720. * The members in a SEARCH
  721. */
  722. MEMBERLIST ML_SEARCH[] = {
  723. WE( SEARCH, SearchName ),
  724. WE( SEARCH, LastFileNameReturned ),
  725. HE( SEARCH, DirectoryHandle ),
  726. PE( SEARCH, LastUseListEntry.Flink ),
  727. PE( SEARCH, HashTableEntry.Flink ),
  728. PE( SEARCH, Session ),
  729. PE( SEARCH, TreeConnect ),
  730. // UE( SEARCH, SearchStorageType ),
  731. PE( SEARCH, DirectoryCache ),
  732. SE( SEARCH, NumberOfCachedFiles ),
  733. SE( SEARCH, SearchAttributes ),
  734. SE( SEARCH, CoreSequence ),
  735. SE( SEARCH, TableIndex ),
  736. SE( SEARCH, HashTableIndex ),
  737. SE( SEARCH, Pid ),
  738. SE( SEARCH, Flags2 ),
  739. BE( SEARCH, Wildcards ),
  740. BE( SEARCH, InUse ),
  741. 0
  742. };
  743. /*
  744. * The members in a CONNECTION
  745. */
  746. MEMBERLIST ML_CONNECTION[] = {
  747. WE( CONNECTION, ClientOSType ),
  748. WE( CONNECTION, ClientLanManType ),
  749. IA( CONNECTION, ClientIPAddress ),
  750. UE( CONNECTION, SmbDialect ),
  751. UE( CONNECTION, SpinLock ),
  752. UE( CONNECTION, Interlock ),
  753. UE( CONNECTION, BalanceCount ),
  754. UE( CONNECTION, LastRequestTime ),
  755. UE( CONNECTION, Lock ),
  756. UE( CONNECTION, LicenseLock ),
  757. PE( CONNECTION, EndpointSpinLock ),
  758. PE( CONNECTION, CachedRfcb ),
  759. UE( CONNECTION, CachedFid ),
  760. BE( CONNECTION, BreakIIToNoneJustSent ),
  761. BE( CONNECTION, EnableRawIo ),
  762. UE( CONNECTION, Sid ),
  763. PE( CONNECTION, Endpoint ),
  764. DE( CONNECTION, MaximumSendSize ),
  765. PE( CONNECTION, NegotiateHandle ),
  766. PE( CONNECTION, FileObject ),
  767. PE( CONNECTION, DeviceObject ),
  768. PE( CONNECTION, InProgressWorkItemList.Flink ),
  769. UE( CONNECTION, LatestOplockBreakResponse ),
  770. UE( CONNECTION, OplockBreaksInProgress ),
  771. PE( CONNECTION, CurrentWorkQueue ),
  772. PE( CONNECTION, PreferredWorkQueue ),
  773. UE( CONNECTION, RawReadsInProgress ),
  774. BE( CONNECTION, OplocksAlwaysDisabled ),
  775. BE( CONNECTION, EnableOplocks ),
  776. PE( CONNECTION, EndpointFreeListEntry.Flink ),
  777. PE( CONNECTION, OplockWorkList ),
  778. UE( CONNECTION, CachedOpenCount ),
  779. LE( CONNECTION, CachedOpenList, RFCB, CachedOpenListEntry ),
  780. UE( CONNECTION, CachedDirectoryCount ),
  781. LE( CONNECTION, CachedDirectoryList, CACHED_DIRECTORY, ListEntry ),
  782. HE( CONNECTION, ClientCapabilities ),
  783. UE( CONNECTION, CachedTransactionCount ),
  784. BE( CONNECTION, OnNeedResourceQueue ),
  785. BE( CONNECTION, NotReusable ),
  786. BE( CONNECTION, DisconnectPending ),
  787. BE( CONNECTION, ReceivePending ),
  788. PE( CONNECTION, PagedConnection ),
  789. UE( CONNECTION, BytesAvailable ),
  790. 0
  791. };
  792. MEMBERLIST ML_CONNECTION_IPX[] = {
  793. SE( CONNECTION, SequenceNumber ),
  794. SE( CONNECTION, LastResponseLength ),
  795. SE( CONNECTION, LastResponseBufferLength ),
  796. SE( CONNECTION, LastUid ),
  797. SE( CONNECTION, LastTid ),
  798. HE( CONNECTION, LastResponseStatus ),
  799. UE( CONNECTION, StartupTime ),
  800. PE( CONNECTION, LastResponse ),
  801. SE( CONNECTION, IpxAddress.Socket ),
  802. UE( CONNECTION, IpxDuplicateCount ),
  803. UE( CONNECTION, IpxDropDuplicateCount ),
  804. 0
  805. };
  806. MEMBERLIST ML_CONNECTION_VC[] = {
  807. BE( CONNECTION, SmbSecuritySignatureActive ),
  808. UE( CONNECTION, SmbSecuritySignatureIndex ),
  809. BE( CONNECTION, NoResponseSignatureIndex ),
  810. 0
  811. };
  812. /*
  813. * The members in a PAGED_CONNECTION
  814. */
  815. MEMBERLIST ML_PAGED_CONNECTION[] = {
  816. WE( PAGED_CONNECTION, ClientMachineNameString ),
  817. BE( PAGED_CONNECTION, LoggedInvalidSmb ),
  818. // BE( PAGED_CONNECTION, ClientTooOld ),
  819. UE( PAGED_CONNECTION, ClientBuildNumber ),
  820. PE( PAGED_CONNECTION, TransactionList.Flink ),
  821. PE( PAGED_CONNECTION, CoreSearchList.Flink ),
  822. HE( PAGED_CONNECTION, ConnectionHandle ),
  823. SE( PAGED_CONNECTION, CurrentNumberOfSessions ),
  824. SE( PAGED_CONNECTION, CurrentNumberOfCoreSearches ),
  825. 0
  826. };
  827. /*
  828. * The members in a TREE_CONNECT
  829. */
  830. MEMBERLIST ML_TREE_CONNECT[] = {
  831. PE( TREE_CONNECT, Connection ),
  832. PE( TREE_CONNECT, Share ),
  833. WE( TREE_CONNECT, ServerName ),
  834. LE( TREE_CONNECT, GlobalTreeConnectListEntry.ListEntry, TREE_CONNECT, GlobalTreeConnectListEntry.ListEntry ),
  835. UE( TREE_CONNECT, CurrentFileOpenCount ),
  836. LE( TREE_CONNECT, ShareListEntry, SHARE, TreeConnectList ),
  837. PE( TREE_CONNECT, PrintFileList.Flink ),
  838. SE( TREE_CONNECT, Tid ),
  839. BE( TREE_CONNECT, RemapPipeNames ),
  840. 0
  841. };
  842. /*
  843. * The members in a WORK_QUEUE
  844. */
  845. MEMBERLIST ML_WORK_QUEUE[] = {
  846. UE( WORK_QUEUE, Queue.MaximumCount ),
  847. UE( WORK_QUEUE, Queue.CurrentCount ),
  848. UE( WORK_QUEUE, Queue.Header.SignalState ),
  849. UE( WORK_QUEUE, CurrentClients ),
  850. UE( WORK_QUEUE, AvgQueueDepthSum ),
  851. UE( WORK_QUEUE, Threads ),
  852. UE( WORK_QUEUE, AvailableThreads ),
  853. UE( WORK_QUEUE, MaxThreads ),
  854. UE( WORK_QUEUE, FreeWorkItems ),
  855. UE( WORK_QUEUE, AllocatedWorkItems ),
  856. UE( WORK_QUEUE, MaximumWorkItems ),
  857. UE( WORK_QUEUE, MinFreeWorkItems ),
  858. UE( WORK_QUEUE, NeedWorkItem ),
  859. UE( WORK_QUEUE, StolenWorkItems ),
  860. UE( WORK_QUEUE, FreeRawModeWorkItems ),
  861. UE( WORK_QUEUE, AllocatedRawModeWorkItems ),
  862. UE( WORK_QUEUE, PagedPoolLookAsideList.MaxSize ),
  863. UE( WORK_QUEUE, NonPagedPoolLookAsideList.MaxSize ),
  864. UE( WORK_QUEUE, PagedPoolLookAsideList.AllocHit ),
  865. UE( WORK_QUEUE, PagedPoolLookAsideList.AllocMiss ),
  866. UE( WORK_QUEUE, NonPagedPoolLookAsideList.AllocHit ),
  867. UE( WORK_QUEUE, NonPagedPoolLookAsideList.AllocMiss ),
  868. PE( WORK_QUEUE, CachedFreeRfcb ),
  869. UE( WORK_QUEUE, FreeRfcbs ),
  870. UE( WORK_QUEUE, MaxFreeRfcbs ),
  871. PE( WORK_QUEUE, CachedFreeMfcb ),
  872. UE( WORK_QUEUE, FreeMfcbs ),
  873. UE( WORK_QUEUE, MaxFreeMfcbs ),
  874. HE( WORK_QUEUE, SpinLock ),
  875. PE( WORK_QUEUE, IrpThread ),
  876. CE( WORK_QUEUE, CreateMoreWorkItems.BlockHeader.Type ),
  877. U64( WORK_QUEUE, IdleTimeOut ),
  878. U64( WORK_QUEUE, stats.BytesReceived ),
  879. U64( WORK_QUEUE, stats.BytesSent ),
  880. U64( WORK_QUEUE, stats.ReadOperations ),
  881. U64( WORK_QUEUE, stats.BytesRead ),
  882. U64( WORK_QUEUE, stats.WriteOperations ),
  883. U64( WORK_QUEUE, stats.BytesWritten ),
  884. U64( WORK_QUEUE, saved.ReadOperations ),
  885. U64( WORK_QUEUE, saved.BytesRead ),
  886. U64( WORK_QUEUE, saved.WriteOperations ),
  887. U64( WORK_QUEUE, saved.BytesWritten ),
  888. UE( WORK_QUEUE, stats.WorkItemsQueued.Count ),
  889. UE( WORK_QUEUE, stats.SystemTime ),
  890. 0
  891. };
  892. /*
  893. * The members in a TABLE_HEADER
  894. */
  895. MEMBERLIST ML_TABLE_HEADER[] = {
  896. SE( TABLE_HEADER, TableSize ),
  897. SE( TABLE_HEADER, FirstFreeEntry ),
  898. SE( TABLE_HEADER, LastFreeEntry ),
  899. BE( TABLE_HEADER, Nonpaged ),
  900. PE( TABLE_HEADER, Table ),
  901. 0
  902. };
  903. /*
  904. * The members in a TABLE_ENTRY
  905. */
  906. MEMBERLIST ML_TABLE_ENTRY[] = {
  907. PE( TABLE_ENTRY, Owner ),
  908. // SE( TABLE_ENTRY, SequenceNumber ),
  909. // SE( TABLE_ENTRY, NextFreeEntry ),
  910. 0
  911. };
  912. /*
  913. * The members in a SHARE
  914. */
  915. MEMBERLIST ML_SHARE[] = {
  916. WE( SHARE, ShareName ),
  917. WE( SHARE, NtPathName ),
  918. WE( SHARE, DosPathName ),
  919. WE( SHARE, Remark ),
  920. UE( SHARE, MaxUses ),
  921. UE( SHARE, CurrentUses ),
  922. HE( SHARE, RootDirectoryHandle ),
  923. UE( SHARE, CurrentRootHandleReferences ),
  924. DE( SHARE, QueryNamePrefixLength ),
  925. PE( SHARE, SecurityDescriptor ),
  926. PE( SHARE, FileSecurityDescriptor ),
  927. BE( SHARE, PotentialSystemFile ),
  928. BE( SHARE, Removable ),
  929. BE( SHARE, SpecialShare ),
  930. BE( SHARE, IsDfs ),
  931. BE( SHARE, IsDfsRoot ),
  932. HE( SHARE, CSCState ),
  933. LE( SHARE, TreeConnectList, TREE_CONNECT, ShareListEntry ),
  934. 0
  935. };
  936. /*
  937. * Forward References...
  938. */
  939. BOOL DumpTable( IN PTABLE_HEADER pt );
  940. /*
  941. * Print out an optional message, a UNICODE_STRING, and maybe a new-line
  942. */
  943. BOOL
  944. PrintStringW( IN LPSTR msg OPTIONAL, IN PUNICODE_STRING puStr, IN BOOL nl )
  945. {
  946. PWCHAR StringData;
  947. ULONG BytesRead;
  948. if( ARGUMENT_PRESENT(msg) )
  949. dprintf( msg );
  950. if( puStr->Length == 0 ) {
  951. dprintf( "<Length == 0>" );
  952. if( nl )
  953. dprintf( "\n" );
  954. return TRUE;
  955. }
  956. if( puStr->Buffer == NULL ) {
  957. dprintf( "<Buffer == 0>" );
  958. if( nl )
  959. dprintf( "\n" );
  960. return TRUE;
  961. }
  962. StringData = (PWCHAR)LocalAlloc( LPTR, puStr->Length + sizeof(UNICODE_NULL));
  963. if( StringData == NULL ) {
  964. dprintf( "Out of memory!\n" );
  965. return FALSE;
  966. }
  967. ReadMemory( (ULONG_PTR)puStr->Buffer,
  968. StringData,
  969. puStr->Length,
  970. &BytesRead);
  971. if (BytesRead) {
  972. StringData[ puStr->Length / sizeof( WCHAR ) ] = '\0';
  973. dprintf("%ws%s", StringData, nl ? "\n" : "" );
  974. }
  975. LocalFree( (HLOCAL)StringData );
  976. return BytesRead;
  977. }
  978. /*
  979. * Print out an optional message, an ANSI_STRING, and maybe a new-line
  980. */
  981. BOOL
  982. PrintStringA( IN LPSTR msg OPTIONAL, IN PANSI_STRING pStr, IN BOOL nl )
  983. {
  984. PCHAR StringData;
  985. ULONG BytesRead;
  986. if( msg )
  987. dprintf( msg );
  988. if( pStr->Length == 0 ) {
  989. if( nl )
  990. dprintf( "\n" );
  991. return TRUE;
  992. }
  993. StringData = (PCHAR)LocalAlloc( LPTR, pStr->Length + 1 );
  994. if( StringData == NULL ) {
  995. ERRPRT( "Out of memory!\n" );
  996. return FALSE;
  997. }
  998. ReadMemory((ULONG_PTR) pStr->Buffer,
  999. StringData,
  1000. pStr->Length,
  1001. &BytesRead );
  1002. if ( BytesRead ) {
  1003. StringData[ pStr->Length ] = '\0';
  1004. dprintf("%s%s", StringData, nl ? "\n" : "" );
  1005. }
  1006. LocalFree((HLOCAL)StringData);
  1007. return BytesRead;
  1008. }
  1009. /*
  1010. * Get 'size' bytes from the debuggee program at 'dwAddress' and place it
  1011. * in our address space at 'ptr'. Use 'type' in an error printout if necessary
  1012. */
  1013. BOOL
  1014. GetData( IN LPVOID ptr, IN ULONG_PTR dwAddress, IN ULONG size, IN PCSTR type )
  1015. {
  1016. BOOL b;
  1017. ULONG BytesRead;
  1018. ULONG count;
  1019. while( size > 0 ) {
  1020. count = MIN( size, 3000 );
  1021. b = ReadMemory( dwAddress, ptr, count, &BytesRead );
  1022. if (!b || BytesRead != count ) {
  1023. ERRPRT( "Unable to read %u bytes at %X, for %s\n", size, dwAddress, type );
  1024. return FALSE;
  1025. }
  1026. dwAddress += count;
  1027. size -= count;
  1028. ptr = (LPVOID)((PBYTE)ptr + count);
  1029. }
  1030. return TRUE;
  1031. }
  1032. /*
  1033. * Follow a LIST_ENTRY list beginning with a head at dwListHeadAddr in the debugee's
  1034. * address space. For each element in the list, print out the pointer value at 'offset'
  1035. */
  1036. BOOL
  1037. PrintListEntryList( IN ULONG_PTR dwListHeadAddr, IN LONG offset )
  1038. {
  1039. LIST_ENTRY ListEntry;
  1040. ULONG i=0;
  1041. BOOL retval = TRUE;
  1042. ULONG count = 20;
  1043. if( !GetData( &ListEntry, dwListHeadAddr, sizeof( ListEntry ), "LIST_ENTRY" ) )
  1044. return FALSE;
  1045. while( count-- ) {
  1046. if( (ULONG_PTR)ListEntry.Flink == dwListHeadAddr || (ULONG_PTR)ListEntry.Flink == 0 )
  1047. break;
  1048. if( !GetData( &ListEntry, (ULONG_PTR)ListEntry.Flink, sizeof( ListEntry ), "ListEntry" ) ) {
  1049. retval = FALSE;
  1050. break;
  1051. }
  1052. dprintf( "%16X%s", (ULONG_PTR)ListEntry.Flink + offset, (i && !(i&3)) ? "\n" : "" );
  1053. i++;
  1054. }
  1055. if( count == 0 && (ULONG_PTR)ListEntry.Flink != dwListHeadAddr && ListEntry.Flink ) {
  1056. dprintf( "\nTruncated list dump\n" );
  1057. } else if( ! ( i && !(i&3) ) ) {
  1058. dprintf( "\n" );
  1059. }
  1060. return retval;
  1061. }
  1062. /*
  1063. * 'ptr' points to a structure in our address space which is described by the MEMBERLIST bp.
  1064. * Print out the structure according to the MEMBERLIST
  1065. */
  1066. VOID
  1067. PrintMemberList( IN VOID *ptr, IN MEMBERLIST *bp )
  1068. {
  1069. int i;
  1070. PCSTR nl = "\n";
  1071. PCSTR sep = " ";
  1072. PCSTR nlsep = "\n ";
  1073. DWORD d;
  1074. for( i=0; bp->name; i++, bp++ ) {
  1075. if( (i&1) == 0 )
  1076. dprintf( " " );
  1077. if( bp->type == 'T' ) {
  1078. dprintf( "%s -- TABLE FOLLOWS -->\n", bp->name );
  1079. } else if( strlen( bp->name ) > 30 ) {
  1080. dprintf( "%-.17s...%s ", bp->name, bp->name+strlen(bp->name)-10 );
  1081. } else {
  1082. dprintf( "%-30s ", bp->name );
  1083. }
  1084. switch( bp->type ) {
  1085. case 'R':
  1086. // dprintf( "%-16X%s", (ULONG_PTR)ptr, i&1 ? nl : sep );
  1087. break;
  1088. case 'C':
  1089. dprintf( "%-16X%s",
  1090. (*(UCHAR *)(((char *)ptr) + bp->offset )) & 0xFF ,
  1091. i&1 ? nl : sep );
  1092. break;
  1093. case 'B':
  1094. dprintf( "%-16s%s",
  1095. *(BOOLEAN *)(((char *)ptr) + bp->offset ) ? "TRUE" : "FALSE",
  1096. i&1 ? nl : sep );
  1097. break;
  1098. case 'H':
  1099. case 'P':
  1100. dprintf( "%-16X%s",
  1101. *(ULONG *)(((char *)ptr) + bp->offset ),
  1102. i&1 ? nl : sep );
  1103. break;
  1104. case 'N':
  1105. //
  1106. // IP Address
  1107. //
  1108. d = *(ULONG *)(((char *)ptr) + bp->offset );
  1109. dprintf( "%-3.3u.%-3.3u.%-3.3u.%-3.3u %s",
  1110. (d&0xFF),
  1111. (d&0xFF00)>>8,
  1112. (d&0xFF0000)>>16,
  1113. (d&0xFF000000)>>24,
  1114. i&1 ? nl : sep );
  1115. break;
  1116. case 'U':
  1117. case 'L':
  1118. dprintf( "%-16d%s",
  1119. *(ULONG *)(((char *)ptr) + bp->offset ),
  1120. i&1 ? nl : sep );
  1121. break;
  1122. case '6':
  1123. {
  1124. ULONGLONG l;
  1125. RtlCopyMemory( &l, ((char *)ptr) + bp->offset, sizeof( l ) );
  1126. dprintf( "%I64u%s", l, i&1 ? nl : sep );
  1127. }
  1128. break;
  1129. case 'S':
  1130. dprintf( "%-16X%s",
  1131. *(SHORT *)(((char *)ptr) + bp->offset ) & 0xFFFF,
  1132. i&1 ? nl : sep );
  1133. break;
  1134. case 'W':
  1135. if( i&1 ) dprintf( nlsep );
  1136. PrintStringW( NULL, (UNICODE_STRING *)(((char *)ptr) + bp->offset ), NL );
  1137. i |= 1;
  1138. break;
  1139. case 'A':
  1140. if( i&1 ) dprintf( nlsep );
  1141. PrintStringA( NULL, (ANSI_STRING *)(((char *)ptr) + bp->offset ), NL );
  1142. i |= 1;
  1143. break;
  1144. case 'I':
  1145. {
  1146. UCHAR SymbolName[ 200 ];
  1147. ULONG_PTR Displacement;
  1148. PVOID sym = (PVOID)(*(ULONG_PTR *)(((char *)ptr) + bp->offset ));
  1149. GetSymbol( sym, SymbolName, &Displacement );
  1150. dprintf( "%-16s\n", SymbolName );
  1151. i |= 1;
  1152. }
  1153. break;
  1154. case 'T':
  1155. DumpTable( (PTABLE_HEADER)(((char *)ptr) + bp->offset) );
  1156. dprintf( " --- End Of %s Table ---\n", bp->name );
  1157. i |= 1;
  1158. break;
  1159. case 'K':
  1160. {
  1161. UCHAR Type = *(UCHAR *)(((char *)ptr) + bp->offset );
  1162. if( Type < 0 || Type >= BlockTypeMax )
  1163. dprintf( "%-16X%s", Type, i&1 ? nl : sep );
  1164. else
  1165. dprintf( "%-16s%s", BlockType[ Type ], i&1 ? nl : sep );
  1166. }
  1167. break;
  1168. case 'Q':
  1169. {
  1170. UCHAR State = *(UCHAR *)(((char *)ptr) + bp->offset );
  1171. if( State < 0 || State >= BlockStateMax )
  1172. dprintf( "%-16X%s", State, i&1 ? nl : sep );
  1173. else
  1174. dprintf( "%-16s%s", BlockState[ State ], i&1 ? nl : sep );
  1175. }
  1176. break;
  1177. case 'Z':
  1178. if( i&1 ) dprintf( nl );
  1179. PrintListEntryList( *(ULONG *)(((char *)ptr) + bp->offset ), -(bp->extra) );
  1180. i |= 1;
  1181. break;
  1182. default:
  1183. ERRPRT( "Unrecognized field type %c for %s\n", bp->type, bp->name );
  1184. break;
  1185. }
  1186. }
  1187. if( i & 1 )
  1188. dprintf( "\n" );
  1189. }
  1190. /*
  1191. * Print out a single HEX character
  1192. */
  1193. VOID
  1194. PrintHexChar( IN UCHAR c )
  1195. {
  1196. dprintf( "%c%c", "0123456789abcdef"[ (c>>4)&0xf ], "0123456789abcdef"[ c&0xf ] );
  1197. }
  1198. /*
  1199. * Print out 'buf' of 'cbuf' bytes as HEX characters
  1200. */
  1201. VOID
  1202. PrintHexBuf( IN PUCHAR buf, IN ULONG cbuf )
  1203. {
  1204. while( cbuf-- ) {
  1205. PrintHexChar( *buf++ );
  1206. dprintf( " " );
  1207. }
  1208. }
  1209. /*
  1210. * Print out the TABLE structure at TABLE_HEADER
  1211. */
  1212. BOOL
  1213. DumpTable( IN PTABLE_HEADER pt )
  1214. {
  1215. LONG i;
  1216. PTABLE_ENTRY pte;
  1217. BOOL bEmpty = TRUE;
  1218. PrintMemberList( pt, ML_TABLE_HEADER );
  1219. if( pt->TableSize < 0 ) {
  1220. ERRPRT( " ILLEGAL TABLE SIZE\n" );
  1221. return FALSE;
  1222. }
  1223. if( pt->FirstFreeEntry > pt->TableSize ) {
  1224. ERRPRT( " ILLEGAL FirstFreeEntry\n" );
  1225. return FALSE;
  1226. }
  1227. if( pt->LastFreeEntry > pt->TableSize ) {
  1228. ERRPRT( " ILLEGAL LastFreeEntry\n" );
  1229. return FALSE;
  1230. }
  1231. pte = (PTABLE_ENTRY)LocalAlloc( LPTR, pt->TableSize * sizeof( TABLE_ENTRY ) );
  1232. if( pte == NULL ) {
  1233. ERRPRT( "Out of memory!\n" );
  1234. return FALSE;
  1235. }
  1236. if( !GetData( pte, (ULONG_PTR)pt->Table, pt->TableSize * sizeof(TABLE_ENTRY), "TABLE_ENTRY" ) ) {
  1237. LocalFree( (HLOCAL)pte );
  1238. return FALSE;
  1239. }
  1240. for( i=0; i < pt->TableSize; i++ ) {
  1241. if( pte[i].Owner != NULL ) {
  1242. bEmpty = FALSE;
  1243. dprintf( "%d-%X ", i, pte[i].Owner );
  1244. }
  1245. if( pte[i].NextFreeEntry > pt->TableSize ) {
  1246. ERRPRT( " ILLEGAL NextFreeEntry %d-%d\n ", i, pte[i].NextFreeEntry );
  1247. LocalFree( (HLOCAL)pte );
  1248. return FALSE;
  1249. }
  1250. }
  1251. dprintf( "\n" );
  1252. LocalFree( (HLOCAL)pte );
  1253. if( bEmpty )
  1254. dprintf( " ** Empty Table**\n " );
  1255. return TRUE;
  1256. }
  1257. /*
  1258. * Fetch the null terminated UNICODE string at dwAddress into buf
  1259. */
  1260. BOOL
  1261. GetString( IN ULONG_PTR dwAddress, IN LPWSTR buf, IN ULONG MaxChars )
  1262. {
  1263. do {
  1264. if( !GetData( buf, dwAddress, sizeof( *buf ), "UNICODE Character" ) )
  1265. return FALSE;
  1266. dwAddress += sizeof( *buf );
  1267. } while( --MaxChars && *buf++ != '\0' );
  1268. return TRUE;
  1269. }
  1270. /*
  1271. * Check out the BLOCK_HEADER structure, ensuring its Type is 'Desired'.
  1272. * If bRefCount == TRUE, ensure the BLOCK_HEADER's reference is > 0
  1273. */
  1274. BOOL
  1275. CheckBlockHeader( IN PBLOCK_HEADER ph, IN UCHAR Desired, IN BOOL bRefCount )
  1276. {
  1277. if( ph->Type != Desired ) {
  1278. ERRPRT( "BLOCK_HEADER.Type is %X, should be %X\n",
  1279. ph->Type, Desired );
  1280. return FALSE;
  1281. }
  1282. if( ph->State < 0 || ph->State >= BlockStateMax ) {
  1283. ERRPRT( " BLOCK_HEADER.State is %X: INVALID\n", ph->State );
  1284. return FALSE;
  1285. }
  1286. if( ph->Size == 0 ) {
  1287. ERRPRT( " BLOCK_HEADER ILLEGAL SIZE!\n" );
  1288. return FALSE;
  1289. }
  1290. if( bRefCount && ph->ReferenceCount == 0 ) {
  1291. ERRPRT( " BLOCK_HEADER.ReferenceCount == 0!\n" );
  1292. return FALSE;
  1293. }
  1294. return TRUE;
  1295. }
  1296. /*
  1297. * Print out the BLOCK_HEADER, and optionally its ReferenceCount
  1298. */
  1299. BOOL
  1300. PrintBlockHeader( IN PBLOCK_HEADER ph, IN BOOL bRefCount )
  1301. {
  1302. dprintf( "BLOCK_HEADER Info: " );
  1303. if( ph->State < 0 || ph->State >= BlockStateMax ) {
  1304. ERRPRT( "State is %X: INVALID\n", ph->State );
  1305. return FALSE;
  1306. }
  1307. dprintf( "%s", BlockState[ ph->State ] );
  1308. if( ph->Type < 0 || ph->Type >= BlockTypeMax ) {
  1309. ERRPRT( "\nBlockType is %X: INVALID\n", ph->Type );
  1310. return FALSE;
  1311. }
  1312. dprintf( ", %s", BlockType[ ph->Type ] );
  1313. dprintf( ", Size %u", ph->Size );
  1314. if( ph->Size == 0 ) {
  1315. ERRPRT( " BLOCK_HEADER ILLEGAL SIZE!\n" );
  1316. return FALSE;
  1317. }
  1318. dprintf( ", ReferenceCount %u", ph->ReferenceCount );
  1319. dprintf( "\n" );
  1320. return TRUE;
  1321. }
  1322. /*
  1323. * Print out the NONPAGED_HEADER structure, ensuring its type is 'Desired', that
  1324. * it points back to its paged block at 'dwPagedBlock'.
  1325. */
  1326. BOOL
  1327. PrintNonpagedHeader(
  1328. IN PNONPAGED_HEADER ph,
  1329. IN ULONG Desired,
  1330. IN ULONG_PTR dwPagedBlock,
  1331. IN BOOL bRefCount
  1332. )
  1333. {
  1334. dprintf( "NONPAGED_HEADER Info: " );
  1335. if( ph->Type != Desired ) {
  1336. ERRPRT( "NONPAGED_HEADER.Type is %X, should be %X\n",
  1337. ph->Type, Desired );
  1338. return FALSE;
  1339. }
  1340. if( bRefCount && ph->ReferenceCount == 0 ) {
  1341. ERRPRT( " NONPAGED_HEADER.ReferenceCount == 0!\n" );
  1342. return FALSE;
  1343. }
  1344. if( (ULONG_PTR)ph->PagedBlock != dwPagedBlock ) {
  1345. ERRPRT( " NONPAGED_HEADER.PagedBlock is %X, should be %X\n", ph->PagedBlock, dwPagedBlock );
  1346. return FALSE;
  1347. }
  1348. if( bRefCount )
  1349. dprintf( "ReferenceCount %u\n", ph->ReferenceCount, ph->PagedBlock );
  1350. return TRUE;
  1351. }
  1352. BOOL
  1353. DumpShare( IN ULONG_PTR dwAddress, IN SHARE_TYPE type, IN PCSTR ShareName OPTIONAL, OUT PLIST_ENTRY *Flink OPTIONAL )
  1354. {
  1355. BOOL b;
  1356. SHARE Share;
  1357. if( !GetData( &Share, dwAddress, sizeof( Share ), "SHARE" ) ||
  1358. !CheckBlockHeader( &Share.BlockHeader, BlockTypeShare, TRUE ) ) {
  1359. return FALSE;
  1360. }
  1361. if( ARGUMENT_PRESENT( Flink ) ) {
  1362. *Flink = Share.GlobalShareList.Flink;
  1363. }
  1364. if( type != (SHARE_TYPE)-1 && type != Share.ShareType ) {
  1365. return TRUE;
  1366. }
  1367. if( ARGUMENT_PRESENT( ShareName ) ) {
  1368. //
  1369. // Only print this share structure out if the name is 'ShareName'
  1370. //
  1371. PWCHAR StringData;
  1372. ULONG BytesRead;
  1373. CHAR NameBuf[ MAX_PATH ];
  1374. if( Share.ShareName.Length == 0 ) {
  1375. return TRUE;
  1376. }
  1377. StringData = LocalAlloc(LPTR,Share.ShareName.Length + sizeof(UNICODE_NULL));
  1378. if( StringData == NULL ) {
  1379. dprintf( "Out of memory!\n" );
  1380. return FALSE;
  1381. }
  1382. ReadMemory( (ULONG_PTR)Share.ShareName.Buffer, StringData, Share.ShareName.Length, &BytesRead );
  1383. if (BytesRead == 0 ) {
  1384. LocalFree( (HLOCAL)StringData );
  1385. return FALSE;
  1386. }
  1387. StringData[ Share.ShareName.Length / sizeof( WCHAR ) ] = '\0';
  1388. wcstombs( NameBuf, StringData, sizeof( NameBuf ) );
  1389. LocalFree( (HLOCAL)StringData);
  1390. if( _strcmpi( NameBuf, ShareName ) ) {
  1391. return TRUE;
  1392. }
  1393. }
  1394. dprintf( "\nSHARE at %X: ", dwAddress );
  1395. PrintBlockHeader( &Share.BlockHeader, TRUE );
  1396. dprintf( " " );
  1397. switch( Share.ShareType ) {
  1398. case ShareTypeDisk:
  1399. dprintf( "ShareTypeDisk\n" );
  1400. break;
  1401. case ShareTypePrint:
  1402. dprintf( "ShareTypePrint, Type.hPrinter = %X ", Share.Type.hPrinter );
  1403. break;
  1404. case ShareTypePipe:
  1405. dprintf( "ShareTypePipe\n" );
  1406. break;
  1407. case ShareTypeWild:
  1408. dprintf( "ShareTypeWild\n" );
  1409. break;
  1410. default:
  1411. ERRPRT( "ShareType %X : INVALID!\n", Share.ShareType );
  1412. return FALSE;
  1413. }
  1414. PrintMemberList( &Share, ML_SHARE );
  1415. if( Share.CurrentUses > Share.MaxUses ) {
  1416. ERRPRT( " CurrentUses exceeds MaxUses!\n" );
  1417. return FALSE;
  1418. }
  1419. dprintf( "\n" );
  1420. return TRUE;
  1421. }
  1422. BOOL
  1423. DumpLock( IN ULONG_PTR dwAddress )
  1424. {
  1425. SRV_LOCK sl;
  1426. char namebuf[ 50 ];
  1427. int i;
  1428. if( !GetData( &sl, dwAddress, sizeof(sl), "ERESOURCE" ) )
  1429. return FALSE;
  1430. dprintf( " ActiveCount %u, ",dwAddress, sl.ActiveCount );
  1431. switch( sl.Flag ) {
  1432. case ResourceNeverExclusive:
  1433. dprintf( "ResourceNeverExclusive, " );
  1434. break;
  1435. case ResourceReleaseByOtherThread:
  1436. dprintf( "ResourceReleaseByOtherThread, " );
  1437. break;
  1438. case ResourceOwnedExclusive:
  1439. dprintf( "ResourceOwnedExclusive, " );
  1440. break;
  1441. default:
  1442. ERRPRT( "Flag = %X%s, ", sl.Flag, sl.Flag ? "(?)" : "" );
  1443. break;
  1444. }
  1445. dprintf( "SpinLock %d\n", sl.SpinLock );
  1446. for( i=0; i < 2; i++ ) {
  1447. if( sl.OwnerThreads[i].OwnerThread == 0 && sl.OwnerThreads[i].OwnerCount == 0 )
  1448. continue;
  1449. dprintf( " OwnerThreads[%d].OwnerThread %X, OwnerCount %d\n",
  1450. i, sl.OwnerThreads[i].OwnerThread, sl.OwnerThreads[i].OwnerCount );
  1451. }
  1452. return TRUE;
  1453. }
  1454. BOOL
  1455. DumpEndpoint( IN ULONG_PTR dwAddress, IN PLIST_ENTRY *Flink OPTIONAL )
  1456. {
  1457. ENDPOINT Endpoint;
  1458. dprintf( "\nENDPOINT at %X: ", dwAddress );
  1459. if( !GetData( &Endpoint, dwAddress, sizeof( Endpoint ), "ENDPOINT" ) ||
  1460. !CheckBlockHeader( &Endpoint.BlockHeader, BlockTypeEndpoint, TRUE ) ||
  1461. !PrintBlockHeader( &Endpoint.BlockHeader, TRUE ) ) {
  1462. return FALSE;
  1463. }
  1464. PrintMemberList( &Endpoint, ML_ENDPOINT );
  1465. dprintf( " NetworkAddressData: %ws\n", Endpoint.NetworkAddressData );
  1466. if( ARGUMENT_PRESENT( Flink ) )
  1467. *Flink = Endpoint.GlobalEndpointListEntry.ListEntry.Flink;
  1468. return TRUE;
  1469. }
  1470. BOOL
  1471. DumpSearch( IN ULONG_PTR dwAddress )
  1472. {
  1473. SEARCH s;
  1474. dprintf( "\nSEARCH at %X: ", dwAddress );
  1475. if( !GetData( &s, dwAddress, sizeof(s), "SEARCH" ) ||
  1476. !PrintBlockHeader( &s.BlockHeader, TRUE ) ) {
  1477. return FALSE;
  1478. }
  1479. PrintMemberList( &s, ML_SEARCH );
  1480. return TRUE;
  1481. }
  1482. BOOL
  1483. DumpBuffer( IN ULONG_PTR dwAddress )
  1484. {
  1485. BUFFER b;
  1486. dprintf( "\nBUFFER at %X:\n", dwAddress );
  1487. if( !GetData( &b, dwAddress, sizeof(b), "BUFFER" ) )
  1488. return FALSE;
  1489. PrintMemberList( &b, ML_BUFFER );
  1490. return TRUE;
  1491. }
  1492. BOOL
  1493. DumpSmb( IN ULONG_PTR dwAddress )
  1494. {
  1495. NT_SMB_HEADER s;
  1496. UCHAR WordCount;
  1497. dprintf( "\nSMB_HEADER at %X\n", dwAddress );
  1498. if( !GetData( &s, dwAddress, sizeof(s), "SMBHEADER" ) )
  1499. return FALSE;
  1500. PrintMemberList( &s, ML_SMB_HEADER );
  1501. if( !GetData( &WordCount, dwAddress+sizeof( NT_SMB_HEADER ), sizeof( WordCount), "WordCount" )){
  1502. ERRPRT( "Unable to retrieve WordCount at %X\n", dwAddress+sizeof(NT_SMB_HEADER) );
  1503. return FALSE;
  1504. }
  1505. dprintf( "\nWordCount @ %X = %u\n", dwAddress + sizeof( NT_SMB_HEADER), WordCount );
  1506. return TRUE;
  1507. }
  1508. BOOL
  1509. DumpTcon( IN ULONG_PTR dwAddress, IN DWORD offset, IN DWORD *value OPTIONAL )
  1510. {
  1511. TREE_CONNECT Tcon;
  1512. NONPAGED_HEADER NonpagedHeader;
  1513. dprintf( "\nTREE_CONNECT at %X: ", dwAddress );
  1514. if( !GetData( &Tcon, dwAddress, sizeof( Tcon ), "TREE_CONNECT" ) ||
  1515. !CheckBlockHeader( &Tcon.BlockHeader, BlockTypeTreeConnect, FALSE ) ||
  1516. !GetData( &NonpagedHeader, (ULONG_PTR)Tcon.NonpagedHeader, sizeof(NonpagedHeader),"NONPAGED_HEADER" ) ) {
  1517. return FALSE;
  1518. }
  1519. if( !PrintBlockHeader( &Tcon.BlockHeader, FALSE ) ||
  1520. !PrintNonpagedHeader( &NonpagedHeader, BlockTypeTreeConnect, dwAddress, TRUE ) ) {
  1521. return FALSE;
  1522. }
  1523. PrintMemberList( &Tcon, ML_TREE_CONNECT );
  1524. if( ARGUMENT_PRESENT( value ) )
  1525. *value = *(DWORD *)(((UCHAR *)&Tcon) + offset);
  1526. dprintf( "\n" );
  1527. return TRUE;
  1528. }
  1529. BOOL
  1530. DumpConnection( IN ULONG_PTR dwAddress, IN DWORD offset, OUT DWORD *value OPTIONAL )
  1531. {
  1532. CONNECTION Connection;
  1533. PAGED_CONNECTION pc;
  1534. WORK_CONTEXT wc;
  1535. ULONG_PTR wcAddr;
  1536. dprintf( "\nCONNECTION at %X: ", dwAddress );
  1537. if( !GetData( &Connection, dwAddress, sizeof( Connection ), "CONNECTION" ) ||
  1538. !CheckBlockHeader( &Connection.BlockHeader, BlockTypeConnection, TRUE ) ||
  1539. !PrintBlockHeader( &Connection.BlockHeader, TRUE ) ) {
  1540. return FALSE;
  1541. }
  1542. if( ARGUMENT_PRESENT( value ) )
  1543. *value = *(DWORD *)(((UCHAR *)&Connection) + offset);
  1544. dprintf( " OemClientMachineName: %s\n", Connection.OemClientMachineName );
  1545. PrintMemberList( &Connection, ML_CONNECTION );
  1546. if( Connection.DeviceObject != NULL ) {
  1547. //
  1548. // Assume this is a VC oriented client
  1549. //
  1550. PrintMemberList( &Connection, ML_CONNECTION_VC );
  1551. } else {
  1552. //
  1553. // Assume this is a direct host IPX client
  1554. //
  1555. PrintMemberList( &Connection, ML_CONNECTION_IPX );
  1556. }
  1557. dprintf( "\n FileTable (contains RFCBs:)\n" );
  1558. if( !DumpTable( &Connection.FileTable ) )
  1559. return FALSE;
  1560. /*
  1561. * See if we can get the PAGED_CONNECTION data
  1562. */
  1563. dprintf( "\nPagedConnection Data-> " );
  1564. if( !GetData( &pc, (ULONG_PTR)Connection.PagedConnection, sizeof(pc), "PAGED_CONNECTION" ) )
  1565. return FALSE;
  1566. PrintMemberList( &pc,ML_PAGED_CONNECTION );
  1567. dprintf( "EncryptionKey: " );
  1568. PrintHexBuf( pc.EncryptionKey, sizeof( pc.EncryptionKey ) );
  1569. dprintf( "\n\n SessionTable\n" );
  1570. if( !DumpTable( &pc.SessionTable ) )
  1571. return FALSE;
  1572. dprintf( "\n TreeConnectTable\n" );
  1573. if( !DumpTable( &pc.TreeConnectTable ) )
  1574. return FALSE;
  1575. dprintf( "\n SearchTable\n" );
  1576. if( !DumpTable( &pc.SearchTable ) )
  1577. return FALSE;
  1578. //
  1579. // Print out the in progress work item list
  1580. //
  1581. dwAddress += FIELD_OFFSET( CONNECTION, InProgressWorkItemList.Flink );
  1582. if( (ULONG_PTR)Connection.InProgressWorkItemList.Flink != dwAddress ) {
  1583. ULONG_PTR thisEntry;
  1584. LIST_ENTRY le;
  1585. dprintf( "\nIn-progress work contexts:\n" );
  1586. thisEntry = (ULONG_PTR)Connection.InProgressWorkItemList.Flink;
  1587. while( 1 ) {
  1588. if( CheckControlC() ) {
  1589. break;
  1590. }
  1591. if( thisEntry == dwAddress ) {
  1592. break;
  1593. }
  1594. wcAddr = thisEntry - FIELD_OFFSET( WORK_CONTEXT, InProgressListEntry.Flink );
  1595. RtlZeroMemory( &wc, sizeof( wc ) );
  1596. GetData( &wc, wcAddr, sizeof( wc ), "WORK_CONTEXT" );
  1597. dprintf( " %p: Rfcb %p, Session %p, Share %p, TreeConnect %p\n",
  1598. wcAddr, wc.Rfcb, wc.Session, wc.Share, wc.TreeConnect );
  1599. if( !GetData( &le, thisEntry, sizeof( le ), "LIST_ENTRY" ) )
  1600. break;
  1601. thisEntry = (ULONG_PTR)le.Flink;
  1602. }
  1603. }
  1604. dprintf( "\n" );
  1605. return TRUE;
  1606. }
  1607. BOOL
  1608. DumpLfcb( IN ULONG_PTR dwAddress )
  1609. {
  1610. LFCB l;
  1611. if( !GetData( &l, dwAddress, sizeof( l ), "LFCB" ) ||
  1612. !CheckBlockHeader( (PBLOCK_HEADER)&l.BlockHeader, BlockTypeLfcb, TRUE ) ||
  1613. !PrintBlockHeader( (PBLOCK_HEADER)&l.BlockHeader, TRUE ) ) {
  1614. return FALSE;
  1615. }
  1616. PrintMemberList( &l, ML_LFCB );
  1617. return TRUE;
  1618. }
  1619. BOOL
  1620. DumpMfcb( IN ULONG_PTR dwAddress )
  1621. {
  1622. MFCB m;
  1623. NONPAGED_MFCB npm;
  1624. if( !GetData( &m, dwAddress, sizeof( m ), "MFCB" ) ||
  1625. !CheckBlockHeader( (PBLOCK_HEADER)&m.BlockHeader, BlockTypeMfcb, FALSE ) ||
  1626. !PrintBlockHeader( (PBLOCK_HEADER)&m.BlockHeader, FALSE ) ||
  1627. !GetData( &npm, (ULONG_PTR)m.NonpagedMfcb, sizeof( npm ), "NONPAGED_MFCB" ) ) {
  1628. return FALSE;
  1629. }
  1630. PrintMemberList( &m, ML_MFCB );
  1631. PrintMemberList( &npm, ML_NONPAGED_MFCB );
  1632. return TRUE;
  1633. }
  1634. BOOL
  1635. DumpRfcb( ULONG_PTR dwAddress, PLIST_ENTRY *Flink )
  1636. {
  1637. RFCB r;
  1638. MFCB m;
  1639. PAGED_RFCB p;
  1640. BOOL PagedPresent;
  1641. if( !GetData( &r, dwAddress, sizeof( r ), "RFCB" ) ||
  1642. !CheckBlockHeader( (PBLOCK_HEADER)&r, BlockTypeRfcb, FALSE ) ) {
  1643. return FALSE;
  1644. }
  1645. PagedPresent = GetData( &p,(ULONG_PTR)r.PagedRfcb, sizeof( p ), "PAGED_RFCB" );
  1646. dprintf( "Rfcb @ %x:\n", dwAddress );
  1647. if( Flink == NULL ) {
  1648. if( !PrintBlockHeader( (PBLOCK_HEADER)&r, TRUE ) )
  1649. return FALSE;
  1650. PrintMemberList( &r, ML_RFCB );
  1651. if( PagedPresent ) PrintMemberList( &p, ML_PAGED_RFCB );
  1652. } else {
  1653. PrintMemberList( &r, ML_RFCB_QUICK );
  1654. *Flink = r.GlobalRfcbListEntry.ListEntry.Flink;
  1655. }
  1656. if( !GetData( &m, (ULONG_PTR)r.Mfcb, sizeof( m ), "MFCB" ) )
  1657. return FALSE;
  1658. PrintStringW( "File: ", &m.FileName, TRUE );
  1659. return TRUE;
  1660. }
  1661. BOOL
  1662. DumpSession( IN ULONG_PTR dwAddress, IN DWORD offset, OUT DWORD *value OPTIONAL )
  1663. {
  1664. SESSION Session;
  1665. NONPAGED_HEADER NonpagedHeader;
  1666. if( !GetData( &Session, dwAddress, sizeof( Session ), "SESSION" ) ||
  1667. !CheckBlockHeader( &Session.BlockHeader, BlockTypeSession, FALSE ) ||
  1668. !PrintBlockHeader( &Session.BlockHeader, FALSE ) ||
  1669. !GetData( &NonpagedHeader, (ULONG_PTR)Session.NonpagedHeader, sizeof(NonpagedHeader),"NONPAGED_HEADER" ) ||
  1670. !PrintNonpagedHeader( &NonpagedHeader, BlockTypeSession, dwAddress, TRUE ) ) {
  1671. return FALSE;
  1672. }
  1673. if( ARGUMENT_PRESENT( value ) )
  1674. *value = *(DWORD *)(((UCHAR *)&Session) + offset);
  1675. PrintMemberList( &Session, ML_SESSION );
  1676. dprintf( "%-30s ", "NtUserSessionKey" );
  1677. PrintHexBuf( Session.NtUserSessionKey, sizeof( Session.NtUserSessionKey ) );
  1678. dprintf( "\n %-30s ", "LanManSessionKey" );
  1679. PrintHexBuf( Session.LanManSessionKey, sizeof( Session.LanManSessionKey ) );
  1680. dprintf( "\n\n" );
  1681. return TRUE;
  1682. }
  1683. BOOL
  1684. DumpTransaction( IN ULONG_PTR dwAddress )
  1685. {
  1686. TRANSACTION t;
  1687. dprintf( "\nTRANSACTION at %X:\n", dwAddress );
  1688. if( !GetData( &t, dwAddress, sizeof(t), "TRANSACTION" ) )
  1689. return FALSE;
  1690. PrintMemberList( &t, ML_TRANSACTION );
  1691. return TRUE;
  1692. }
  1693. BOOL
  1694. DumpWorkContext( IN ULONG_PTR dwAddress )
  1695. {
  1696. WORK_CONTEXT wc;
  1697. dprintf( "\nWORK_CONTEXT at %X:\n", dwAddress );
  1698. if( !GetData( &wc, dwAddress, sizeof(wc), "WORK_CONTEXT" ) )
  1699. return FALSE;
  1700. PrintMemberList( &wc, ML_WORK_CONTEXT );
  1701. dprintf( " Parameters addr %X, Parameters2 addr %X\n",
  1702. dwAddress + FIELD_OFFSET( WORK_CONTEXT, Parameters ),
  1703. dwAddress + FIELD_OFFSET( WORK_CONTEXT, Parameters2 ));
  1704. if( wc.BlockingOperation )
  1705. dprintf( " BlockingOperation" );
  1706. if( wc.UsingExtraSmbBuffer )
  1707. dprintf( " UsingExtraSmbBuffer" );
  1708. if( wc.OplockOpen )
  1709. dprintf( " OplockOpen" );
  1710. if( wc.ShareAclFailure )
  1711. dprintf( " ShareAclFailure" );
  1712. if( wc.QueueToHead )
  1713. dprintf( " QueueToHead" );
  1714. if( wc.NoResponseSmbSecuritySignature )
  1715. dprintf( " NoResponseSmbSecuritySignature" );
  1716. if( wc.LargeIndication )
  1717. dprintf( " LargeIndication" );
  1718. dprintf( "\n" );
  1719. return TRUE;
  1720. }
  1721. VOID *
  1722. ThreadHandleToPointer( HANDLE hThread )
  1723. {
  1724. return (VOID *)hThread;
  1725. }
  1726. BOOL
  1727. DumpWorkQueue( IN ULONG_PTR dwAddress )
  1728. {
  1729. WORK_QUEUE WorkQueue;
  1730. ULONG i;
  1731. PHANDLE pHandles;
  1732. dprintf( " at %X:\n", dwAddress );
  1733. if( !GetData( &WorkQueue, dwAddress, sizeof( WorkQueue ), "WORK_QUEUE" ) )
  1734. return FALSE;
  1735. if( WorkQueue.Queue.Header.Type != QueueObject ) {
  1736. ERRPRT( "WARNING: Queue.Header.Type is %X, should be %X\n",
  1737. WorkQueue.Queue.Header.Type, QueueObject );
  1738. }
  1739. if( WorkQueue.Queue.Header.Size != sizeof( KQUEUE )/ sizeof( LONG ) ) {
  1740. ERRPRT( "WARNING: Queue.Header.Size is %d, should be %d\n",
  1741. WorkQueue.Queue.Header.Size, sizeof( KQUEUE ) );
  1742. }
  1743. PrintMemberList( &WorkQueue, ML_WORK_QUEUE );
  1744. if( WorkQueue.Queue.Header.SignalState > 0 ) {
  1745. dprintf( " Queued WORK_CONTEXTs:\n" );
  1746. if( !PrintListEntryList( dwAddress + FIELD_OFFSET(WORK_QUEUE, Queue.EntryListHead.Flink ),
  1747. FIELD_OFFSET( KWAIT_BLOCK, Thread ))) {
  1748. }
  1749. }
  1750. return TRUE;
  1751. }
  1752. VOID
  1753. PrintHelp( VOID )
  1754. {
  1755. int i;
  1756. for( i=0; Extensions[i]; i++ )
  1757. dprintf( " %s\n", Extensions[i] );
  1758. }
  1759. /*
  1760. * Print out the usage message
  1761. */
  1762. DECLARE_API( help )
  1763. {
  1764. PrintHelp();
  1765. }
  1766. /*
  1767. * Follow a LIST_ENTRY to the end
  1768. */
  1769. DECLARE_API( df )
  1770. {
  1771. LIST_ENTRY ListEntry;
  1772. ULONG_PTR headAddress, dwAddress, prevAddress;
  1773. ULONG count = 0;
  1774. if( args == NULL || *args == '\0' ) {
  1775. PrintHelp();
  1776. return;
  1777. }
  1778. headAddress = GetExpression( args );
  1779. if( !headAddress ||
  1780. !GetData( &ListEntry, headAddress, sizeof( ListEntry ), "LIST_HEAD" ) ) {
  1781. return;
  1782. }
  1783. prevAddress = headAddress;
  1784. while( !CheckControlC() ) {
  1785. dwAddress = (ULONG_PTR)ListEntry.Flink;
  1786. if( dwAddress == headAddress ) {
  1787. dprintf( " %u elements in the list\n", count );
  1788. return;
  1789. }
  1790. if( dwAddress == prevAddress ) {
  1791. dprintf( " Flink at %X points to itself. Count %u\n", dwAddress, count );
  1792. }
  1793. if( !GetData( &ListEntry, dwAddress, sizeof( ListEntry ), "LIST_ENTRY" ) ) {
  1794. dprintf( " Flink at %X is bad --", prevAddress );
  1795. dprintf( " %u elements into list\n", count );
  1796. return;
  1797. }
  1798. prevAddress = dwAddress;
  1799. count++;
  1800. }
  1801. dprintf( " CTRL-C: %u elements scanned\n", count );
  1802. }
  1803. DECLARE_API( pagedconnection )
  1804. {
  1805. ULONG_PTR dwAddress;
  1806. PAGED_CONNECTION pc;
  1807. if( args == NULL || *args == '\0' ) {
  1808. PrintHelp();
  1809. } else {
  1810. dwAddress = GetExpression( args );
  1811. if( dwAddress && GetData( &pc, dwAddress, sizeof(pc), "PAGED_CONNECTION" ) ) {
  1812. dprintf( " sizeof( PAGED_CONNECTION ) = %d bytes\n", sizeof( pc ) );
  1813. PrintMemberList( &pc, ML_PAGED_CONNECTION );
  1814. }
  1815. }
  1816. }
  1817. DECLARE_API( share )
  1818. {
  1819. ULONG_PTR dwAddress;
  1820. BOOL ShowMany = FALSE;
  1821. SHARE_TYPE ShareType = (SHARE_TYPE)-1;
  1822. LPCSTR ShareName = NULL;
  1823. LIST_ENTRY SrvShareHashTable[ NSHARE_HASH_TABLE ];
  1824. ULONG i;
  1825. if( args == NULL || *args == '\0' ) {
  1826. ShowMany = TRUE;
  1827. } else if( !_strcmpi( args, "disk" ) ) {
  1828. ShowMany = TRUE;
  1829. ShareType = ShareTypeDisk;
  1830. } else if( !_strcmpi( args, "print" ) ) {
  1831. ShowMany = TRUE;
  1832. ShareType = ShareTypePrint;
  1833. } else if( !_strcmpi( args, "pipe" ) ) {
  1834. ShowMany = TRUE;
  1835. ShareType = ShareTypePipe;
  1836. } else if( args[0] == '=' ) {
  1837. ShareName = args + 1;
  1838. ShowMany = TRUE;
  1839. } else if( !_strcmpi( args, "?" ) ) {
  1840. PrintHelp();
  1841. return;
  1842. }
  1843. if( ShowMany == FALSE ) {
  1844. //
  1845. // Get at the address that was passed to this on the command line.
  1846. //
  1847. dwAddress = GetExpression( args );
  1848. if( dwAddress == 0 )
  1849. return;
  1850. DumpShare( dwAddress, ShareType, NULL, NULL );
  1851. return;
  1852. }
  1853. //
  1854. // Dump entries from the entire server share table!
  1855. //
  1856. dwAddress = GetExpression( "srv!SrvShareHashTable" );
  1857. if( dwAddress == 0 ) {
  1858. ERRPRT( "Unable to get address for srv!SrvShareHashTable\n" );
  1859. return;
  1860. }
  1861. if( !GetData( &SrvShareHashTable, dwAddress, sizeof( SrvShareHashTable ), "HASH TABLE" ) ) {
  1862. ERRPRT( "Unable to read hash table\n" );
  1863. return;
  1864. }
  1865. for( i = 0; i < NSHARE_HASH_TABLE; i++ ) {
  1866. LIST_ENTRY *NextShare;
  1867. NextShare = SrvShareHashTable[i].Flink;
  1868. while( (ULONG_PTR)NextShare != dwAddress + i*sizeof( LIST_ENTRY ) ) {
  1869. ULONG_PTR ShareEntry;
  1870. ShareEntry = (ULONG_PTR)CONTAINING_RECORD( NextShare, SHARE, GlobalShareList );
  1871. if( !DumpShare( ShareEntry, ShareType, ShareName, &NextShare ) )
  1872. break;
  1873. }
  1874. }
  1875. }
  1876. DECLARE_API( lock )
  1877. {
  1878. ULONG_PTR dwAddress;
  1879. CHAR buf[ 100 ];
  1880. int i;
  1881. if( args && *args ) {
  1882. dwAddress = GetExpression( args );
  1883. DumpLock( dwAddress );
  1884. return;
  1885. }
  1886. strcpy( buf, "srv!" );
  1887. for( i=0; SrvLocks[i]; i++ ) {
  1888. strcpy( &buf[4], SrvLocks[i] );
  1889. dwAddress = GetExpression ( buf );
  1890. if( dwAddress == 0 ) {
  1891. ERRPRT( "Unable to get address of %s\n", SrvLocks[i] );
  1892. continue;
  1893. }
  1894. dprintf( "\n%s\n", SrvLocks[i] );
  1895. if( !DumpLock( dwAddress ) )
  1896. break;
  1897. }
  1898. }
  1899. DECLARE_API( endpoint )
  1900. {
  1901. LIST_ENTRY *NextEndpoint;
  1902. ORDERED_LIST_HEAD SrvEndpointList;
  1903. ULONG_PTR dwAddress;
  1904. int i;
  1905. if( args && *args ) {
  1906. dwAddress = GetExpression( args );
  1907. DumpEndpoint( dwAddress, NULL );
  1908. return;
  1909. }
  1910. dwAddress = GetExpression ( "srv!SrvEndpointList" );
  1911. if( dwAddress == 0 ) {
  1912. ERRPRT( "Unable to get address of srv!SrvEndpointList\n" );
  1913. return;
  1914. }
  1915. if( !GetData( &SrvEndpointList, dwAddress, sizeof( SrvEndpointList ), "ORDERED_LIST_HEAD" ) ) {
  1916. ERRPRT( "Unable to read data for srv!SrvEndpointList\n" );
  1917. return;
  1918. }
  1919. if( SrvEndpointList.Initialized == 0 ) {
  1920. ERRPRT( "srv!SrvEndpointList.Initialized == 0!\n" );
  1921. return;
  1922. }
  1923. if( (ULONG_PTR)SrvEndpointList.ListHead.Flink == dwAddress ) {
  1924. ERRPRT( "srv!SrvEndpointList list is empty\n" );
  1925. return;
  1926. }
  1927. if( (ULONG_PTR)SrvEndpointList.ListHead.Flink == 0 ) {
  1928. ERRPRT( "srv!SrvEndpointList.ListHead.Flink == 0: list is empty\n" );
  1929. return;
  1930. }
  1931. NextEndpoint = SrvEndpointList.ListHead.Flink;
  1932. do {
  1933. ULONG_PTR EndpointEntry;
  1934. if( CheckControlC() ) {
  1935. dprintf( "\n" );
  1936. break;
  1937. }
  1938. EndpointEntry = (ULONG_PTR)CONTAINING_RECORD( NextEndpoint, ENDPOINT, GlobalEndpointListEntry );
  1939. if( !DumpEndpoint( EndpointEntry, &NextEndpoint ) )
  1940. break;
  1941. } while( (ULONG_PTR)NextEndpoint != dwAddress );
  1942. }
  1943. DECLARE_API( search )
  1944. {
  1945. if( !args || !*args ) {
  1946. ERRPRT( "SEARCH address required\n" );
  1947. } else {
  1948. DumpSearch( GetExpression( args ) );
  1949. }
  1950. }
  1951. DECLARE_API( buffer )
  1952. {
  1953. if( !args || !*args ) {
  1954. ERRPRT( "BUFFER address required\n" );
  1955. } else {
  1956. DumpBuffer( GetExpression( args ) );
  1957. }
  1958. }
  1959. DECLARE_API( smb )
  1960. {
  1961. if( !args || !*args ) {
  1962. ERRPRT( "BUFFER address required\n" );
  1963. } else {
  1964. DumpSmb( GetExpression( args ) );
  1965. }
  1966. }
  1967. DECLARE_API( tcon )
  1968. {
  1969. if( !args || !*args ) {
  1970. ERRPRT( "Tcon address required\n" );
  1971. } else {
  1972. DumpTcon( GetExpression(args), 0, NULL );
  1973. }
  1974. }
  1975. DECLARE_API ( connection )
  1976. {
  1977. if( !args || !*args ) {
  1978. ERRPRT( "Connection address required\n" );
  1979. } else {
  1980. DumpConnection( GetExpression(args), 0, NULL );
  1981. }
  1982. }
  1983. DECLARE_API( lfcb )
  1984. {
  1985. if( !args || !*args ) {
  1986. ERRPRT( "LFCB address required\n" );
  1987. } else {
  1988. DumpLfcb( GetExpression(args) );
  1989. }
  1990. }
  1991. DECLARE_API( mfcb )
  1992. {
  1993. if( !args || !*args ) {
  1994. ERRPRT( "MFCB address required\n" );
  1995. } else {
  1996. DumpMfcb( GetExpression(args) );
  1997. }
  1998. }
  1999. DECLARE_API( rfcb )
  2000. {
  2001. LIST_ENTRY *NextRfcb;
  2002. ORDERED_LIST_HEAD SrvRfcbList;
  2003. ULONG_PTR dwAddress;
  2004. int i;
  2005. if( args && *args ) {
  2006. DumpRfcb( GetExpression(args), NULL );
  2007. return;
  2008. }
  2009. dwAddress = GetExpression ( "srv!SrvRfcbList" );
  2010. if( dwAddress == 0 ) {
  2011. ERRPRT( "Unable to get address of srv!SrvSrvRfcbList\n" );
  2012. return;
  2013. }
  2014. if( !GetData( &SrvRfcbList, dwAddress, sizeof( SrvRfcbList ), "ORDERED_LIST_HEAD" ) ) {
  2015. ERRPRT( "Unable to read data for srv!SrvRfcbList\n" );
  2016. return;
  2017. }
  2018. if( SrvRfcbList.Initialized == 0 ) {
  2019. ERRPRT( "srv!SrvRfcbList.Initialized == 0!\n" );
  2020. return;
  2021. }
  2022. if( (ULONG_PTR)SrvRfcbList.ListHead.Flink == dwAddress ) {
  2023. ERRPRT( "srv!SrvRfcbList list is empty\n" );
  2024. return;
  2025. }
  2026. if( (ULONG_PTR)SrvRfcbList.ListHead.Flink == 0 ) {
  2027. ERRPRT( "srv!SrvRfcbList.ListHead.Flink == 0: list is empty\n" );
  2028. return;
  2029. }
  2030. NextRfcb = SrvRfcbList.ListHead.Flink;
  2031. do {
  2032. ULONG_PTR RfcbEntry;
  2033. RfcbEntry = (ULONG_PTR)CONTAINING_RECORD( NextRfcb, RFCB, GlobalRfcbListEntry );
  2034. dprintf( "\n" );
  2035. DumpRfcb( RfcbEntry, &NextRfcb );
  2036. if( CheckControlC() ) {
  2037. dprintf( "\n" );
  2038. break;
  2039. }
  2040. } while( (ULONG_PTR)NextRfcb != dwAddress );
  2041. }
  2042. DECLARE_API( session )
  2043. {
  2044. if( !args || !*args ) {
  2045. ERRPRT( "Session address required\n" );
  2046. } else {
  2047. DumpSession( GetExpression(args), 0, NULL );
  2048. }
  2049. }
  2050. DECLARE_API( globals )
  2051. {
  2052. ULONG_PTR dwAddress;
  2053. CHAR buf[ 200 ];
  2054. int i;
  2055. int c=0;
  2056. GUID guid;
  2057. strcpy( buf, "srv!" );
  2058. dprintf( "BOOLEAN Values (%u bytes):\n", sizeof( BOOLEAN ) );
  2059. for( i=0; GlobalBool[i]; i++, c++ ) {
  2060. BOOLEAN b;
  2061. strcpy( &buf[4], GlobalBool[i] );
  2062. dwAddress = GetExpression ( buf );
  2063. if( dwAddress == 0 ) {
  2064. continue;
  2065. }
  2066. if( !GetData( &b, dwAddress, sizeof(b), GlobalBool[i] ) )
  2067. return;
  2068. dprintf( "%s%-35s %10s%s",
  2069. c&1 ? " " : "",
  2070. GlobalBool[i],
  2071. b ? " TRUE" : "FALSE",
  2072. c&1 ? "\n" : "" );
  2073. }
  2074. if( CheckControlC() ) {
  2075. dprintf( "\n" );
  2076. return;
  2077. }
  2078. dprintf( "%s\nSHORT Values (%u bytes):\n", c&1 ? "\n" : "" ,sizeof( SHORT ) );
  2079. c &= ~01;
  2080. for( i=0; GlobalShort[i]; i++, c++ ) {
  2081. SHORT s;
  2082. strcpy( &buf[4], GlobalShort[i] );
  2083. dwAddress = GetExpression ( buf );
  2084. if( dwAddress == 0 ) {
  2085. continue;
  2086. }
  2087. if( !GetData( &s, dwAddress, sizeof(s), GlobalShort[i] ) )
  2088. return;
  2089. dprintf( "%s%-35s %10d%s",
  2090. c&1 ? " " : "",
  2091. GlobalShort[i],
  2092. s,
  2093. c&1 ? "\n" : "" );
  2094. }
  2095. if( CheckControlC() ) {
  2096. dprintf( "\n" );
  2097. return;
  2098. }
  2099. dprintf( "%s\nLONG Values (%u bytes):\n", c&1 ? "\n" : "", sizeof( LONG ) );
  2100. c &= ~01;
  2101. for( i=0; GlobalLong[i]; i++, c++ ) {
  2102. LONG l;
  2103. strcpy( &buf[4], GlobalLong[i] );
  2104. dwAddress = GetExpression ( buf );
  2105. if( dwAddress == 0 ) {
  2106. continue;
  2107. }
  2108. if( !GetData( &l, dwAddress, sizeof(l), GlobalLong[i] ) )
  2109. return;
  2110. dprintf( "%s%-35s %10u%s",
  2111. c&1 ? " " : "",
  2112. GlobalLong[i],
  2113. l,
  2114. c&1 ? "\n" : "" );
  2115. }
  2116. if( CheckControlC() ) {
  2117. dprintf( "\n" );
  2118. return;
  2119. }
  2120. for( i=0; GlobalLongHex[i]; i++, c++ ) {
  2121. LONG l;
  2122. strcpy( &buf[4], GlobalLongHex[i] );
  2123. dwAddress = GetExpression ( buf );
  2124. if( dwAddress == 0 ) {
  2125. continue;
  2126. }
  2127. if( !GetData( &l, dwAddress, sizeof(l), GlobalLongHex[i] ) )
  2128. return;
  2129. dprintf( "%s%-35s %10X%s",
  2130. c&1 ? " " : "",
  2131. GlobalLongHex[i],
  2132. l,
  2133. c&1 ? "\n" : "" );
  2134. }
  2135. if( CheckControlC() ) {
  2136. dprintf( "\n" );
  2137. return;
  2138. }
  2139. //
  2140. // Dump out the server GUID
  2141. //
  2142. dwAddress = GetExpression( "srv!ServerGuid" );
  2143. if( dwAddress != 0 &&
  2144. GetData( &guid, dwAddress, sizeof(guid), "ServerGuid" ) ) {
  2145. dprintf( "%s%s ", c&1 ? " " : "", "ServerGuid" );
  2146. for( i=0; i < sizeof( guid ); i++ ) {
  2147. dprintf( "%2.2X", ((CHAR *)&guid)[i] & 0xFF );
  2148. }
  2149. }
  2150. for( i = 0; GlobalStrings[i]; i++ ) {
  2151. UNICODE_STRING String;
  2152. WCHAR wszbuf[35];
  2153. dprintf( "\n%s%s:\n", c&1 ? "\n" : "", GlobalStrings[i] );
  2154. c &= ~01;
  2155. strcpy( &buf[4], GlobalStrings[i] );
  2156. dwAddress = GetExpression ( buf );
  2157. if( dwAddress == 0 ) {
  2158. continue;
  2159. }
  2160. if( GetData( &String, dwAddress, sizeof( String ), GlobalStrings[i] ) ) {
  2161. wszbuf[ sizeof(wszbuf)/sizeof(wszbuf[0]) - 1 ] = L'\0';
  2162. if( !GetString( (ULONG_PTR)String.Buffer, wszbuf, sizeof(wszbuf)/sizeof(wszbuf[0])-1) )
  2163. continue;
  2164. dprintf( " %-35ws%s", wszbuf, c&1 ? "\n" : "" );
  2165. c++;
  2166. }
  2167. }
  2168. if( CheckControlC() ) {
  2169. dprintf( "\n" );
  2170. return;
  2171. }
  2172. for( i=0; GlobalStringVector[i]; i++ ) {
  2173. ULONG_PTR StringAddress;
  2174. WCHAR wszbuf[ 35 ];
  2175. dprintf( "\n%s%s:\n", c&1 ? "\n" : "", GlobalStringVector[i] );
  2176. c &= ~01;
  2177. strcpy( &buf[4], GlobalStringVector[i] );
  2178. dwAddress = GetExpression ( buf );
  2179. if( dwAddress == 0 ) {
  2180. continue;
  2181. }
  2182. if( !GetData( &dwAddress, dwAddress, sizeof( dwAddress ), GlobalStringVector[i] ) ) {
  2183. return;
  2184. }
  2185. if( dwAddress == 0 )
  2186. continue;
  2187. wszbuf[ sizeof(wszbuf)/sizeof(wszbuf[0]) - 1 ] = L'\0';
  2188. while( 1 ) {
  2189. if( !GetData( &StringAddress, dwAddress, sizeof(StringAddress), GlobalStringVector[i] ) )
  2190. break;
  2191. if( StringAddress == 0 )
  2192. break;
  2193. if( !GetString( StringAddress, wszbuf, sizeof(wszbuf) / sizeof(wszbuf[0]) - 1 ) )
  2194. break;
  2195. dprintf( " %-35ws%s",
  2196. wszbuf,
  2197. c&1 ? "\n" : "" );
  2198. dwAddress += sizeof( LPSTR );
  2199. c++;
  2200. }
  2201. }
  2202. dprintf( "\n" );
  2203. }
  2204. DECLARE_API( context )
  2205. {
  2206. if( args == NULL || !*args ) {
  2207. ERRPRT( "WORK_CONTEXT address required\n" );
  2208. } else {
  2209. DumpWorkContext( GetExpression( args ) );
  2210. }
  2211. }
  2212. DECLARE_API( transaction )
  2213. {
  2214. if( args == NULL || !*args ) {
  2215. ERRPRT( "TRANSACTION address required\n" );
  2216. } else {
  2217. DumpTransaction( GetExpression( args ) );
  2218. }
  2219. }
  2220. DECLARE_API( queue )
  2221. {
  2222. ULONG_PTR dwAddress, dweAddress;
  2223. ULONG nProcessors;
  2224. ULONG i;
  2225. BOOLEAN mp;
  2226. if( args && *args ) {
  2227. dprintf( "WorkQueue" );
  2228. DumpWorkQueue( GetExpression( args ) );
  2229. return;
  2230. }
  2231. dwAddress = GetExpression( "srv!SrvMultiProcessorDriver" );
  2232. if( !GetData( &mp, dwAddress, sizeof( mp ), "srv!SrvMultiProcessorDriver" ) )
  2233. return;
  2234. if( mp == TRUE ) {
  2235. dwAddress = GetExpression( "srv!SrvNumberOfProcessors" );
  2236. if( !GetData( &nProcessors, dwAddress, sizeof(nProcessors), "srv!SrvNumberOfProcessors" ) )
  2237. return;
  2238. dwAddress = GetExpression( "srv!SrvWorkQueues" );
  2239. if( !GetData( &dwAddress, dwAddress, sizeof(dwAddress), "srv!SrvWorkQueues" ))
  2240. return;
  2241. dweAddress = GetExpression( "srv!eSrvWorkQueues" );
  2242. if( !GetData( &dweAddress, dweAddress, sizeof(dweAddress), "srv!eSrvWorkQueues" ))
  2243. return;
  2244. if( dwAddress + nProcessors*sizeof(WORK_QUEUE) != dweAddress ) {
  2245. ERRPRT( "eSrvWorkQueues is %X, should be %X\n",
  2246. dweAddress, dwAddress + nProcessors*sizeof(WORK_QUEUE) );
  2247. }
  2248. } else {
  2249. dwAddress = GetExpression( "srv!SrvWorkQueues" );
  2250. nProcessors = 1;
  2251. }
  2252. for( i=0; i < nProcessors; i++, dwAddress += sizeof( WORK_QUEUE ) ) {
  2253. dprintf( "%sProcessor %d ", i?"\n":"", i );
  2254. if( DumpWorkQueue( dwAddress ) == FALSE )
  2255. break;
  2256. }
  2257. dwAddress = GetExpression( "srv!SrvBlockingWorkQueue" );
  2258. dprintf( "\nBlockingWorkQueue " );
  2259. DumpWorkQueue( dwAddress );
  2260. }
  2261. char *mystrtok ( char *string, char * control )
  2262. {
  2263. static unsigned char *str;
  2264. char *p, *s;
  2265. if( string )
  2266. str = string;
  2267. if( str == NULL || *str == '\0' )
  2268. return NULL;
  2269. //
  2270. // Skip leading delimiters...
  2271. //
  2272. for( ; *str; str++ ) {
  2273. for( s=control; *s; s++ ) {
  2274. if( *str == *s )
  2275. break;
  2276. }
  2277. if( *s == '\0' )
  2278. break;
  2279. }
  2280. //
  2281. // Was it was all delimiters?
  2282. //
  2283. if( *str == '\0' ) {
  2284. str = NULL;
  2285. return NULL;
  2286. }
  2287. //
  2288. // We've got a string, terminate it at first delimeter
  2289. //
  2290. for( p = str+1; *p; p++ ) {
  2291. for( s = control; *s; s++ ) {
  2292. if( *p == *s ) {
  2293. s = str;
  2294. *p = '\0';
  2295. str = p+1;
  2296. return s;
  2297. }
  2298. }
  2299. }
  2300. //
  2301. // We've got a string that ends with the NULL
  2302. //
  2303. s = str;
  2304. str = NULL;
  2305. return s;
  2306. }
  2307. void
  2308. DoLongLongBits( PCSTR symbol, PCSTR args, struct BitFields b[] )
  2309. {
  2310. ULONGLONG value;
  2311. ULONG_PTR dwAddress;
  2312. char *p;
  2313. ULONG bytesWritten;
  2314. int i;
  2315. int bsize;
  2316. dwAddress = GetExpression( symbol );
  2317. if( !GetData( &value, dwAddress, sizeof(value), symbol ) )
  2318. return;
  2319. if( !args || !*args ) {
  2320. for( i=0; b[i].name; i++ ) {
  2321. if( i && i%3 == 0 )
  2322. dprintf( "\n" );
  2323. if( strlen( b[i].name ) > 15 ) {
  2324. dprintf( " %2u %-.7s...%s ", i, b[i].name,
  2325. b[i].name+strlen(b[i].name)-5 );
  2326. } else {
  2327. dprintf( " %2u %-15s ", i, b[i].name );
  2328. }
  2329. dprintf( " %c", value & b[i].value ? 'T' : 'F' );
  2330. }
  2331. dprintf( "\n" );
  2332. return;
  2333. }
  2334. for( bsize=0; b[ bsize ].name; bsize++ )
  2335. ;
  2336. if( !_strcmpi( args, "on" ) || !_strcmpi( args, "true" ) || !_strcmpi( args, "t" ) ) {
  2337. value = (ULONGLONG)-1;
  2338. } else if( !_strcmpi( args, "off" ) || !_strcmpi( args, "false" ) || !_strcmpi( args, "f" ) ) {
  2339. value = 0;
  2340. } else {
  2341. char argbuf[ MAX_PATH ];
  2342. strcpy( argbuf, args );
  2343. for( p = mystrtok( argbuf, " \t,;" ); p && *p; p = mystrtok( NULL, " \t,;" ) ) {
  2344. i = atoi( p );
  2345. if( i < 0 || i >= bsize ) {
  2346. dprintf( "%s: illegal index number\n", p );
  2347. continue;
  2348. }
  2349. if( value & b[i].value ) {
  2350. value &= ~b[i].value;
  2351. } else {
  2352. value |= b[i].value;
  2353. }
  2354. }
  2355. }
  2356. WriteMemory( dwAddress, &value, sizeof(value), &bytesWritten );
  2357. if( bytesWritten != sizeof( value ) )
  2358. dprintf( "Write error\n" );
  2359. }
  2360. DECLARE_API( srvdebug )
  2361. {
  2362. #if SRVDBG == 1
  2363. DoLongLongBits( "srv!SrvDebug", args, SrvDebugFlags );
  2364. #else
  2365. dprintf( "Not Available!\n" );
  2366. #endif
  2367. }
  2368. DECLARE_API( smbdebug )
  2369. {
  2370. #if SRVDBG == 1
  2371. DoLongLongBits( "srv!SmbDebug", args, SmbDebugFlags );
  2372. #else
  2373. dprintf( "Not Available!\n" );
  2374. #endif
  2375. }
  2376. DECLARE_API( statistics )
  2377. {
  2378. ULONG_PTR dwAddress;
  2379. SRV_STATISTICS s;
  2380. dwAddress = GetExpression( "srv!SrvStatistics" );
  2381. if( !GetData( &s, dwAddress, sizeof(s), "SrvStatistics" ) )
  2382. return;
  2383. PrintMemberList( &s, ML_SRV_STATISTICS );
  2384. }
  2385. DECLARE_API( scavenger )
  2386. {
  2387. ULONG_PTR dwAddress;
  2388. CHAR buf[ 100 ];
  2389. int i;
  2390. int c=0;
  2391. strcpy( buf, "srv!" );
  2392. dprintf( "BOOLEAN Values (%u bytes):\n", sizeof( BOOLEAN ) );
  2393. for( i=0; ScavengerBool[i]; i++, c++ ) {
  2394. BOOLEAN b;
  2395. strcpy( &buf[4], ScavengerBool[i] );
  2396. dwAddress = GetExpression ( buf );
  2397. if( dwAddress == 0 ) {
  2398. ERRPRT( "Unable to get address of %s\n", ScavengerBool[i] );
  2399. continue;
  2400. }
  2401. if( !GetData( &b, dwAddress, sizeof(b), ScavengerBool[i] ) )
  2402. return;
  2403. dprintf( "%s%-30s %10s%s",
  2404. c&1 ? " " : "",
  2405. ScavengerBool[i],
  2406. b ? " TRUE" : "FALSE",
  2407. c&1 ? "\n" : "" );
  2408. }
  2409. dprintf( "%s\nLONG Values (%u bytes):\n", c&1 ? "\n" : "", sizeof( LONG ) );
  2410. c &= ~01;
  2411. for( i=0; ScavengerLong[i]; i++, c++ ) {
  2412. LONG l;
  2413. strcpy( &buf[4], ScavengerLong[i] );
  2414. dwAddress = GetExpression ( buf );
  2415. if( dwAddress == 0 ) {
  2416. ERRPRT( "Unable to get address of %s\n", ScavengerLong[i] );
  2417. continue;
  2418. }
  2419. if( !GetData( &l, dwAddress, sizeof(l), ScavengerLong[i] ) )
  2420. return;
  2421. dprintf( "%s%-30s %10u%s",
  2422. c&1 ? " " : "",
  2423. ScavengerLong[i],
  2424. l,
  2425. c&1 ? "\n" : "" );
  2426. }
  2427. }
  2428. DECLARE_API( srv )
  2429. {
  2430. ULONG_PTR dwAddress;
  2431. BOOLEAN b;
  2432. ULONG ul;
  2433. ULONG bytesWritten;
  2434. dwAddress = GetExpression( "srv!SrvProductTypeServer" );
  2435. b = TRUE;
  2436. WriteMemory( dwAddress, &b, sizeof(b), &bytesWritten );
  2437. if( bytesWritten != sizeof(b) ) {
  2438. ERRPRT( "Unable to update SrvProductTypeServer\n" );
  2439. return;
  2440. }
  2441. dwAddress = GetExpression( "srv!SrvCachedOpenLimit" );
  2442. ul = 5;
  2443. WriteMemory( dwAddress, &ul, sizeof(ul), &bytesWritten );
  2444. if( bytesWritten != sizeof(ul) ) {
  2445. ERRPRT( "Unable to update SrvCachedOpenLimit\n" );
  2446. }
  2447. }
  2448. DECLARE_API( wksta )
  2449. {
  2450. ULONG_PTR dwAddress;
  2451. BOOLEAN b;
  2452. ULONG ul;
  2453. ULONG bytesWritten;
  2454. dwAddress = GetExpression( "srv!SrvProductTypeServer" );
  2455. b = FALSE;
  2456. WriteMemory( dwAddress, &b, sizeof(b), &bytesWritten );
  2457. if( bytesWritten != sizeof(b) ) {
  2458. ERRPRT( "Unable to update SrvProductTypeServer\n" );
  2459. return;
  2460. }
  2461. dwAddress = GetExpression( "srv!SrvCachedOpenLimit" );
  2462. ul = 0;
  2463. WriteMemory( dwAddress, &ul, sizeof(ul), &bytesWritten );
  2464. if( bytesWritten != sizeof(ul) ) {
  2465. ERRPRT( "Unable to update SrvCachedOpenLimit\n" );
  2466. }
  2467. }
  2468. DECLARE_API( client )
  2469. {
  2470. ULONG_PTR epListAddress;
  2471. LIST_ENTRY *NextEndpoint;
  2472. ORDERED_LIST_HEAD SrvEndpointList;
  2473. WORK_QUEUE WorkQueue;
  2474. ULONG_PTR WorkQueueAddress = 0;
  2475. LONG SrvConnectionNoSessionsTimeout = 0;
  2476. ULONG_PTR dwAddress;
  2477. epListAddress = GetExpression ( "srv!SrvEndpointList" );
  2478. if( epListAddress == 0 ) {
  2479. ERRPRT( "Unable to get address of srv!SrvEndpointList\n" );
  2480. return;
  2481. }
  2482. if( !GetData( &SrvEndpointList,epListAddress,sizeof( SrvEndpointList ),"ORDERED_LIST_HEAD" )){
  2483. ERRPRT( "Unable to read data for srv!SrvEndpointList\n" );
  2484. return;
  2485. }
  2486. if( SrvEndpointList.Initialized == 0 ) {
  2487. ERRPRT( "srv!SrvEndpointList.Initialized == 0!\n" );
  2488. return;
  2489. }
  2490. if( (ULONG_PTR)SrvEndpointList.ListHead.Flink == epListAddress ) {
  2491. ERRPRT( "srv!SrvEndpointList list is empty\n" );
  2492. return;
  2493. }
  2494. if( (ULONG_PTR)SrvEndpointList.ListHead.Flink == 0 ) {
  2495. ERRPRT( "srv!SrvEndpointList.ListHead.Flink == 0: list is empty\n" );
  2496. return;
  2497. }
  2498. if( dwAddress = GetExpression( "srv!SrvConnectionNoSessionsTimeout" ) ) {
  2499. GetData( &SrvConnectionNoSessionsTimeout, dwAddress, sizeof(ULONG_PTR), "SrvConnectionNoSessionsTimeout" );
  2500. dprintf( "Session Idle Timeout: %d ticks\n", SrvConnectionNoSessionsTimeout );
  2501. }
  2502. NextEndpoint = SrvEndpointList.ListHead.Flink;
  2503. //
  2504. // Run the endpoint list, and run the connection list for each endpoint
  2505. //
  2506. do {
  2507. ENDPOINT endpoint;
  2508. CONNECTION connection;
  2509. PTABLE_ENTRY table;
  2510. USHORT i;
  2511. LONG idleTime;
  2512. dwAddress = (ULONG_PTR)CONTAINING_RECORD( NextEndpoint, ENDPOINT, GlobalEndpointListEntry );
  2513. if( CheckControlC() ) {
  2514. dprintf( "\n" );
  2515. break;
  2516. }
  2517. if( !GetData( &endpoint, dwAddress, sizeof( endpoint ), "ENDPOINT" ) ||
  2518. !CheckBlockHeader( &endpoint.BlockHeader, BlockTypeEndpoint, TRUE ) ) {
  2519. break;
  2520. }
  2521. //
  2522. // Now, run the connection table for this endpoint and print out the client names
  2523. // and connection structure address
  2524. //
  2525. if( endpoint.ConnectionTable.Table == NULL ) {
  2526. continue;
  2527. }
  2528. table = (PTABLE_ENTRY)LocalAlloc( LPTR,
  2529. endpoint.ConnectionTable.TableSize*sizeof(TABLE_ENTRY) );
  2530. if( table == NULL ) {
  2531. continue;
  2532. }
  2533. if( !GetData( table, (ULONG_PTR)endpoint.ConnectionTable.Table,
  2534. endpoint.ConnectionTable.TableSize*sizeof(TABLE_ENTRY), "TABLE" ) ) {
  2535. LocalFree( (HLOCAL)table );
  2536. continue;
  2537. }
  2538. for( i = 0; i < endpoint.ConnectionTable.TableSize; i++ ) {
  2539. if( table[i].Owner &&
  2540. GetData( &connection,(ULONG_PTR)table[i].Owner, sizeof( connection ),"CONNECTION") &&
  2541. connection.BlockHeader.ReferenceCount != 0 &&
  2542. connection.OemClientMachineName[0] &&
  2543. connection.OemClientMachineName[0] != ' ' ) {
  2544. if( args != NULL && *args != '\0' ) {
  2545. int j;
  2546. for( j = 0; args[j] ; j++ ) {
  2547. if( connection.OemClientMachineName[j] != args[j] )
  2548. break;
  2549. }
  2550. if( args[j] ) {
  2551. continue;
  2552. }
  2553. }
  2554. if( WorkQueueAddress != (ULONG_PTR)connection.CurrentWorkQueue ) {
  2555. if( GetData( &WorkQueue, (ULONG_PTR)connection.CurrentWorkQueue, sizeof( WorkQueue ), "WORK_QUEUE" ) ) {
  2556. WorkQueueAddress = (ULONG_PTR)connection.CurrentWorkQueue;
  2557. }
  2558. }
  2559. idleTime = WorkQueue.stats.SystemTime - connection.LastRequestTime;
  2560. dprintf( "%8X %-16s, Idle %d ticks\n", table[i].Owner,connection.OemClientMachineName,idleTime);
  2561. if( idleTime > SrvConnectionNoSessionsTimeout ) {
  2562. dprintf( "*** Above client is due for idle disconnect, if no open files\n" );
  2563. }
  2564. if( CheckControlC() ) {
  2565. dprintf( "\n" );
  2566. return;
  2567. }
  2568. }
  2569. }
  2570. LocalFree( (HLOCAL)table );
  2571. NextEndpoint = endpoint.GlobalEndpointListEntry.ListEntry.Flink;
  2572. } while( (ULONG_PTR)NextEndpoint != epListAddress );
  2573. }
  2574. DECLARE_API( errcodes )
  2575. {
  2576. ULONG_PTR dwAddress;
  2577. NTSTATUS status;
  2578. int count = 0;
  2579. dwAddress = GetExpression( "srv!SrvErrorLogIgnore" );
  2580. while( 1 ) {
  2581. if( !GetData( &status, dwAddress, sizeof( status ), "NTSTATUS" ) )
  2582. return;
  2583. if( status == 0 )
  2584. break;
  2585. dprintf( " %X", status );
  2586. dwAddress += sizeof( status );
  2587. if( (++count & 7) == 0 )
  2588. dprintf( "\n" );
  2589. }
  2590. dprintf( "\n" );
  2591. }
  2592. VOID
  2593. WinDbgExtensionDllInit(
  2594. PWINDBG_EXTENSION_APIS lpExtensionApis,
  2595. USHORT MajorVersion,
  2596. USHORT MinorVersion
  2597. )
  2598. {
  2599. ExtensionApis = *lpExtensionApis;
  2600. SavedMajorVersion = MajorVersion;
  2601. SavedMinorVersion = MinorVersion;
  2602. ChkTarget = SavedMajorVersion == 0x0c ? TRUE : FALSE;
  2603. }
  2604. DECLARE_API( version )
  2605. {
  2606. #if DBG
  2607. PCSTR kind = "Checked";
  2608. #else
  2609. PCSTR kind = "Free";
  2610. #endif
  2611. dprintf(
  2612. "%s SMB Extension dll for Build %d debugging %s kernel for Build %d\n",
  2613. kind,
  2614. VER_PRODUCTBUILD,
  2615. SavedMajorVersion == 0x0c ? "Checked" : "Free",
  2616. SavedMinorVersion
  2617. );
  2618. }
  2619. VOID
  2620. CheckVersion(
  2621. VOID
  2622. )
  2623. {
  2624. #if DBG
  2625. if ((SavedMajorVersion != 0x0c) || (SavedMinorVersion != VER_PRODUCTBUILD)) {
  2626. dprintf("\r\n*** Extension DLL(%d Checked) does not match target system(%d %s)\r\n\r\n",
  2627. VER_PRODUCTBUILD, SavedMinorVersion, (SavedMajorVersion==0x0f) ? "Free" : "Checked" );
  2628. }
  2629. #else
  2630. if ((SavedMajorVersion != 0x0f) || (SavedMinorVersion != VER_PRODUCTBUILD)) {
  2631. dprintf("\r\n*** Extension DLL(%d Free) does not match target system(%d %s)\r\n\r\n",
  2632. VER_PRODUCTBUILD, SavedMinorVersion, (SavedMajorVersion==0x0f) ? "Free" : "Checked" );
  2633. }
  2634. #endif
  2635. }
  2636. LPEXT_API_VERSION
  2637. ExtensionApiVersion(
  2638. VOID
  2639. )
  2640. {
  2641. return &ApiVersion;
  2642. }