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.

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