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.

2401 lines
71 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. object.c
  5. Abstract:
  6. WinDbg Extension Api
  7. Author:
  8. Ramon J San Andres (ramonsa) 5-Nov-1993
  9. Environment:
  10. User Mode.
  11. Revision History:
  12. Kshitiz K. Sharma (kksharma)
  13. Using debugger type info.
  14. Daniel Mihai (DMihai)
  15. Add !htrace - for dumping handle tracing information.
  16. --*/
  17. #include "precomp.h"
  18. #pragma hdrstop
  19. typedef struct _SEGMENT_OBJECT {
  20. PVOID BaseAddress;
  21. ULONG TotalNumberOfPtes;
  22. LARGE_INTEGER SizeOfSegment;
  23. ULONG NonExtendedPtes;
  24. ULONG ImageCommitment;
  25. PVOID ControlArea;
  26. } SEGMENT_OBJECT, *PSEGMENT_OBJECT;
  27. typedef struct _SECTION_OBJECT {
  28. PVOID StartingVa;
  29. PVOID EndingVa;
  30. PVOID Parent;
  31. PVOID LeftChild;
  32. PVOID RightChild;
  33. PSEGMENT_OBJECT Segment;
  34. } SECTION_OBJECT;
  35. typedef ULONG64 (*ENUM_LIST_ROUTINE)(
  36. IN ULONG64 ListEntry,
  37. IN PVOID Parameter
  38. );
  39. static ULONG64 ObpTypeObjectType = 0;
  40. static ULONG64 ObpRootDirectoryObject = 0;
  41. static WCHAR ObjectNameBuffer[ MAX_PATH ];
  42. //
  43. // Object Type Structure
  44. //
  45. typedef struct _OBJECT_TYPE_READ {
  46. LIST_ENTRY64 TypeList;
  47. UNICODE_STRING64 Name;
  48. ULONG64 DefaultObject;
  49. ULONG Index;
  50. ULONG TotalNumberOfObjects;
  51. ULONG TotalNumberOfHandles;
  52. ULONG HighWaterNumberOfObjects;
  53. ULONG HighWaterNumberOfHandles;
  54. ULONG Key;
  55. } OBJECT_TYPE_READ, *POBJECT_TYPE_READ;
  56. BOOLEAN
  57. DumpObjectsForType(
  58. IN ULONG64 pObjectHeader,
  59. IN PVOID Parameter
  60. );
  61. ULONG64
  62. WalkRemoteList(
  63. IN ULONG64 Head,
  64. IN ENUM_LIST_ROUTINE EnumRoutine,
  65. IN PVOID Parameter
  66. );
  67. ULONG64
  68. CompareObjectTypeName(
  69. IN ULONG64 ListEntry,
  70. IN PVOID Parameter
  71. );
  72. PWSTR
  73. GetObjectName(
  74. ULONG64 Object
  75. );
  76. BOOLEAN
  77. GetObjectTypeName(
  78. IN UNICODE_STRING64 ustrTypeName,
  79. IN ULONG64 lpType,
  80. IN OUT WCHAR * wszTypeName
  81. );
  82. ULONG64 HighestUserAddress;
  83. DECLARE_API( obtrace )
  84. /*++
  85. Routine Description:
  86. Dump the object trace information for an object.
  87. Arguments:
  88. args - [object (pointer/path)]
  89. Return Value:
  90. None
  91. --*/
  92. {
  93. ULONG64 ObpObjectTable,
  94. ObpStackTable,
  95. ObpObjectBuckets,
  96. ObpTraceDepth,
  97. ObpStacksPerObject,
  98. ObjectToTrace,
  99. ObjectHash,
  100. ObjectHeader,
  101. ObRefInfoPtr,
  102. ObRefInfoPtrLoc,
  103. BaseStackInfoAddr,
  104. Offset,
  105. TraceAddr,
  106. Trace;
  107. ULONG ObjectHeaderBodyOffset,
  108. ObStackInfoTypeSize,
  109. PVoidTypeSize,
  110. Lupe,
  111. TraceNumber,
  112. NextPos,
  113. CountRef,
  114. CountDeref,
  115. BytesRead;
  116. USHORT Sequence,
  117. Index;
  118. UCHAR ImageFileName[16],
  119. FunctionName[256];
  120. FIELD_INFO ObRefInfoFields[] = {
  121. {"ObjectHeader", NULL, 0, DBG_DUMP_FIELD_COPY_FIELD_DATA, 0, &ObjectHeader},
  122. {"NextRef", NULL, 0, DBG_DUMP_FIELD_COPY_FIELD_DATA, 0, &ObRefInfoPtr},
  123. {"ImageFileName", NULL, 0, DBG_DUMP_FIELD_COPY_FIELD_DATA, 0, ImageFileName},
  124. {"StackInfo", NULL, 0, DBG_DUMP_FIELD_RETURN_ADDRESS, 0, NULL},
  125. {"NextPos", NULL, 0, DBG_DUMP_FIELD_COPY_FIELD_DATA, 0, &NextPos}
  126. }, ObStackInfoFields[] = {
  127. {"Sequence", NULL, 0, DBG_DUMP_FIELD_COPY_FIELD_DATA, 0, &Sequence},
  128. {"Index" , NULL, 0, DBG_DUMP_FIELD_COPY_FIELD_DATA, 0, &Index}
  129. };
  130. SYM_DUMP_PARAM ObRefInfo = {
  131. sizeof (SYM_DUMP_PARAM), "nt!_OBJECT_REF_INFO", DBG_DUMP_NO_PRINT,
  132. 0, NULL, NULL, NULL, 2, &ObRefInfoFields[0]
  133. }, ObStackInfo = {
  134. sizeof (SYM_DUMP_PARAM), "nt!_OBJECT_REF_STACK_INFO", DBG_DUMP_NO_PRINT,
  135. 0, NULL, NULL, NULL, 2, &ObStackInfoFields[0]
  136. };
  137. ObpObjectTable = GetUlongValue("ObpObjectTable");
  138. ObpStackTable = GetUlongValue("ObpStackTable");
  139. ObpObjectBuckets = GetUlongValue("ObpObjectBuckets");
  140. ObpTraceDepth = GetUlongValue("ObpTraceDepth");
  141. ObpStacksPerObject = GetUlongValue("ObpStacksPerObject");
  142. if (GetFieldOffset("nt!_OBJECT_HEADER",
  143. "Body",
  144. &ObjectHeaderBodyOffset)) {
  145. return E_INVALIDARG;
  146. }
  147. ObStackInfoTypeSize = GetTypeSize("nt!_OBJECT_REF_STACK_INFO");
  148. PVoidTypeSize = IsPtr64() ? 8 : 4;
  149. if (strlen(args) < 1) {
  150. return E_INVALIDARG;
  151. }
  152. if (args[0] == '\\') {
  153. ObjectToTrace = FindObjectByName((PUCHAR)args, 0);
  154. } else {
  155. ObjectToTrace = GetExpression(args);
  156. }
  157. if (ObjectToTrace == 0) {
  158. dprintf("Object %s not found.\n", args);
  159. return E_INVALIDARG;
  160. }
  161. // ObjectRefChain <= ObpObjectTable[OBTRACE_HASHOBJECT(ObjectToTrace)]
  162. ObjectHash = ((ObjectToTrace >> 4) & 0xfffff) % (ObpObjectBuckets ? ObpObjectBuckets : 1);
  163. ObRefInfoPtrLoc = ObpObjectTable + GetTypeSize("nt!POBJECT_REF_INFO") * ObjectHash;
  164. for (ObRefInfo.addr = GetPointerFromAddress(ObRefInfoPtrLoc);
  165. ObRefInfo.addr;
  166. ObRefInfo.addr = ObRefInfoPtr) {
  167. if (Ioctl(IG_DUMP_SYMBOL_INFO, &ObRefInfo, ObRefInfo.size)) {
  168. dprintf("Unable to read ObRefInfo %x\n", ObRefInfo.addr);
  169. return E_INVALIDARG;
  170. }
  171. if (ObjectHeader == ObjectToTrace - ObjectHeaderBodyOffset) {
  172. break;
  173. }
  174. if (CheckControlC()) {
  175. dprintf("Aborting object lookup\n");
  176. return S_OK;
  177. }
  178. }
  179. if (! ObRefInfo.addr) {
  180. dprintf("Unable to find object in table.\n");
  181. return E_INVALIDARG;
  182. }
  183. // We need the rest of the fields now
  184. ObRefInfo.nFields = sizeof(ObRefInfoFields) / sizeof(ObRefInfoFields[0]);
  185. if (Ioctl(IG_DUMP_SYMBOL_INFO, &ObRefInfo, ObRefInfo.size)) {
  186. return E_INVALIDARG;
  187. }
  188. BaseStackInfoAddr = ObRefInfoFields[3].address;
  189. dprintf("Object: %x\n", ObjectToTrace);
  190. dprintf(" Image: %s\n", ImageFileName);
  191. dprintf("Seq. Stack\n");
  192. dprintf("---- ----------------------------------------------------------\n");
  193. CountRef = 0;
  194. CountDeref = 0;
  195. for (Lupe = 0;
  196. Lupe < NextPos;
  197. Lupe++) {
  198. if (CheckControlC()) {
  199. return S_OK;
  200. }
  201. ObStackInfo.addr = BaseStackInfoAddr + Lupe * ObStackInfoTypeSize;
  202. if (Ioctl(IG_DUMP_SYMBOL_INFO, &ObStackInfo, ObStackInfo.size)) {
  203. dprintf("Unable to read ObStackInfo %x\n", ObStackInfo.addr);
  204. return E_INVALIDARG;
  205. }
  206. if (Index & 0x8000) {
  207. CountRef++;
  208. } else {
  209. CountDeref++;
  210. }
  211. for (TraceNumber = 0;
  212. TraceNumber < ObpTraceDepth;
  213. TraceNumber++) {
  214. TraceAddr = ObpStackTable
  215. + (PVoidTypeSize
  216. * (ObpTraceDepth * (Index & 0x7fff)
  217. + TraceNumber));
  218. Trace = GetPointerFromAddress(TraceAddr);
  219. if (Trace) {
  220. GetSymbol(Trace, FunctionName, &Offset);
  221. if (TraceNumber == 0) {
  222. dprintf("%04x %c",
  223. Sequence,
  224. Index & 0x8000 ? '+' : ' ');
  225. } else {
  226. dprintf(" "); /* six spaces */
  227. }
  228. dprintf("%s+%x\n", FunctionName, Offset);
  229. }
  230. if (CheckControlC()) {
  231. return S_OK;
  232. }
  233. }
  234. dprintf("\n");
  235. }
  236. dprintf("---- ----------------------------------------------------------\n");
  237. dprintf("References: %d, Dereferences %d", CountRef, CountDeref);
  238. if(CountDeref + CountRef == ObpStacksPerObject) {
  239. dprintf(" (maximum stacks reached)");
  240. }
  241. dprintf("\n");
  242. return S_OK;
  243. }
  244. DECLARE_API( object )
  245. /*++
  246. Routine Description:
  247. Dump an object manager object.
  248. Arguments:
  249. args - 0 <TypeName> | <Path> | <Address> | -r
  250. Return Value:
  251. None
  252. --*/
  253. {
  254. ULONG64 ObjectToDump = 0;
  255. char NameBuffer[ MAX_PATH+1 ];
  256. ULONG NumberOfObjects;
  257. ULONG ObjectDumpFlags = 0xFFFFFFFF;
  258. HighestUserAddress = GetNtDebuggerDataValue(MmHighestUserAddress);
  259. if (!FetchObjectManagerVariables(FALSE)) {
  260. return E_INVALIDARG;
  261. }
  262. ObjectToDump = EXPRLastDump;
  263. ZeroMemory(NameBuffer, sizeof(NameBuffer));
  264. // Skip leading whitespace
  265. while (args && (*args == ' ')) {
  266. ++args;
  267. }
  268. //
  269. // If the argument looks like a path, try to chase it.
  270. //
  271. if (args[0] == '\\') {
  272. ULONG64 object;
  273. object = FindObjectByName((PUCHAR) args, 0);
  274. if (object != 0) {
  275. DumpObject("", object, ObjectDumpFlags);
  276. } else {
  277. dprintf("Object %s not found\n", args);
  278. }
  279. return S_OK;
  280. }
  281. //
  282. // If the argument is -r or -R, reload the cached symbol information
  283. //
  284. if ( !strcmp(args, "-r") ) {
  285. FetchObjectManagerVariables(TRUE);
  286. return S_OK;
  287. }
  288. if ( !strcmp(args, "-h") || !strcmp(args, "-?") ||
  289. (strlen(args) == 0) ) {
  290. dprintf("Usage: !object [[-r] | [<Path>] | [<Address>] | [0 <TypeName>]]\n");
  291. return S_OK;
  292. }
  293. //
  294. // If the argument looks like 0 <TypeName>, get TypeName
  295. //
  296. if ((args[0] == '0') && (args[1] == ' ')) {
  297. args += 2;
  298. while (args && (*args == ' ')) {
  299. ++args;
  300. }
  301. strncpy(NameBuffer, args, sizeof(NameBuffer)/sizeof(char) - 1);
  302. ObjectToDump = 0;
  303. } else {
  304. //
  305. // Argument must be in form of address or expression
  306. //
  307. if (GetExpressionEx(args,&ObjectToDump, &args)) {
  308. DumpObject("", ObjectToDump, ObjectDumpFlags);
  309. return S_OK;
  310. } else {
  311. dprintf("*** Invalid address argument specified\n");
  312. return E_INVALIDARG;
  313. }
  314. if (!args || !*args) {
  315. dprintf("*** Unrecognized argument(s) specified: '%s'\n",
  316. args);
  317. return E_INVALIDARG;
  318. }
  319. }
  320. if ( (ObjectToDump == 0) && (strlen( NameBuffer ) > 0) ) {
  321. NumberOfObjects = 0;
  322. if (WalkObjectsByType( NameBuffer, DumpObjectsForType, &NumberOfObjects )) {
  323. dprintf( "Total of %u objects of type '%s'\n", NumberOfObjects, NameBuffer );
  324. return S_OK;
  325. }
  326. return E_INVALIDARG;
  327. }
  328. dprintf( "*** invalid syntax.\n" );
  329. return E_INVALIDARG;
  330. }
  331. BOOLEAN
  332. DumpObjectsForType(
  333. IN ULONG64 pObjectHeader,
  334. IN PVOID Parameter
  335. )
  336. {
  337. ULONG64 Object;
  338. ULONG BodyOffset;
  339. PULONG NumberOfObjects = (PULONG)Parameter;
  340. if (GetFieldOffset("nt!_OBJECT_HEADER", "Body", &BodyOffset)) {
  341. return FALSE;
  342. }
  343. *NumberOfObjects += 1;
  344. Object = pObjectHeader + BodyOffset;
  345. DumpObject( "", Object, 0xFFFFFFFF );
  346. return TRUE;
  347. }
  348. BOOLEAN
  349. FetchObjectManagerVariables(
  350. BOOLEAN ForceReload
  351. )
  352. {
  353. ULONG Result;
  354. ULONG64 Addr;
  355. static BOOL HaveObpVariables = FALSE;
  356. if (HaveObpVariables && !ForceReload) {
  357. return TRUE;
  358. }
  359. Addr = GetNtDebuggerData( ObpTypeObjectType );
  360. if ( !Addr ||
  361. !ReadPointer( Addr,
  362. &ObpTypeObjectType) ) {
  363. dprintf("%08p: Unable to get value of ObpTypeObjectType\n", Addr );
  364. return FALSE;
  365. }
  366. Addr = GetNtDebuggerData( ObpRootDirectoryObject );
  367. if ( !Addr ||
  368. !ReadPointer( Addr,
  369. &ObpRootDirectoryObject) ) {
  370. dprintf("%08p: Unable to get value of ObpRootDirectoryObject\n",Addr );
  371. return FALSE;
  372. }
  373. HaveObpVariables = TRUE;
  374. return TRUE;
  375. }
  376. ULONG64
  377. FindObjectType(
  378. IN PUCHAR TypeName
  379. )
  380. {
  381. WCHAR NameBuffer[ 64 ] = {0};
  382. FIELD_INFO offField = {"TypeList", NULL, 0, DBG_DUMP_FIELD_RETURN_ADDRESS, 0, NULL};
  383. SYM_DUMP_PARAM TypeSym ={
  384. sizeof (SYM_DUMP_PARAM), "nt!_OBJECT_TYPE", DBG_DUMP_NO_PRINT, 0,
  385. NULL, NULL, NULL, 1, &offField
  386. };
  387. // Get The offset
  388. if (Ioctl(IG_DUMP_SYMBOL_INFO, &TypeSym, TypeSym.size)) {
  389. return 0;
  390. }
  391. _snwprintf( NameBuffer,
  392. sizeof( NameBuffer ) / sizeof( WCHAR ) - sizeof(WCHAR),
  393. L"%hs",
  394. TypeName
  395. );
  396. return WalkRemoteList( ObpTypeObjectType + offField.address,
  397. CompareObjectTypeName,
  398. NameBuffer
  399. );
  400. }
  401. ULONG64
  402. WalkRemoteList(
  403. IN ULONG64 Head,
  404. IN ENUM_LIST_ROUTINE EnumRoutine,
  405. IN PVOID Parameter
  406. )
  407. {
  408. ULONG Result;
  409. ULONG64 Element;
  410. ULONG64 Flink;
  411. ULONG64 Next;
  412. if ( GetFieldValue(Head, "nt!_LIST_ENTRY", "Flink", Next)) {
  413. dprintf( "%08lx: Unable to read list\n", Head );
  414. return 0;
  415. }
  416. while (Next != Head) {
  417. Element = (EnumRoutine)( Next, Parameter );
  418. if (Element != 0) {
  419. return Element;
  420. }
  421. if ( CheckControlC() ) {
  422. return 0;
  423. }
  424. if ( GetFieldValue(Next, "nt!_LIST_ENTRY", "Flink", Flink)) {
  425. dprintf( "%08lx: Unable to read list\n", Next );
  426. return 0;
  427. }
  428. Next = Flink;
  429. }
  430. return 0;
  431. }
  432. ULONG64
  433. CompareObjectTypeName(
  434. IN ULONG64 ListEntry,
  435. IN PVOID Parameter
  436. )
  437. {
  438. ULONG Result;
  439. ULONG64 pObjectTypeObjectHeader;
  440. WCHAR NameBuffer[ 64 ];
  441. UNICODE_STRING64 Name64={0};
  442. ULONG64 pCreatorInfo;
  443. ULONG64 pNameInfo;
  444. ULONG BodyOffset, TypeListOffset;
  445. // Get The offset
  446. if (GetFieldOffset("nt!_OBJECT_HEADER_CREATOR_INFO", "TypeList", &TypeListOffset)) {
  447. dprintf("Type nt!_OBJECT_HEADER_CREATOR_INFO, field TypeList not found\n");
  448. return FALSE;
  449. }
  450. pCreatorInfo = ListEntry - TypeListOffset;
  451. pObjectTypeObjectHeader = (pCreatorInfo + GetTypeSize("nt!_OBJECT_HEADER_CREATOR_INFO"));
  452. KD_OBJECT_HEADER_TO_NAME_INFO( pObjectTypeObjectHeader, &pNameInfo);
  453. GetFieldValue(pNameInfo, "nt!_OBJECT_HEADER_NAME_INFO", "Name.Length", Name64.Length);
  454. GetFieldValue(pNameInfo, "nt!_OBJECT_HEADER_NAME_INFO", "Name.MaximumLength", Name64.MaximumLength);
  455. GetFieldValue(pNameInfo, "nt!_OBJECT_HEADER_NAME_INFO", "Name.Buffer", Name64.Buffer);
  456. if (Name64.Length > sizeof( NameBuffer )) {
  457. Name64.Length = sizeof( NameBuffer ) - sizeof( UNICODE_NULL );
  458. }
  459. if (GetFieldOffset("nt!_OBJECT_HEADER", "Body", &BodyOffset)) {
  460. dprintf("Type nt!_OBJECT_HEADER, field Body not found\n");
  461. return FALSE;
  462. }
  463. if (!GetObjectTypeName(Name64, (pObjectTypeObjectHeader + BodyOffset) , NameBuffer))
  464. {
  465. dprintf( "%08p: Unable to read object type name.\n", pObjectTypeObjectHeader );
  466. return 0;
  467. }
  468. NameBuffer[ Name64.Length / sizeof( WCHAR ) ] = UNICODE_NULL;
  469. if (!_wcsicmp( NameBuffer, (PWSTR)Parameter )) {
  470. return (pObjectTypeObjectHeader + BodyOffset);
  471. }
  472. return 0;
  473. }
  474. typedef struct _OBJECT_HEADER_READ {
  475. LONG PointerCount;
  476. LONG HandleCount;
  477. ULONG64 SEntry;
  478. ULONG64 Type;
  479. UCHAR NameInfoOffset;
  480. UCHAR HandleInfoOffset;
  481. UCHAR QuotaInfoOffset;
  482. UCHAR Flags;
  483. ULONG64 ObjectCreateInfo;
  484. ULONG64 SecurityDescriptor;
  485. QUAD Body;
  486. } OBJECT_HEADER_READ, *POBJECT_HEADER_READ;
  487. typedef struct OBJECT_HEADER_NAME_INFO_READ {
  488. ULONG64 Directory;
  489. UNICODE_STRING64 Name;
  490. } OBJECT_HEADER_NAME_INFO_READ;
  491. typedef struct _OBJECT_INFO {
  492. ULONG64 pObjectHeader;
  493. OBJECT_HEADER_READ ObjectHeader;
  494. OBJECT_TYPE_READ ObjectType;
  495. OBJECT_HEADER_NAME_INFO_READ NameInfo;
  496. WCHAR TypeName[ 32 ];
  497. WCHAR ObjectName[ 256 ];
  498. WCHAR FileSystemName[ 32 ];
  499. CHAR Message[ 256 ];
  500. } OBJECT_INFO, *POBJECT_INFO;
  501. //+---------------------------------------------------------------------------
  502. //
  503. // Function: GetObjectTypeName
  504. //
  505. // Synopsis: Fill in the ObjectTypeName in the ObjectInfo struct
  506. //
  507. // Arguments: [Object] -- object examined used only in an error message
  508. // [ObjectInfo] -- struct containing object type info that is
  509. // modified to include the object type name
  510. //
  511. // Returns: TRUE if successful
  512. //
  513. // History: 12-05-1997 benl Created
  514. //
  515. // Notes: If the name is paged out we try a direct comparison against
  516. // known object types, this known list is not comprehensive
  517. //
  518. //----------------------------------------------------------------------------
  519. BOOLEAN
  520. GetObjectTypeName(IN UNICODE_STRING64 ustrTypeName, IN ULONG64 lpType,
  521. IN OUT WCHAR * wszTypeName)
  522. {
  523. DWORD dwResult;
  524. BOOLEAN fRet = TRUE;
  525. ULONG64 dwIoFileObjectType = 0;
  526. ULONG64 dwCmpKeyObjectType = 0;
  527. ULONG64 dwMmSectionObjectType = 0;
  528. ULONG64 dwObpDirectoryObjectType = 0;
  529. ULONG64 dwObpSymbolicLinkObjectType = 0;
  530. __try
  531. {
  532. if (ReadMemory( ustrTypeName.Buffer,
  533. wszTypeName,
  534. ustrTypeName.Length,
  535. &dwResult
  536. )){
  537. fRet = TRUE;
  538. __leave;
  539. }
  540. //
  541. // Unable to directly read object type name so try to load the known
  542. // types directly and compare addresses
  543. // This is not comprehensive for all object types, if we don't find
  544. // a match this way - revert to old behavior and fail with a message
  545. //
  546. if (!ReadPointer( GetExpression("NT!IoFileObjectType"),
  547. &dwIoFileObjectType)) {
  548. dprintf("Unable to load NT!IoFileObjectType\n");
  549. } else if (dwIoFileObjectType == lpType) {
  550. wcscpy(wszTypeName, L"File");
  551. __leave;
  552. }
  553. if (!ReadPointer( GetExpression("NT!CmpKeyObjectType"),
  554. &dwCmpKeyObjectType)) {
  555. dprintf("Unable to load NT!CmpKeyObjectType\n");
  556. } else if (dwCmpKeyObjectType == lpType) {
  557. wcscpy(wszTypeName, L"Key");
  558. __leave;
  559. }
  560. if (!ReadPointer( GetExpression("NT!MmSectionObjectType"),
  561. &dwMmSectionObjectType)) {
  562. dprintf("Unable to load NT!MmSectionObjectType\n");
  563. } else if (dwMmSectionObjectType == lpType) {
  564. wcscpy(wszTypeName, L"Section");
  565. __leave;
  566. }
  567. if (!ReadPointer( GetExpression("NT!ObpDirectoryObjectType"),
  568. &dwObpDirectoryObjectType)) {
  569. dprintf("Unable to load NT!ObpDirectoryObjectType\n");
  570. } else if (dwObpDirectoryObjectType == lpType) {
  571. wcscpy(wszTypeName, L"Directory");
  572. __leave;
  573. }
  574. if (!ReadPointer( GetExpression("NT!ObpSymbolicLinkObjectType"),
  575. &dwObpDirectoryObjectType)) {
  576. dprintf("Unable to load NT!ObpSymbolicLinkObjectType\n");
  577. } else if (dwObpSymbolicLinkObjectType == lpType) {
  578. wcscpy(wszTypeName, L"SymbolicLink");
  579. __leave;
  580. }
  581. //
  582. //Fallthrough if type not found
  583. //
  584. wszTypeName[0] = L'\0';
  585. fRet = FALSE;
  586. } __finally
  587. {
  588. }
  589. return fRet;
  590. } // GetObjectTypeName
  591. BOOLEAN
  592. GetObjectInfo(
  593. ULONG64 Object,
  594. POBJECT_INFO ObjectInfo
  595. )
  596. {
  597. ULONG Result;
  598. ULONG64 pNameInfo;
  599. BOOLEAN PagedOut;
  600. UNICODE_STRING64 ObjectName;
  601. PWSTR FileSystemName;
  602. SECTION_OBJECT SectionObject;
  603. SEGMENT_OBJECT SegmentObject;
  604. ULONG BodyOffset;
  605. #define Hdr ObjectInfo->ObjectHeader
  606. FIELD_INFO ObjHdrFields[] = {
  607. {"PointerCount" , "", 0, DBG_DUMP_FIELD_COPY_FIELD_DATA, 0, (PVOID) &Hdr.PointerCount},
  608. {"HandleCount" , "", 0, DBG_DUMP_FIELD_COPY_FIELD_DATA, 0, (PVOID) &Hdr.HandleCount},
  609. {"SEntry" , "", 0, DBG_DUMP_FIELD_COPY_FIELD_DATA, 0, (PVOID) &Hdr.SEntry},
  610. {"Type" , "", 0, DBG_DUMP_FIELD_COPY_FIELD_DATA | DBG_DUMP_FIELD_RECUR_ON_THIS, 0, (PVOID) &Hdr.Type},
  611. {"NameInfoOffset" , "", 0, DBG_DUMP_FIELD_COPY_FIELD_DATA, 0, (PVOID) &Hdr.NameInfoOffset},
  612. {"HandleInfoOffset" , "", 0, DBG_DUMP_FIELD_COPY_FIELD_DATA, 0, (PVOID) &Hdr.HandleInfoOffset},
  613. {"QuotaInfoOffset" , "", 0, DBG_DUMP_FIELD_COPY_FIELD_DATA, 0, (PVOID) &Hdr.QuotaInfoOffset},
  614. {"Flags" , "", 0, DBG_DUMP_FIELD_COPY_FIELD_DATA, 0, (PVOID) &Hdr.Flags},
  615. {"ObjectCreateInfo" , "", 0, DBG_DUMP_FIELD_COPY_FIELD_DATA, 0, (PVOID) &Hdr.ObjectCreateInfo},
  616. {"SecurityDescriptor","", 0, DBG_DUMP_FIELD_COPY_FIELD_DATA, 0, (PVOID) &Hdr.SecurityDescriptor},
  617. };
  618. #undef Hdr
  619. SYM_DUMP_PARAM ObjSym ={
  620. sizeof (SYM_DUMP_PARAM), "nt!_OBJECT_HEADER", DBG_DUMP_NO_PRINT, 0,
  621. NULL, NULL, NULL, sizeof (ObjHdrFields) / sizeof (FIELD_INFO), &ObjHdrFields[0]
  622. };
  623. PagedOut = FALSE;
  624. memset( ObjectInfo, 0, sizeof( *ObjectInfo ) );
  625. GetFieldOffset("nt!_OBJECT_HEADER", "Body", &BodyOffset);
  626. ObjectInfo->pObjectHeader = (Object - BodyOffset); // (OBJECT_TO_OBJECT_HEADER( Object );
  627. ObjSym.addr = ObjectInfo->pObjectHeader;
  628. if (Ioctl(IG_DUMP_SYMBOL_INFO, &ObjSym, ObjSym.size)) {
  629. if (Object >= HighestUserAddress && (ULONG)Object < 0xF0000000) {
  630. PagedOut = TRUE;
  631. return FALSE;
  632. // Not using Opt Value
  633. /*
  634. sprintf( ObjectInfo->Message, "%08lx: object is paged out.", Object );
  635. if (!ARGUMENT_PRESENT( OptObjectHeader )) {
  636. return FALSE;
  637. }
  638. ObjectInfo->ObjectHeader.Flags = OptObjectHeader->Flags;
  639. ObjectInfo->ObjectHeader.HandleCount = OptObjectHeader->HandleCount;
  640. ObjectInfo->ObjectHeader.NameInfoOffset = OptObjectHeader->NameInfoOffset;
  641. ObjectInfo->ObjectHeader.ObjectCreateInfo = (ULONG64) OptObjectHeader->ObjectCreateInfo;
  642. ObjectInfo->ObjectHeader.PointerCount = OptObjectHeader->PointerCount;
  643. ObjectInfo->ObjectHeader.QuotaInfoOffset = OptObjectHeader->QuotaInfoOffset;
  644. ObjectInfo->ObjectHeader.SecurityDescriptor = (ULONG64) OptObjectHeader->SecurityDescriptor;
  645. ObjectInfo->ObjectHeader.SEntry = (ULONG64) OptObjectHeader->SEntry;
  646. ObjectInfo->ObjectHeader.Type = (ULONG64) OptObjectHeader->Type;*/
  647. } else {
  648. sprintf( ObjectInfo->Message, "%I64lx: not a valid object (ObjectHeader invalid @ -offset %x)", UNEXTEND64(Object), BodyOffset );
  649. return FALSE;
  650. }
  651. }
  652. if (!ObjectInfo->ObjectHeader.Type) {
  653. sprintf( ObjectInfo->Message, "%08I64lx: Not a valid object (ObjectType invalid)", UNEXTEND64(Object) );
  654. return FALSE;
  655. }
  656. GetFieldValue(ObjectInfo->ObjectHeader.Type, "nt!_OBJECT_TYPE",
  657. "Name.Length", ObjectInfo->ObjectType.Name.Length);
  658. GetFieldValue(ObjectInfo->ObjectHeader.Type, "nt!_OBJECT_TYPE",
  659. "Name.MaximumLength", ObjectInfo->ObjectType.Name.MaximumLength);
  660. GetFieldValue(ObjectInfo->ObjectHeader.Type, "nt!_OBJECT_TYPE",
  661. "Name.Buffer", ObjectInfo->ObjectType.Name.Buffer);
  662. if (ObjectInfo->ObjectType.Name.Length >= sizeof( ObjectInfo->TypeName )) {
  663. ObjectInfo->ObjectType.Name.Length = sizeof( ObjectInfo->TypeName ) - sizeof( UNICODE_NULL );
  664. }
  665. if (!GetObjectTypeName(ObjectInfo->ObjectType.Name,
  666. ObjectInfo->ObjectHeader.Type, ObjectInfo->TypeName))
  667. {
  668. sprintf( ObjectInfo->Message, "%I64lx: Not a valid object "
  669. "(ObjectType.Name at 0x%I64lx invalid)",
  670. UNEXTEND64(Object), ObjectInfo->ObjectType.Name.Buffer);
  671. return FALSE;
  672. }
  673. ObjectInfo->TypeName[ ObjectInfo->ObjectType.Name.Length / sizeof( WCHAR ) ] = UNICODE_NULL;
  674. if (PagedOut) {
  675. return TRUE;
  676. }
  677. if (!wcscmp( ObjectInfo->TypeName, L"File" )) {
  678. ULONG64 DeviceObject=0;
  679. if (GetFieldValue(Object, "nt!_FILE_OBJECT", "FileName.Buffer", ObjectName.Buffer)) {
  680. sprintf( ObjectInfo->Message, "%08I64lx: unable to read _FILE_OBJECT for name\n", UNEXTEND64(Object) );
  681. } else {
  682. GetFieldValue(Object, "nt!_FILE_OBJECT", "DeviceObject", DeviceObject);
  683. GetFieldValue(Object, "nt!_FILE_OBJECT", "FileName.Length", ObjectName.Length);
  684. GetFieldValue(Object, "nt!_FILE_OBJECT", "FileName.MaximumLength", ObjectName.MaximumLength);
  685. FileSystemName = GetObjectName( DeviceObject );
  686. if (FileSystemName != NULL) {
  687. wcscpy( ObjectInfo->FileSystemName, FileSystemName );
  688. }
  689. }
  690. } else if (!wcscmp( ObjectInfo->TypeName, L"Key" )) {
  691. ULONG64 pKeyControlBlock=0;
  692. if (GetFieldValue(Object, "nt!_CM_KEY_BODY", "KeyControlBlock", pKeyControlBlock)) {
  693. sprintf( ObjectInfo->Message, "%08I64lx: unable to read key object for name\n", UNEXTEND64(Object) );
  694. } else if (!pKeyControlBlock) {
  695. sprintf( ObjectInfo->Message, "%08I64lx: unable to read key control block for name\n", UNEXTEND64(pKeyControlBlock) );
  696. } else {
  697. ObjectName.Length = GetKcbName( pKeyControlBlock,
  698. ObjectInfo->ObjectName,
  699. sizeof( ObjectInfo->ObjectName));
  700. return TRUE;
  701. }
  702. } else {
  703. if (ObjectInfo->ObjectHeader.NameInfoOffset) {
  704. pNameInfo = ObjectInfo->pObjectHeader - ObjectInfo->ObjectHeader.NameInfoOffset;
  705. } else {
  706. return TRUE;
  707. }
  708. if ( InitTypeRead(pNameInfo, nt!_OBJECT_HEADER_NAME_INFO) ) {
  709. dprintf( ObjectInfo->Message, "*** unable to read _OBJECT_HEADER_NAME_INFO at %08p\n", pNameInfo );
  710. return FALSE;
  711. }
  712. ObjectInfo->NameInfo.Name.Length = (USHORT) ReadField(Name.Length);
  713. ObjectInfo->NameInfo.Name.MaximumLength = (USHORT) ReadField(Name.MaximumLength);
  714. ObjectInfo->NameInfo.Name.Buffer = ReadField(Name.Buffer);
  715. ObjectInfo->NameInfo.Directory = ReadField(Directory);
  716. ObjectName = ObjectInfo->NameInfo.Name;
  717. }
  718. if (ObjectName.Length == 0 && !wcscmp( ObjectInfo->TypeName, L"Section" )) {
  719. ULONG PtrSize = GetTypeSize("nt!PVOID");
  720. ULONG64 Segment=0;
  721. //
  722. // Get Types of SectionObject etc
  723. //
  724. //
  725. // Assumption ptr to section object is 6th pointer value from Object
  726. //
  727. if (!GetFieldValue( Object, "nt!_SECTION_OBJECT", "Segment", Segment)) {
  728. ULONG64 ControlArea=0;
  729. if (Segment && !GetFieldValue( Segment, "nt!_SEGMENT_OBJECT", "ControlArea", ControlArea)) {
  730. ULONG64 FilePointer=0;
  731. if (ControlArea &&
  732. !GetFieldValue( Segment, "nt!_CONTROL_AREA", "FilePointer", FilePointer)) {
  733. if (FilePointer) {
  734. GetFieldValue(FilePointer, "nt!_FILE_OBJECT", "FileName.Length", ObjectName.Length);
  735. GetFieldValue(FilePointer, "nt!_FILE_OBJECT", "FileName.Buffer", ObjectName.Buffer);
  736. ObjectName.MaximumLength = ObjectName.Length;
  737. } else {
  738. sprintf( ObjectInfo->Message, "unable to read file object at %08I64lx for section %08I64lx\n",
  739. UNEXTEND64(FilePointer), UNEXTEND64(Object) );
  740. }
  741. } else {
  742. sprintf( ObjectInfo->Message, "unable to read segment object at %08I64lx for section %08I64lx\n",
  743. UNEXTEND64(ControlArea), UNEXTEND64(Object) );
  744. }
  745. } else {
  746. sprintf( ObjectInfo->Message, "unable to read segment object at %08I64lx for section %08I64lx\n",
  747. UNEXTEND64(Segment), UNEXTEND64(Object) );
  748. }
  749. } else {
  750. sprintf( ObjectInfo->Message, "unable to read section object at %08lx\n", Object );
  751. }
  752. }
  753. if (ObjectName.Length >= sizeof( ObjectInfo->ObjectName )) {
  754. ObjectName.Length = sizeof( ObjectInfo->ObjectName ) - sizeof( UNICODE_NULL );
  755. }
  756. if (ObjectName.Length != 0) {
  757. if (!ReadMemory( ObjectName.Buffer,
  758. ObjectInfo->ObjectName,
  759. ObjectName.Length,
  760. &Result
  761. )
  762. ) {
  763. wcscpy( ObjectInfo->ObjectName, L"(*** Name not accessable ***)" );
  764. } else {
  765. ObjectInfo->ObjectName[ ObjectName.Length / sizeof( WCHAR ) ] = UNICODE_NULL;
  766. }
  767. }
  768. return TRUE;
  769. }
  770. ULONG64
  771. FindObjectByName(
  772. IN PUCHAR Path,
  773. IN ULONG64 RootObject
  774. )
  775. {
  776. ULONG Result, i, j;
  777. ULONG64 pDirectoryObject;
  778. ULONG64 pDirectoryEntry;
  779. ULONG64 HashBucketsAddress;
  780. ULONG HashBucketSz;
  781. OBJECT_INFO ObjectInfo;
  782. BOOLEAN foundMatch = FALSE;
  783. ULONG HashOffset;
  784. PUCHAR nextPath;
  785. if (RootObject == 0) {
  786. if (!FetchObjectManagerVariables(FALSE)) {
  787. return 0;
  788. }
  789. RootObject = ObpRootDirectoryObject;
  790. }
  791. pDirectoryObject = RootObject;
  792. //
  793. // See if we've reached the end of the path, at which point we know
  794. // that RootObject is the object to be dumped.
  795. //
  796. if (*Path == '\0') {
  797. return RootObject;
  798. }
  799. //
  800. // Scan the path looking for another delimiter or for the end of the
  801. // string.
  802. nextPath = Path;
  803. while ((*nextPath != '\0') &&
  804. (*nextPath != '\\')) {
  805. nextPath++;
  806. }
  807. //
  808. // if we found a delimeter remove it from the next path and use it to
  809. // truncate the current path.
  810. //
  811. if (*nextPath == '\\') {
  812. *nextPath = '\0';
  813. nextPath++;
  814. }
  815. //
  816. // Make sure there's a path node here. If not, recursively call ourself
  817. // with the remainder of the path.
  818. //
  819. if (*Path == '\0') {
  820. return FindObjectByName(nextPath, RootObject);
  821. }
  822. //
  823. // Get the address of hashbuckets array and size of the pointer to scan the array
  824. //
  825. if (GetFieldOffset("nt!_OBJECT_DIRECTORY", "HashBuckets", &HashOffset)) {
  826. dprintf("Cannot find _OBJECT_DIRECTORY type.\n");
  827. return FALSE;
  828. }
  829. HashBucketsAddress = pDirectoryObject + HashOffset;
  830. HashBucketSz = IsPtr64() ? 8 : 4;
  831. // From ob.h
  832. #define NUMBER_HASH_BUCKETS 37
  833. for (i=0; i<NUMBER_HASH_BUCKETS; i++) {
  834. ULONG64 HashBucketI = 0;
  835. ReadPointer(HashBucketsAddress + i*HashBucketSz, &HashBucketI);
  836. if (HashBucketI != 0) {
  837. pDirectoryEntry = HashBucketI;
  838. while (pDirectoryEntry != 0) {
  839. ULONG64 Object=0, Next=0;
  840. if (CheckControlC()) {
  841. return FALSE;
  842. }
  843. if ( GetFieldValue(pDirectoryEntry, "nt!_OBJECT_DIRECTORY_ENTRY", "Object", Object)) {
  844. // dprintf( "Unable to read directory entry at %x\n", pDirectoryEntry );
  845. break;
  846. }
  847. if (!GetObjectInfo(Object, &ObjectInfo)) {
  848. // dprintf( " - %s\n", ObjectInfo.Message );
  849. } else {
  850. foundMatch = TRUE;
  851. for (j = 0;
  852. (Path[j] != '\0') && (ObjectInfo.ObjectName[j] != L'\0');
  853. j++) {
  854. if (tolower(Path[j]) !=
  855. towlower(ObjectInfo.ObjectName[j])) {
  856. foundMatch = FALSE;
  857. break;
  858. }
  859. }
  860. if (foundMatch) {
  861. if ((Path[j] == '\0') &&
  862. (ObjectInfo.ObjectName[j] == L'\0')) {
  863. return FindObjectByName(nextPath, Object);
  864. }
  865. }
  866. }
  867. GetFieldValue(pDirectoryEntry, "nt!_OBJECT_DIRECTORY_ENTRY", "ChainLink", Next);
  868. pDirectoryEntry = Next;
  869. }
  870. }
  871. }
  872. return 0;
  873. }
  874. VOID
  875. DumpDirectoryObject(
  876. IN char *Pad,
  877. IN ULONG64 Object
  878. )
  879. {
  880. ULONG Result, i;
  881. ULONG64 pDirectoryObject = Object;
  882. ULONG64 pDirectoryEntry;
  883. ULONG64 HashBucketsAddress;
  884. ULONG HashBucketSz;
  885. ULONG HashOffset;
  886. OBJECT_INFO ObjectInfo;
  887. ULONG SymbolicLinkUsageCount=0;
  888. ULONG Indent64; // extra indent to aligning column headers for 64-bit addresses
  889. //
  890. // Get the address of hashbuckets array and size of the pointer to scan the array
  891. //
  892. if (GetFieldOffset("nt!_OBJECT_DIRECTORY", "HashBuckets", &HashOffset)) {
  893. dprintf("Cannot find _OBJECT_DIRECTORY type.\n");
  894. return ;
  895. }
  896. HashBucketsAddress = pDirectoryObject + HashOffset;
  897. HashBucketSz = IsPtr64() ? 8 : 4;
  898. Indent64 = IsPtr64() ? 8 : 0;
  899. GetFieldValue(pDirectoryObject, "nt!_OBJECT_DIRECTORY", "SymbolicLinkUsageCount", SymbolicLinkUsageCount);
  900. if (SymbolicLinkUsageCount != 0) {
  901. dprintf( "%s %u symbolic links snapped through this directory\n",
  902. Pad,
  903. SymbolicLinkUsageCount
  904. );
  905. }
  906. dprintf("\n");
  907. dprintf("%s Hash Address%*s Type Name\n", Pad, Indent64, "");
  908. dprintf("%s ---- -------%*s ---- ----\n", Pad, Indent64, "");
  909. for (i=0; i<NUMBER_HASH_BUCKETS; i++) {
  910. ULONG64 HashBucketI = 0;
  911. ReadPointer(HashBucketsAddress + i*HashBucketSz, &HashBucketI);
  912. if (HashBucketI != 0) {
  913. dprintf( "%s %02u ",
  914. Pad,
  915. i
  916. );
  917. pDirectoryEntry = HashBucketI;
  918. while (pDirectoryEntry != 0) {
  919. ULONG64 ObjectE=0, Next=0;
  920. if (GetFieldValue(pDirectoryEntry, "nt!_OBJECT_DIRECTORY_ENTRY", "Object", ObjectE)) {
  921. dprintf( "Unable to read directory entry at %p\n", pDirectoryEntry );
  922. break;
  923. }
  924. if (pDirectoryEntry != HashBucketI) {
  925. dprintf( "%s ", Pad );
  926. }
  927. dprintf( "%p", ObjectE );
  928. if (!GetObjectInfo( ObjectE, &ObjectInfo)) {
  929. dprintf( " - %s\n", ObjectInfo.Message );
  930. } else {
  931. //
  932. // !object \ObjectTypes shows WindowStation is longest
  933. // object type name with 13 chars
  934. //
  935. dprintf( " %-13ws %ws\n", ObjectInfo.TypeName, ObjectInfo.ObjectName );
  936. }
  937. GetFieldValue(pDirectoryEntry, "nt!_OBJECT_DIRECTORY_ENTRY", "ChainLink", Next);
  938. pDirectoryEntry = Next;
  939. }
  940. }
  941. }
  942. }
  943. VOID
  944. DumpSymbolicLinkObject(
  945. IN char *Pad,
  946. IN ULONG64 Object,
  947. OPTIONAL OUT PCHAR TargetString,
  948. IN ULONG TargetStringSize
  949. )
  950. {
  951. ULONG Result, i;
  952. ULONG64 pSymbolicLinkObject = Object;
  953. PWSTR s, FreeBuffer;
  954. ULONG Length;
  955. ULONG64 TargetBuffer=0, DosDeviceDriveIndex=0, LinkTargetObject=0;
  956. if (GetFieldValue(pSymbolicLinkObject, "nt!_OBJECT_SYMBOLIC_LINK", "LinkTarget.Length", Length)) {
  957. dprintf( "Unable to read symbolic link object at %p\n", Object );
  958. return;
  959. }
  960. if (Length > 0x1000) // sanity check
  961. {
  962. Length = 0x1000;
  963. }
  964. GetFieldValue(pSymbolicLinkObject, "nt!_OBJECT_SYMBOLIC_LINK", "LinkTarget.Buffer", TargetBuffer);
  965. GetFieldValue(pSymbolicLinkObject, "nt!_OBJECT_SYMBOLIC_LINK", "DosDeviceDriveIndex" , DosDeviceDriveIndex);
  966. GetFieldValue(pSymbolicLinkObject, "nt!_OBJECT_SYMBOLIC_LINK", "LinkTargetObject", LinkTargetObject);
  967. FreeBuffer = s = HeapAlloc( GetProcessHeap(),
  968. HEAP_ZERO_MEMORY,
  969. Length + sizeof( UNICODE_NULL )
  970. );
  971. if (s == NULL ||
  972. !ReadMemory( TargetBuffer,
  973. s,
  974. Length,
  975. &Result
  976. )
  977. ) {
  978. s = L"*** target string unavailable ***";
  979. }
  980. dprintf( "%s Target String is '%ws'\n",
  981. Pad,
  982. s
  983. );
  984. if (TargetString && (TargetStringSize > wcslen(s))) {
  985. sprintf(TargetString, "%ws", s);
  986. }
  987. if (FreeBuffer != NULL) {
  988. HeapFree( GetProcessHeap(), 0, FreeBuffer );
  989. }
  990. if (DosDeviceDriveIndex != 0) {
  991. dprintf( "%s Drive Letter Index is %I64u (%c:)\n",
  992. Pad,
  993. DosDeviceDriveIndex,
  994. 'A' + DosDeviceDriveIndex - 1
  995. );
  996. }
  997. if (LinkTargetObject != 0) {
  998. GetFieldValue(pSymbolicLinkObject, "_OBJECT_SYMBOLIC_LINK", "LinkTargetRemaining.Length", Length);
  999. if (Length > 0x1000) // sanity check
  1000. {
  1001. Length = 0x1000;
  1002. }
  1003. FreeBuffer = s = HeapAlloc( GetProcessHeap(),
  1004. HEAP_ZERO_MEMORY,
  1005. Length + sizeof( UNICODE_NULL )
  1006. );
  1007. GetFieldValue(pSymbolicLinkObject, "_OBJECT_SYMBOLIC_LINK", "LinkTargetRemaining.Buffer", TargetBuffer);
  1008. if (s == NULL ||
  1009. !ReadMemory( TargetBuffer,
  1010. s,
  1011. Length,
  1012. &Result
  1013. )
  1014. ) {
  1015. s = L"*** remaining name unavailable ***";
  1016. }
  1017. dprintf( "%s Snapped to Object %p '%ws'\n",
  1018. Pad,
  1019. LinkTargetObject,
  1020. s
  1021. );
  1022. if (FreeBuffer != NULL) {
  1023. HeapFree( GetProcessHeap(), 0, FreeBuffer );
  1024. }
  1025. }
  1026. return;
  1027. }
  1028. BOOLEAN
  1029. DumpObject(
  1030. IN char *Pad,
  1031. IN ULONG64 Object,
  1032. IN ULONG Flags
  1033. )
  1034. {
  1035. OBJECT_INFO ObjectInfo;
  1036. if (!GetObjectInfo(Object, &ObjectInfo)) {
  1037. dprintf( "%s\n", ObjectInfo.Message );
  1038. return FALSE;
  1039. }
  1040. dprintf( "Object: %08p Type: (%08p) %ws\n",
  1041. Object,
  1042. ObjectInfo.ObjectHeader.Type,
  1043. ObjectInfo.TypeName
  1044. );
  1045. dprintf( " ObjectHeader: %08p\n",
  1046. ObjectInfo.pObjectHeader
  1047. );
  1048. if (!(Flags & 0x1)) {
  1049. return TRUE;
  1050. }
  1051. dprintf( "%s HandleCount: %u PointerCount: %u\n",
  1052. Pad,
  1053. ObjectInfo.ObjectHeader.HandleCount,
  1054. ObjectInfo.ObjectHeader.PointerCount
  1055. );
  1056. if (ObjectInfo.ObjectName[ 0 ] != UNICODE_NULL ||
  1057. ObjectInfo.NameInfo.Directory != 0
  1058. ) {
  1059. dprintf( "%s Directory Object: %08p Name: %ws",
  1060. Pad,
  1061. ObjectInfo.NameInfo.Directory,
  1062. ObjectInfo.ObjectName
  1063. );
  1064. if (ObjectInfo.FileSystemName[0] != UNICODE_NULL) {
  1065. dprintf( " {%ws}\n", ObjectInfo.FileSystemName );
  1066. } else {
  1067. dprintf( "\n" );
  1068. }
  1069. }
  1070. if ((Flags & 0x8)) {
  1071. if (!wcscmp( ObjectInfo.TypeName, L"Directory" )) {
  1072. DumpDirectoryObject( Pad, Object );
  1073. } else if (!wcscmp( ObjectInfo.TypeName, L"SymbolicLink" )) {
  1074. DumpSymbolicLinkObject( Pad, Object, NULL, 0 );
  1075. }
  1076. }
  1077. return TRUE;
  1078. }
  1079. PWSTR
  1080. GetObjectName(
  1081. ULONG64 Object
  1082. )
  1083. {
  1084. ULONG Result;
  1085. ULONG64 pObjectHeader;
  1086. UNICODE_STRING64 ObjectName={0};
  1087. ULONG64 pNameInfo;
  1088. ULONG NameInfoOffset=0;
  1089. ULONG64 Type=0;
  1090. ULONG BodyOffset;
  1091. if (GetFieldOffset("nt!_OBJECT_HEADER", "Body", &BodyOffset)) {
  1092. return NULL;
  1093. }
  1094. pObjectHeader = Object - BodyOffset;
  1095. if (GetFieldValue(pObjectHeader, "nt!_OBJECT_HEADER", "Type", Type) ||
  1096. GetFieldValue(pObjectHeader, "nt!_OBJECT_HEADER", "NameInfoOffset", NameInfoOffset)) {
  1097. if (Object >= HighestUserAddress && (ULONG)Object < 0xF0000000) {
  1098. swprintf( ObjectNameBuffer, L"(%08I64lx: object is paged out)", UNEXTEND64(Object) );
  1099. return ObjectNameBuffer;
  1100. } else {
  1101. swprintf( ObjectNameBuffer, L"(%08I64lx: invalid object header)", UNEXTEND64(Object) );
  1102. return ObjectNameBuffer;
  1103. }
  1104. }
  1105. pNameInfo = NameInfoOffset ? (pObjectHeader - NameInfoOffset) : 0;
  1106. if (pNameInfo == 0) {
  1107. dprintf("NameInfoOffset not found for _OBJECT_HEADER at %p\n", pObjectHeader);
  1108. return NULL;
  1109. }
  1110. if (GetFieldValue(pNameInfo, "nt!_OBJECT_HEADER_NAME_INFO", "Name.Length", ObjectName.Length) ||
  1111. GetFieldValue(pNameInfo, "nt!_OBJECT_HEADER_NAME_INFO", "Name.Buffer", ObjectName.Buffer) ||
  1112. GetFieldValue(pNameInfo, "nt!_OBJECT_HEADER_NAME_INFO", "Name.MaximumLength", ObjectName.MaximumLength)) {
  1113. dprintf( "%08p: Unable to read object name info\n", pNameInfo );
  1114. return NULL;
  1115. }
  1116. if (ObjectName.Length == 0 || ObjectName.Buffer == 0) {
  1117. return NULL;
  1118. }
  1119. if (ObjectName.Length >= sizeof(ObjectNameBuffer) ) {
  1120. ObjectName.Length = sizeof(ObjectNameBuffer) - sizeof(WCHAR);
  1121. }
  1122. if ( !ReadMemory( ObjectName.Buffer,
  1123. ObjectNameBuffer,
  1124. ObjectName.Length,
  1125. &Result) ) {
  1126. swprintf( ObjectNameBuffer, L"(%08lx: name not accessable)", ObjectName.Buffer );
  1127. } else {
  1128. ObjectNameBuffer[ ( ObjectName.Length / sizeof( WCHAR ) ) ] = UNICODE_NULL;
  1129. }
  1130. return ObjectNameBuffer;
  1131. }
  1132. BOOLEAN
  1133. WalkObjectsByType(
  1134. IN PUCHAR ObjectTypeName,
  1135. IN ENUM_TYPE_ROUTINE EnumRoutine,
  1136. IN PVOID Parameter
  1137. )
  1138. {
  1139. ULONG Result;
  1140. LIST_ENTRY64 ListEntry;
  1141. ULONG64 Head, Next;
  1142. ULONG64 pObjectHeader;
  1143. ULONG64 pObjectType;
  1144. BOOLEAN WalkingBackwards;
  1145. ULONG64 pCreatorInfo;
  1146. ULONG TotalNumberOfObjects=0;
  1147. ULONG TypeListOffset=0;
  1148. ULONG CreatorTypeListOffset=0, CreatorTypeSizeHeader = 0;
  1149. ULONG64 Flink=0, TypeList_Flink=0, TypeList_Blink=0;
  1150. if (GetFieldOffset("nt!_OBJECT_TYPE", "TypeList", &TypeListOffset)) {
  1151. return FALSE;
  1152. }
  1153. pObjectType = FindObjectType( ObjectTypeName );
  1154. if (pObjectType == 0) {
  1155. dprintf( "*** unable to find '%s' object type.\n", ObjectTypeName );
  1156. return FALSE;
  1157. }
  1158. if (GetFieldValue(pObjectType, "nt!_OBJECT_TYPE", "TypeList.Flink", Flink)) {
  1159. dprintf( "%08lx: Unable to read object type\n", pObjectType );
  1160. return FALSE;
  1161. }
  1162. GetFieldValue(pObjectType, "nt!_OBJECT_TYPE", "TypeList.Blink", TypeList_Blink);
  1163. GetFieldValue(pObjectType, "nt!_OBJECT_TYPE", "TypeList.Flink", TypeList_Flink);
  1164. GetFieldValue(pObjectType, "nt!_OBJECT_TYPE", "TotalNumberOfObjects", TotalNumberOfObjects);
  1165. dprintf( "Scanning %u objects of type '%s'\n", TotalNumberOfObjects & 0x00FFFFFF, ObjectTypeName );
  1166. Head = pObjectType + TypeListOffset;
  1167. ListEntry.Flink = TypeList_Flink;
  1168. ListEntry.Blink = TypeList_Blink;
  1169. Next = Flink;
  1170. WalkingBackwards = FALSE;
  1171. if ((TotalNumberOfObjects & 0x00FFFFFF) != 0 && Next == Head) {
  1172. dprintf( "*** objects of the same type are only linked together if the %x flag is set in NtGlobalFlags\n",
  1173. FLG_MAINTAIN_OBJECT_TYPELIST
  1174. );
  1175. return TRUE;
  1176. }
  1177. if (GetFieldOffset("nt!_OBJECT_HEADER_CREATOR_INFO", "TypeList", &CreatorTypeListOffset)) {
  1178. return FALSE;
  1179. }
  1180. CreatorTypeSizeHeader = GetTypeSize("nt!_OBJECT_HEADER_CREATOR_INFO");
  1181. while (Next != Head) {
  1182. if ( GetFieldValue(Next, "nt!_LIST_ENTRY", "Blink", ListEntry.Blink) ||
  1183. GetFieldValue(Next, "nt!_LIST_ENTRY", "Flink", ListEntry.Flink)) {
  1184. if (WalkingBackwards) {
  1185. dprintf( "%08p: Unable to read object type list\n", Next );
  1186. return FALSE;
  1187. }
  1188. //
  1189. // Switch to walk in reverse direction
  1190. //
  1191. WalkingBackwards = TRUE ;
  1192. Next = TypeList_Blink;
  1193. dprintf( "%08p: Switch to walking backwards\n", Next );
  1194. continue;
  1195. }
  1196. pCreatorInfo = Next - CreatorTypeListOffset; // CONTAINING_RECORD( Next, OBJECT_HEADER_CREATOR_INFO, TypeList );
  1197. pObjectHeader = pCreatorInfo + CreatorTypeSizeHeader;
  1198. if ( GetFieldValue( pObjectHeader,"nt!OBJECT_HEADER","Flags", Result) ) {
  1199. dprintf( "%08p: Not a valid object header\n", pObjectHeader );
  1200. return FALSE;
  1201. }
  1202. if ( !(Result & OB_FLAG_CREATOR_INFO) )
  1203. {
  1204. dprintf("WARNING: Object header %p flag (%hx) does not have OB_FLAG_CREATOR_INFO (%hx) set\n",
  1205. pObjectHeader,
  1206. Result,
  1207. OB_FLAG_CREATOR_INFO);
  1208. return FALSE;
  1209. }
  1210. //
  1211. // Not reading the objectheader as before, just pass the address
  1212. //
  1213. if (!(EnumRoutine)( pObjectHeader, Parameter )) {
  1214. return FALSE;
  1215. }
  1216. if ( CheckControlC() ) {
  1217. return FALSE;
  1218. }
  1219. if (WalkingBackwards) {
  1220. Next = ListEntry.Blink;
  1221. } else {
  1222. Next = ListEntry.Flink;
  1223. }
  1224. }
  1225. return TRUE;
  1226. }
  1227. BOOLEAN
  1228. CaptureObjectName(
  1229. IN ULONG64 pObjectHeader,
  1230. IN PWSTR Buffer,
  1231. IN ULONG BufferSize
  1232. )
  1233. {
  1234. ULONG Result;
  1235. PWSTR s1 = L"*** unable to get object name";
  1236. PWSTR s = &Buffer[ BufferSize ];
  1237. ULONG n = BufferSize * sizeof( WCHAR );
  1238. ULONG64 pNameInfo;
  1239. ULONG64 pObjectDirectoryHeader = 0;
  1240. ULONG64 ObjectDirectory;
  1241. UNICODE_STRING64 Name;
  1242. ULONG BodyOffset;
  1243. Buffer[ 0 ] = UNICODE_NULL;
  1244. KD_OBJECT_HEADER_TO_NAME_INFO( pObjectHeader, &pNameInfo );
  1245. if (pNameInfo == 0) {
  1246. return TRUE;
  1247. }
  1248. if ( GetFieldValue(pNameInfo, "nt!_OBJECT_HEADER_NAME_INFO", "Name.Buffer", Name.Buffer)) {
  1249. wcscpy( Buffer, s1 );
  1250. return FALSE;
  1251. }
  1252. GetFieldValue(pNameInfo, "_OBJECT_HEADER_NAME_INFO", "Name.Length", Name.Length);
  1253. GetFieldValue(pNameInfo, "_OBJECT_HEADER_NAME_INFO", "Name.MaximumLength", Name.MaximumLength);
  1254. if (Name.Length == 0) {
  1255. return TRUE;
  1256. }
  1257. if (Name.Length > (ULONG64) (s - Buffer)) {
  1258. if (Name.Length > 1024) {
  1259. wsprintfW(Buffer, L"*** Bad object Name length for ObjHdr at %I64lx", UNEXTEND64(pObjectHeader));
  1260. return FALSE;
  1261. }
  1262. Name.Length = (USHORT) (ULONG64) (s - Buffer);
  1263. }
  1264. *--s = UNICODE_NULL;
  1265. s = (PWCH)((PCH)s - Name.Length);
  1266. if ( !ReadMemory( Name.Buffer,
  1267. s,
  1268. Name.Length,
  1269. &Result) ) {
  1270. wcscpy( Buffer, s1 );
  1271. return FALSE;
  1272. }
  1273. GetFieldValue(pNameInfo, "_OBJECT_HEADER_NAME_INFO", "Directory", ObjectDirectory);
  1274. while ((ObjectDirectory != ObpRootDirectoryObject) && (ObjectDirectory)) {
  1275. pObjectDirectoryHeader = KD_OBJECT_TO_OBJECT_HEADER(ObjectDirectory);
  1276. KD_OBJECT_HEADER_TO_NAME_INFO( pObjectDirectoryHeader, &pNameInfo );
  1277. if ( GetFieldValue(pNameInfo, "nt!_OBJECT_HEADER_NAME_INFO", "Name.Buffer", Name.Buffer)) {
  1278. wcscpy( Buffer, s1 );
  1279. return FALSE;
  1280. }
  1281. GetFieldValue(pNameInfo, "nt!_OBJECT_HEADER_NAME_INFO", "Name.Length", Name.Length);
  1282. GetFieldValue(pNameInfo, "nt!_OBJECT_HEADER_NAME_INFO", "Name.MaximumLength", Name.MaximumLength);
  1283. if (Name.Length > (ULONG64) (s - Buffer)) {
  1284. if (Name.Length > 1024) {
  1285. wsprintfW(Buffer, L"*** Bad object Name length for ObjHdr at %I64lx", UNEXTEND64(pObjectDirectoryHeader));
  1286. return FALSE;
  1287. }
  1288. Name.Length = (USHORT) (ULONG64) (s - Buffer);
  1289. }
  1290. *--s = OBJ_NAME_PATH_SEPARATOR;
  1291. s = (PWCH)((PCH)s - Name.Length);
  1292. if ( !ReadMemory( Name.Buffer,
  1293. s,
  1294. Name.Length,
  1295. &Result) ) {
  1296. wcscpy( Buffer, s1 );
  1297. return FALSE;
  1298. }
  1299. ObjectDirectory = 0;
  1300. GetFieldValue(pNameInfo, "nt!_OBJECT_HEADER_NAME_INFO", "Directory", ObjectDirectory);
  1301. if ( CheckControlC() ) {
  1302. return FALSE;
  1303. }
  1304. }
  1305. *--s = OBJ_NAME_PATH_SEPARATOR;
  1306. wcscpy( Buffer, s );
  1307. return TRUE;
  1308. }
  1309. /////////////////////////////////////////////////////////////
  1310. static BOOL
  1311. ReadStructFieldVerbose( ULONG64 AddrStructBase,
  1312. PCHAR StructTypeName,
  1313. PCHAR StructFieldName,
  1314. PVOID Buffer,
  1315. ULONG BufferSize )
  1316. {
  1317. ULONG FieldOffset;
  1318. ULONG ErrorCode;
  1319. BOOL Success;
  1320. Success = FALSE;
  1321. //
  1322. // Get the field offset
  1323. //
  1324. ErrorCode = GetFieldOffset (StructTypeName,
  1325. StructFieldName,
  1326. &FieldOffset );
  1327. if (ErrorCode == S_OK) {
  1328. //
  1329. // Read the data
  1330. //
  1331. Success = ReadMemory (AddrStructBase + FieldOffset,
  1332. Buffer,
  1333. BufferSize,
  1334. NULL );
  1335. if (Success != TRUE) {
  1336. dprintf ("ERROR: Cannot read structure field value at 0x%p, error %u\n",
  1337. AddrStructBase + FieldOffset,
  1338. ErrorCode );
  1339. }
  1340. }
  1341. else {
  1342. dprintf ("ERROR: Cannot get field offset of %s in %s, error %u\n",
  1343. StructFieldName,
  1344. StructTypeName,
  1345. ErrorCode );
  1346. }
  1347. return Success;
  1348. }
  1349. /////////////////////////////////////////////////////////////
  1350. static BOOL
  1351. ReadPtrStructFieldVerbose( ULONG64 AddrStructBase,
  1352. PCHAR StructTypeName,
  1353. PCHAR StructFieldName,
  1354. PULONG64 Buffer )
  1355. {
  1356. ULONG FieldOffset;
  1357. ULONG ErrorCode;
  1358. BOOL Success;
  1359. Success = FALSE;
  1360. //
  1361. // Get the field offset inside the structure
  1362. //
  1363. ErrorCode = GetFieldOffset (StructTypeName,
  1364. StructFieldName,
  1365. &FieldOffset );
  1366. if (ErrorCode == S_OK) {
  1367. //
  1368. // Read the data
  1369. //
  1370. ErrorCode = ReadPtr (AddrStructBase + FieldOffset,
  1371. Buffer );
  1372. if (ErrorCode != S_OK) {
  1373. dprintf ("ERROR: Cannot read structure field value at 0x%p, error %u\n",
  1374. AddrStructBase + FieldOffset,
  1375. ErrorCode );
  1376. }
  1377. else {
  1378. Success = TRUE;
  1379. }
  1380. }
  1381. else {
  1382. dprintf ("ERROR: Cannot get field offset of %s in structure %s, error %u\n",
  1383. StructFieldName,
  1384. StructTypeName,
  1385. ErrorCode );
  1386. }
  1387. return Success;
  1388. }
  1389. /////////////////////////////////////////////////////////////
  1390. static BOOL
  1391. DumpStackTrace (ULONG64 PointerAddress,
  1392. ULONG MaxStackTraceDepth,
  1393. ULONG PointerSize)
  1394. {
  1395. ULONG64 CodePointer;
  1396. ULONG64 Displacement;
  1397. ULONG StackTraceDepth;
  1398. ULONG ErrorCode;
  1399. BOOL Continue;
  1400. char Symbol[ 1024 ];
  1401. Continue = TRUE;
  1402. for (StackTraceDepth = 0; StackTraceDepth < MaxStackTraceDepth; StackTraceDepth += 1) {
  1403. if (CheckControlC()) {
  1404. Continue = FALSE;
  1405. goto Done;
  1406. }
  1407. ErrorCode = ReadPtr (PointerAddress,
  1408. &CodePointer );
  1409. if (ErrorCode != S_OK) {
  1410. dprintf ("ERROR: Cannot read address at 0x%p, error %u\n",
  1411. PointerAddress,
  1412. ErrorCode );
  1413. }
  1414. else {
  1415. if( CodePointer == 0 ) {
  1416. //
  1417. // End of stack trace
  1418. //
  1419. goto Done;
  1420. }
  1421. GetSymbol (CodePointer,
  1422. Symbol,
  1423. &Displacement);
  1424. dprintf ("0x%p: %s+0x%I64X\n",
  1425. CodePointer,
  1426. Symbol,
  1427. Displacement );
  1428. }
  1429. PointerAddress += PointerSize;
  1430. }
  1431. Done:
  1432. return Continue;
  1433. }
  1434. /////////////////////////////////////////////////////////////
  1435. static BOOL
  1436. DumpHandleTraceEntry (ULONG64 TraceDbEntry,
  1437. ULONG64 Handle,
  1438. ULONG64 NullHandleEntry,
  1439. ULONG StackTraceFieldOffset,
  1440. ULONG MaxStackTraceDepth,
  1441. ULONG PointerSize,
  1442. PULONG EntriesDisplayed)
  1443. {
  1444. ULONG64 EntryHandle;
  1445. ULONG Type;
  1446. BOOL Success;
  1447. BOOL Continue;
  1448. #ifndef HANDLE_TRACE_DB_OPEN
  1449. #define HANDLE_TRACE_DB_OPEN 1
  1450. #endif
  1451. #ifndef HANDLE_TRACE_DB_CLOSE
  1452. #define HANDLE_TRACE_DB_CLOSE 2
  1453. #endif
  1454. #ifndef HANDLE_TRACE_DB_BADREF
  1455. #define HANDLE_TRACE_DB_BADREF 3
  1456. #endif
  1457. Continue = TRUE;
  1458. //
  1459. // Read the handle of this entry
  1460. //
  1461. Success = ReadPtrStructFieldVerbose (TraceDbEntry,
  1462. "nt!_HANDLE_TRACE_DB_ENTRY",
  1463. "Handle",
  1464. &EntryHandle );
  1465. if (Success == FALSE) {
  1466. dprintf ("ERROR: Cannot read handle for trace database entry at 0x%p.\n",
  1467. TraceDbEntry );
  1468. goto Done;
  1469. }
  1470. //
  1471. // Read the operation type
  1472. //
  1473. Success = ReadStructFieldVerbose (TraceDbEntry,
  1474. "nt!_HANDLE_TRACE_DB_ENTRY",
  1475. "Type",
  1476. &Type,
  1477. sizeof( Type ) );
  1478. if (Success == FALSE) {
  1479. dprintf ("ERROR: Cannot read operation type for trace database entry at 0x%p.\n",
  1480. TraceDbEntry );
  1481. goto Done;
  1482. }
  1483. if (EntryHandle == 0 && Type == 0 && TraceDbEntry != NullHandleEntry) {
  1484. //
  1485. // We are done parsing the database.
  1486. //
  1487. Continue = FALSE;
  1488. goto Done;
  1489. }
  1490. //
  1491. // Check if we need to dump this entry.
  1492. //
  1493. if (Handle == 0 || Handle == EntryHandle) {
  1494. *EntriesDisplayed += 1;
  1495. dprintf( "--------------------------------------\n"
  1496. "Handle 0x%I64X - ",
  1497. EntryHandle );
  1498. switch( Type ) {
  1499. case HANDLE_TRACE_DB_OPEN:
  1500. dprintf( "OPEN:\n" );
  1501. break;
  1502. case HANDLE_TRACE_DB_CLOSE:
  1503. dprintf( "CLOSE:\n" );
  1504. break;
  1505. case HANDLE_TRACE_DB_BADREF:
  1506. dprintf( "*** BAD REFERENCE ***:\n" );
  1507. break;
  1508. default:
  1509. dprintf( "ERROR: Invalid operation type for database entry at 0x%p\n",
  1510. TraceDbEntry );
  1511. Continue = FALSE;
  1512. goto Done;
  1513. }
  1514. Continue = DumpStackTrace (TraceDbEntry + StackTraceFieldOffset,
  1515. MaxStackTraceDepth,
  1516. PointerSize );
  1517. }
  1518. Done:
  1519. return Continue;
  1520. }
  1521. /////////////////////////////////////////////////////////////
  1522. static VOID
  1523. DumpHandleTraces (ULONG64 Process,
  1524. ULONG64 Handle)
  1525. {
  1526. ULONG64 ObjectTable;
  1527. ULONG64 DebugInfo;
  1528. ULONG64 TraceDbEntry;
  1529. ULONG64 FirstDbEntry;
  1530. ULONG SizeofDbEntry;
  1531. ULONG CurrentStackIndex;
  1532. ULONG SizeofDebugInfo;
  1533. ULONG TraceDbFieldOffset;
  1534. ULONG EntriesInTraceDb;
  1535. ULONG EntriesParsed;
  1536. ULONG StackTraceFieldOffset;
  1537. ULONG MaxStackTraceDepth;
  1538. ULONG PointerTypeSize;
  1539. ULONG ErrorCode;
  1540. ULONG EntriesDisplayed;
  1541. BOOL Success;
  1542. BOOL Continue;
  1543. EntriesParsed = 0;
  1544. EntriesDisplayed = 0;
  1545. //
  1546. // Get the pointer type size
  1547. //
  1548. PointerTypeSize = GetTypeSize ("nt!PVOID");
  1549. if (PointerTypeSize == 0) {
  1550. dprintf ("ERROR: Cannot get the pointer size.\n");
  1551. goto Done;
  1552. }
  1553. //
  1554. // Read the address of the object table structure
  1555. //
  1556. Success = ReadPtrStructFieldVerbose (Process,
  1557. "nt!_EPROCESS",
  1558. "ObjectTable",
  1559. &ObjectTable);
  1560. if (Success == FALSE) {
  1561. dprintf ("ERROR: Cannot read process object table address.\n");
  1562. goto Done;
  1563. }
  1564. else {
  1565. dprintf ("ObjectTable 0x%p\n\n",
  1566. ObjectTable );
  1567. }
  1568. //
  1569. // Read the DebugInfo from the handle table structure
  1570. //
  1571. Success = ReadPtrStructFieldVerbose (ObjectTable,
  1572. "nt!_HANDLE_TABLE",
  1573. "DebugInfo",
  1574. &DebugInfo );
  1575. if (Success == FALSE) {
  1576. dprintf( "ERROR: Cannot read object table debug information.\n" );
  1577. goto Done;
  1578. }
  1579. if (DebugInfo == 0) {
  1580. dprintf( "Trace information is not enabled for this process.\n" );
  1581. goto Done;
  1582. }
  1583. //
  1584. // Get the current index in the trace database
  1585. //
  1586. Success = ReadStructFieldVerbose (DebugInfo,
  1587. "nt!_HANDLE_TRACE_DEBUG_INFO",
  1588. "CurrentStackIndex",
  1589. &CurrentStackIndex,
  1590. sizeof( CurrentStackIndex ) );
  1591. if (Success == FALSE) {
  1592. dprintf( "ERROR: Cannot read the current index of the trace database.\n" );
  1593. goto Done;
  1594. }
  1595. //
  1596. // Get the size of the HANDLE_TRACE_DB_ENTRY type
  1597. //
  1598. SizeofDbEntry = GetTypeSize ("nt!HANDLE_TRACE_DB_ENTRY");
  1599. if (SizeofDbEntry == 0) {
  1600. dprintf ("Cannot get the size of the trace database entry structure\n");
  1601. goto Done;
  1602. }
  1603. //
  1604. // Get the max number of entries in the StackTrace array inside HANDLE_TRACE_DB_ENTRY
  1605. //
  1606. ErrorCode = GetFieldOffset ("nt!_HANDLE_TRACE_DB_ENTRY",
  1607. "StackTrace",
  1608. &StackTraceFieldOffset);
  1609. if (ErrorCode != S_OK) {
  1610. dprintf ("Cannot get StackTrace field offset.\n");
  1611. goto Done;
  1612. }
  1613. MaxStackTraceDepth = (SizeofDbEntry - StackTraceFieldOffset) / PointerTypeSize;
  1614. //
  1615. // Get the size of the HANDLE_TRACE_DEBUG_INFO type
  1616. //
  1617. SizeofDebugInfo = GetTypeSize ("nt!HANDLE_TRACE_DEBUG_INFO");
  1618. if (SizeofDebugInfo == 0) {
  1619. dprintf ("ERROR: Cannot get the size of the debug info structure\n");
  1620. goto Done;
  1621. }
  1622. //
  1623. // Get the offset of TraceDb inside the _HANDLE_TRACE_DEBUG_INFO structure
  1624. //
  1625. ErrorCode = GetFieldOffset ("nt!_HANDLE_TRACE_DEBUG_INFO",
  1626. "TraceDb",
  1627. &TraceDbFieldOffset);
  1628. if (ErrorCode != S_OK) {
  1629. dprintf ("ERROR: Cannot get TraceDb field offset.\n");
  1630. goto Done;
  1631. }
  1632. //
  1633. // Compute the number of entries in the TraceDb array
  1634. //
  1635. EntriesInTraceDb = (SizeofDebugInfo - TraceDbFieldOffset) / SizeofDbEntry;
  1636. if (EntriesInTraceDb == 0) {
  1637. dprintf ("ERROR: zero entries in the trace database.\n");
  1638. goto Done;
  1639. }
  1640. CurrentStackIndex = CurrentStackIndex % EntriesInTraceDb;
  1641. //
  1642. // Compute a pointer to the current stack trace database entry
  1643. //
  1644. FirstDbEntry = DebugInfo + TraceDbFieldOffset;
  1645. TraceDbEntry = FirstDbEntry + CurrentStackIndex * SizeofDbEntry;
  1646. //
  1647. // Dump all the valid entries in the array
  1648. //
  1649. EntriesDisplayed = 0;
  1650. for (EntriesParsed = 0; EntriesParsed < EntriesInTraceDb; EntriesParsed += 1) {
  1651. if (CheckControlC()) {
  1652. goto Done;
  1653. }
  1654. //
  1655. // The first entry in the array is never used so skip it
  1656. //
  1657. if (EntriesParsed != CurrentStackIndex) {
  1658. Continue = DumpHandleTraceEntry( TraceDbEntry,
  1659. Handle,
  1660. FirstDbEntry,
  1661. StackTraceFieldOffset,
  1662. MaxStackTraceDepth,
  1663. PointerTypeSize,
  1664. &EntriesDisplayed );
  1665. if (Continue == FALSE) {
  1666. //
  1667. // This current entry is free or the user pressed Ctrl-C
  1668. // so we don't have any entries left to dump.
  1669. //
  1670. EntriesParsed += 1;
  1671. break;
  1672. }
  1673. //
  1674. // Go backward
  1675. //
  1676. TraceDbEntry -= SizeofDbEntry;
  1677. }
  1678. else {
  1679. //
  1680. // We should be at the beginning of the array
  1681. //
  1682. if( TraceDbEntry != FirstDbEntry ) {
  1683. dprintf ("ERROR: 0x%p should be the beginning of the traces array 0x%p\n",
  1684. TraceDbEntry,
  1685. FirstDbEntry);
  1686. goto Done;
  1687. }
  1688. //
  1689. // Start over again with the last entry in the array
  1690. //
  1691. TraceDbEntry = DebugInfo + TraceDbFieldOffset + ( EntriesInTraceDb - 1 ) * SizeofDbEntry;
  1692. }
  1693. }
  1694. Done:
  1695. dprintf ("\n--------------------------------------\n"
  1696. "Parsed 0x%X stack traces.\n"
  1697. "Dumped 0x%X stack traces.\n",
  1698. EntriesParsed,
  1699. EntriesDisplayed);
  1700. NOTHING;
  1701. }
  1702. /////////////////////////////////////////////////////////////
  1703. DECLARE_API( htrace )
  1704. /*++
  1705. Routine Description:
  1706. Dump the trace information for a handle
  1707. Arguments:
  1708. args - [process] [handle]
  1709. Return Value:
  1710. None
  1711. --*/
  1712. {
  1713. ULONG64 Handle;
  1714. ULONG64 Process;
  1715. ULONG CurrentProcessor;
  1716. //
  1717. // Did the user ask for help?
  1718. //
  1719. if(strcmp( args, "-?" ) == 0 ||
  1720. strcmp( args, "?" ) == 0 ||
  1721. strcmp( args, "-h" ) == 0) {
  1722. dprintf( "\n!htrace [ handle [process] ] - dump handle tracing information.\n" );
  1723. goto Done;
  1724. }
  1725. Handle = 0;
  1726. Process = 0;
  1727. //
  1728. // Get the current processor number
  1729. //
  1730. if (!GetCurrentProcessor(Client, &CurrentProcessor, NULL)) {
  1731. CurrentProcessor = 0;
  1732. }
  1733. //
  1734. // Did the user specify a process and a handle?
  1735. //
  1736. GetExpressionEx(args, &Handle, &args);
  1737. if (args && *args)
  1738. {
  1739. GetExpressionEx(args, &Process, &args);
  1740. }
  1741. if (Process == 0) {
  1742. GetCurrentProcessAddr( CurrentProcessor, 0, &Process );
  1743. if (Process == 0) {
  1744. dprintf ("Cannot get current process address\n");
  1745. goto Done;
  1746. }
  1747. else {
  1748. dprintf( "Process 0x%p\n",
  1749. Process );
  1750. }
  1751. }
  1752. else {
  1753. dprintf ("Process 0x%p\n",
  1754. Process );
  1755. }
  1756. DumpHandleTraces (Process,
  1757. Handle);
  1758. Done:
  1759. return S_OK;
  1760. }
  1761. DECLARE_API( driveinfo )
  1762. {
  1763. CHAR VolumeName[100];
  1764. CHAR ObjectName[100];
  1765. ULONG i=0;
  1766. ULONG64 Object;
  1767. CHAR targetVolume[100]={0};
  1768. ULONG64 DevObjVPB;
  1769. ULONG64 VpbDevice;
  1770. ULONG64 DriverObject;
  1771. ULONG64 DrvNameAddr;
  1772. OBJECT_INFO ObjectInfo;
  1773. WCHAR FileSystem[100]={0};
  1774. PWSTR FsType;
  1775. ULONG NameLen;
  1776. ULONG result;
  1777. while (*args == ' ') ++args;
  1778. while (*args && *args != ' ' && i < sizeof(VolumeName)) {
  1779. VolumeName[i++] = *args++;
  1780. }
  1781. if (!i) {
  1782. dprintf("Usage : !driveinfo <drive-name>[:]\n");
  1783. return E_INVALIDARG;
  1784. }
  1785. if (VolumeName[i-1] == ':') {
  1786. --i;
  1787. }
  1788. VolumeName[i]=0;
  1789. // Build Object name
  1790. strcpy(ObjectName, "\\global\?\?\\");
  1791. if ((StringCchCat(ObjectName, sizeof(ObjectName), VolumeName) != S_OK) ||
  1792. (StringCchCat(ObjectName, sizeof(ObjectName), ":") != S_OK))
  1793. {
  1794. Object = 0;
  1795. } else
  1796. {
  1797. // GetObject info
  1798. Object = FindObjectByName((PUCHAR) ObjectName, 0);
  1799. }
  1800. if (!Object) {
  1801. dprintf("Drive object not found for %s\n", ObjectName);
  1802. return E_FAIL;
  1803. }
  1804. dprintf("Drive %s:, DriveObject %p\n", VolumeName, Object);
  1805. if (!GetObjectInfo(Object, &ObjectInfo)) {
  1806. dprintf( "%s\n", ObjectInfo.Message );
  1807. return E_FAIL;
  1808. }
  1809. if (ObjectInfo.ObjectName[ 0 ] != UNICODE_NULL ||
  1810. ObjectInfo.NameInfo.Directory != 0
  1811. ) {
  1812. dprintf( " Directory Object: %08p Name: %ws",
  1813. ObjectInfo.NameInfo.Directory,
  1814. ObjectInfo.ObjectName
  1815. );
  1816. if (ObjectInfo.FileSystemName[0] != UNICODE_NULL) {
  1817. dprintf( " {%ws}\n", ObjectInfo.FileSystemName );
  1818. } else {
  1819. dprintf( "\n" );
  1820. }
  1821. }
  1822. if (!wcscmp( ObjectInfo.TypeName, L"SymbolicLink" )) {
  1823. DumpSymbolicLinkObject( " ", Object, targetVolume, sizeof(targetVolume) );
  1824. }
  1825. // devobj for volume
  1826. Object = FindObjectByName((PUCHAR) targetVolume, 0);
  1827. if (!Object) {
  1828. dprintf("Object not found for %s\n", targetVolume);
  1829. return E_FAIL;
  1830. }
  1831. dprintf(" Volume DevObj: %p\n", Object);
  1832. // Now get the vpb (volume parameter block) for devobj
  1833. if (GetFieldValue(Object, "nt!_DEVICE_OBJECT", "Vpb", DevObjVPB)) {
  1834. dprintf("Cannot get nt!_DEVICE_OBJECT.Vpb @ %p\n", DevObjVPB);
  1835. return E_FAIL;
  1836. }
  1837. // Now find device object of VPB
  1838. if (GetFieldValue(DevObjVPB, "nt!_VPB", "DeviceObject", VpbDevice)) {
  1839. dprintf("Cannot get nt!_VPB.DeviceObject @ %p\n", VpbDevice);
  1840. return E_FAIL;
  1841. }
  1842. dprintf(" Vpb: %p DeviceObject: %p\n", DevObjVPB, VpbDevice);
  1843. // Get fielsystem for VPB Device
  1844. if (GetFieldValue(VpbDevice, "nt!_DEVICE_OBJECT", "DriverObject", DriverObject)) {
  1845. dprintf("Error in getting _DEVICE_OBJECT.DriverObject @ %p\n", VpbDevice);
  1846. return E_FAIL;
  1847. }
  1848. if (GetFieldValue(DriverObject, "nt!_DRIVER_OBJECT", "DriverName.MaximumLength", NameLen)) {
  1849. dprintf("Cannot get driver name for %p\n", DriverObject);
  1850. return E_FAIL;
  1851. }
  1852. GetFieldValue(DriverObject, "nt!_DRIVER_OBJECT", "DriverName.Buffer", DrvNameAddr);
  1853. if (NameLen >= sizeof(FileSystem)/sizeof(WCHAR)) {
  1854. NameLen = sizeof(FileSystem)/sizeof(WCHAR)-1;
  1855. }
  1856. if (!ReadMemory( DrvNameAddr,FileSystem,NameLen,&result)) {
  1857. dprintf("Filesystem driver name paged out");
  1858. return E_FAIL;
  1859. }
  1860. dprintf(" FileSystem: %ws\n", FileSystem);
  1861. FsType = FileSystem + wcslen(L"\\FileSystem")+1;
  1862. if (!wcscmp(FsType, L"Fastfat")) {
  1863. ULONG NumberOfClusters, NumberOfFreeClusters, LogOfBytesPerSector,
  1864. LogOfBytesPerCluster, FatIndexBitSize;
  1865. ULONG64 ClusterSize;
  1866. // Its a FAT system
  1867. if (GetFieldValue(VpbDevice,
  1868. "fastfat!VOLUME_DEVICE_OBJECT",
  1869. "Vcb.AllocationSupport.NumberOfClusters",
  1870. NumberOfClusters)) {
  1871. dprintf("Cannot get fastfat!VOLUME_DEVICE_OBJECT.Vcb @ %p\n", VpbDevice);
  1872. return E_FAIL;
  1873. }
  1874. InitTypeRead(VpbDevice, fastfat!VOLUME_DEVICE_OBJECT);
  1875. NumberOfFreeClusters = (ULONG) ReadField(Vcb.AllocationSupport.NumberOfFreeClusters);
  1876. LogOfBytesPerSector = (ULONG) ReadField(Vcb.AllocationSupport.LogOfBytesPerSector);
  1877. LogOfBytesPerCluster = (ULONG) ReadField(Vcb.AllocationSupport.LogOfBytesPerCluster);
  1878. FatIndexBitSize = (ULONG) ReadField(Vcb.AllocationSupport.FatIndexBitSize);
  1879. ClusterSize = (ULONG64) 1 << LogOfBytesPerCluster;
  1880. dprintf(" Volume has 0x%lx (free) / 0x%lx (total) clusters of size 0x%I64lx\n",
  1881. NumberOfFreeClusters, NumberOfClusters, ClusterSize);
  1882. #define _MB( Bytes ) ((double)(Bytes)/(((ULONG64)1) << 20))
  1883. dprintf(" %I64g of %I64g MB free\n",
  1884. _MB(NumberOfFreeClusters*ClusterSize), _MB(NumberOfClusters*ClusterSize));
  1885. } else if (!wcscmp(FsType, L"Ntfs")) {
  1886. // Ntfs filesystem
  1887. ULONG64 TotalClusters, FreeClusters, BytesPerCluster;
  1888. if (GetFieldValue(VpbDevice,
  1889. "ntfs!VOLUME_DEVICE_OBJECT",
  1890. "Vcb.TotalClusters",
  1891. TotalClusters)) {
  1892. dprintf("Cannot get ntfs!VOLUME_DEVICE_OBJECT.Vcb @ %p\n", VpbDevice);
  1893. return E_FAIL;
  1894. }
  1895. InitTypeRead(VpbDevice, ntfs!VOLUME_DEVICE_OBJECT);
  1896. FreeClusters = ReadField(Vcb.FreeClusters);
  1897. BytesPerCluster = ReadField(Vcb.BytesPerCluster);
  1898. dprintf(" Volume has 0x%I64lx (free) / 0x%I64lx (total) clusters of size 0x%I64lx\n",
  1899. FreeClusters, TotalClusters, BytesPerCluster);
  1900. dprintf(" %I64g of %I64g MB free\n",
  1901. _MB(FreeClusters*BytesPerCluster), _MB(TotalClusters*BytesPerCluster));
  1902. }
  1903. return S_OK;
  1904. }