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.

776 lines
22 KiB

  1. /*++
  2. Copyright (c) 1992-2000 Microsoft Corporation
  3. Module Name:
  4. handle.c
  5. Abstract:
  6. WinDbg Extension Api
  7. Revision History:
  8. --*/
  9. #include "precomp.h"
  10. #pragma hdrstop
  11. BOOL
  12. DumpHandles (
  13. IN ULONG64 RealProcessBase,
  14. IN ULONG64 HandleToDump,
  15. IN ULONG64 pObjectType,
  16. IN ULONG Flags
  17. );
  18. BOOLEAN
  19. DumpHandle(
  20. IN ULONG64 pHandleTableEntry,
  21. IN ULONG64 Handle,
  22. IN ULONG64 pObjectType,
  23. IN ULONG Flags
  24. );
  25. DECLARE_API( handle )
  26. /*++
  27. Routine Description:
  28. Dump the active handles
  29. Arguments:
  30. args - [handle-to-dump [flags [process [TypeName]]]]
  31. if handle-to-dump is 0 dump all
  32. Return Value:
  33. None
  34. --*/
  35. {
  36. ULONG64 ProcessToDump;
  37. ULONG64 HandleToDump;
  38. ULONG Flags;
  39. ULONG Result;
  40. ULONG nArgs;
  41. ULONG64 Next;
  42. ULONG64 ProcessHead;
  43. ULONG64 Process;
  44. char TypeName[ MAX_PATH ];
  45. ULONG64 pObjectType;
  46. ULONG64 UserProbeAddress;
  47. ULONG ActiveProcessLinksOffset=0;
  48. ULONG64 UniqueProcessId=0, ActiveProcessLinks_Flink=0;
  49. FIELD_INFO procLink[] = {
  50. {"ActiveProcessLinks", "", 0, DBG_DUMP_FIELD_RETURN_ADDRESS, 0, NULL},
  51. {"UniqueProcessId", "", 0, DBG_DUMP_FIELD_COPY_FIELD_DATA, 0, (PVOID) &UniqueProcessId},
  52. {"ActiveProcessLinks.Flink","", 0, DBG_DUMP_FIELD_COPY_FIELD_DATA, 0, (PVOID) &ActiveProcessLinks_Flink},
  53. };
  54. SYM_DUMP_PARAM EProc = {
  55. sizeof (SYM_DUMP_PARAM), "nt!_EPROCESS", DBG_DUMP_NO_PRINT, 0,
  56. NULL, NULL, NULL, 3, &procLink[0],
  57. };
  58. ULONG dwProcessor=0;
  59. CHAR Addr1[100], Addr2[100];
  60. GetCurrentProcessor(Client, &dwProcessor, NULL);
  61. HandleToDump = 0;
  62. Flags = 0x3; //by default dump bodies and objects for in use entries
  63. ProcessToDump = -1;
  64. UserProbeAddress = GetNtDebuggerDataValue(MmUserProbeAddress);
  65. dprintf("processor number %d\n", dwProcessor);
  66. Addr1[0] = 0;
  67. Addr2[0] = 0;
  68. nArgs = 0;
  69. if (GetExpressionEx(args, &HandleToDump, &args)) {
  70. ULONG64 tmp;
  71. ++nArgs;
  72. if (GetExpressionEx(args, &tmp, &args)) {
  73. ULONG i;
  74. Flags = (ULONG) tmp;
  75. ++nArgs;
  76. while (args && (*args == ' ')) {
  77. ++args;
  78. }
  79. // Do not use GetExpressionEx since it will search for TypeName
  80. // in symbols
  81. i=0;
  82. while (*args && (*args != ' ')) {
  83. Addr1[i++] = *args++;
  84. }
  85. Addr1[i] = 0;
  86. if (Addr1[0]) {
  87. ProcessToDump = GetExpression(Addr1);
  88. ++nArgs;
  89. while (args && (*args == ' ')) {
  90. ++args;
  91. }
  92. strcpy(TypeName, args);
  93. if (TypeName[0]) ++nArgs;
  94. }
  95. }
  96. }
  97. if (ProcessToDump == -1) {
  98. GetCurrentProcessAddr( dwProcessor, 0, &ProcessToDump );
  99. if (ProcessToDump == 0) {
  100. dprintf("Unable to get current process pointer.\n");
  101. return E_INVALIDARG;
  102. }
  103. }
  104. pObjectType = 0;
  105. if (nArgs > 3 && FetchObjectManagerVariables(FALSE)) {
  106. pObjectType = FindObjectType( TypeName );
  107. }
  108. if (ProcessToDump == 0) {
  109. dprintf("**** NT ACTIVE PROCESS HANDLE DUMP ****\n");
  110. if (Flags == 0xFFFFFFFF) {
  111. Flags = 1;
  112. }
  113. }
  114. //
  115. // If a process id is specified, then search the active process list
  116. // for the specified process id.
  117. //
  118. if (ProcessToDump < UserProbeAddress) {
  119. ULONG64 List_Flink=0, List_Blink=0;
  120. FIELD_INFO listFields[] = {
  121. {"Flink", "", 0, DBG_DUMP_FIELD_COPY_FIELD_DATA, 0, (PVOID) &List_Flink},
  122. {"Blink", "", 0, DBG_DUMP_FIELD_COPY_FIELD_DATA, 0, (PVOID) &List_Blink},
  123. };
  124. SYM_DUMP_PARAM Lst = {
  125. sizeof (SYM_DUMP_PARAM), "nt!_LIST_ENTRY", DBG_DUMP_NO_PRINT,
  126. 0, NULL, NULL, NULL, 2, &listFields[0]
  127. };
  128. ProcessHead = GetNtDebuggerData( PsActiveProcessHead );
  129. if ( !ProcessHead ) {
  130. dprintf("Unable to get value of PsActiveProcessHead\n");
  131. return E_INVALIDARG;
  132. }
  133. Lst.addr = ProcessHead;
  134. if (Ioctl(IG_DUMP_SYMBOL_INFO, &Lst, Lst.size)) {
  135. dprintf("Unable to find _LIST_ENTRY type, ProcessHead: %08I64x\n", ProcessHead);
  136. return E_INVALIDARG;
  137. }
  138. if (ProcessToDump != 0) {
  139. dprintf("Searching for Process with Cid == %I64lx\n", ProcessToDump);
  140. }
  141. Next = List_Flink;
  142. if (Next == 0) {
  143. dprintf("PsActiveProcessHead is NULL!\n");
  144. return E_INVALIDARG;
  145. }
  146. } else {
  147. Next = 0;
  148. ProcessHead = 1;
  149. }
  150. if (pObjectType != 0) {
  151. dprintf("Searching for handles of type %s\n", TypeName);
  152. }
  153. if (GetFieldOffset("nt!_EPROCESS", "ActiveProcessLinks", &ActiveProcessLinksOffset)) {
  154. dprintf("Unable to find _EPROCESS type\n");
  155. return E_INVALIDARG;
  156. }
  157. while(Next != ProcessHead) {
  158. if ( CheckControlC() ) {
  159. return E_INVALIDARG;
  160. }
  161. if (Next != 0) {
  162. Process = Next - ActiveProcessLinksOffset;
  163. } else {
  164. Process = ProcessToDump;
  165. }
  166. EProc.addr = Process;
  167. if (Ioctl(IG_DUMP_SYMBOL_INFO, &EProc, EProc.size)) {
  168. dprintf("_EPROCESS Ioctl failed at %p\n",Process);
  169. return E_INVALIDARG;
  170. }
  171. if (ProcessToDump == 0 ||
  172. ProcessToDump < UserProbeAddress && ProcessToDump == UniqueProcessId ||
  173. ProcessToDump >= UserProbeAddress && ProcessToDump == Process
  174. ) {
  175. if (DumpProcess ("", Process, 0, NULL)) {
  176. if (!DumpHandles ( Process, HandleToDump, pObjectType, Flags)) {
  177. break;
  178. }
  179. } else {
  180. break;
  181. }
  182. }
  183. if (Next == 0) {
  184. break;
  185. }
  186. Next = ActiveProcessLinks_Flink;
  187. }
  188. return S_OK;
  189. }
  190. #define KERNEL_HANDLE_MASK 0x80000000
  191. //+---------------------------------------------------------------------------
  192. //
  193. // Function: DumpHandles
  194. //
  195. // Synopsis: Dump the handle table for the given process
  196. //
  197. // Arguments: [RealProcessBase] -- base address of the process
  198. // [HandleToDump] -- handle to look for - if 0 dump all
  199. // [pObjectType] -- object type to look for
  200. // [Flags] -- flags passed thru to DumpHandle
  201. // if 0x10 is set dump the kernel handle table
  202. //
  203. // Returns: TRUE if successful
  204. //
  205. // History: 1-12-1998 benl Created
  206. //
  207. // Notes: Each segment of table has 0xFF or 8 bits worth of entries
  208. // the handle number's lowest 2 bit are application defined
  209. // so the indexes are gotten from the 3 8 bits ranges after
  210. // the first 2 bits
  211. //
  212. //----------------------------------------------------------------------------
  213. BOOL
  214. DumpHandles (
  215. IN ULONG64 RealProcessBase,
  216. IN ULONG64 HandleToDump,
  217. IN ULONG64 pObjectType,
  218. IN ULONG Flags
  219. )
  220. {
  221. ULONG64 ObjectTable=0;
  222. ULONG ulRead;
  223. ULONG64 ulTopLevel;
  224. ULONG64 ulMidLevel;
  225. ULONG ulHandleNum = ((ULONG)(HandleToDump) >> 2);
  226. ULONG iIndex1;
  227. ULONG iIndex2;
  228. ULONG iIndex3;
  229. ULONG ptrSize, hTableEntrySize;
  230. ULONG64 tablePtr;
  231. ULONG64 HandleCount = 0;
  232. ULONG64 Table = 0;
  233. ULONG64 UniqueProcessId = 0;
  234. BOOL KernelHandle = FALSE, CidHandle = FALSE;
  235. ULONG LowLevelCounts = 256;
  236. ULONG MidLevelCounts = 256;
  237. ULONG HighLevelCounts = 256;
  238. ULONG TableLevel = 2;
  239. BOOLEAN NewStyle = FALSE;
  240. //
  241. // Typeinfo parsing structures
  242. //
  243. FIELD_INFO procFields[] = {
  244. {"ObjectTable", "", 0, DBG_DUMP_FIELD_COPY_FIELD_DATA, 0, (PVOID) &ObjectTable},
  245. };
  246. FIELD_INFO handleTblFields[] = {
  247. {"HandleCount", "", 0, DBG_DUMP_FIELD_COPY_FIELD_DATA, 0, (PVOID) &HandleCount},
  248. {"UniqueProcessId", "", 0, DBG_DUMP_FIELD_COPY_FIELD_DATA, 0, (PVOID) &UniqueProcessId},
  249. };
  250. SYM_DUMP_PARAM handleSym = {
  251. sizeof (SYM_DUMP_PARAM), "nt!_EPROCESS", DBG_DUMP_NO_PRINT, RealProcessBase,
  252. NULL, NULL, NULL, 1, &procFields[0]
  253. };
  254. //
  255. // Check for kernel handle table
  256. //
  257. if ((Flags & 0x10) || ((ulHandleNum != 0) && (((ULONG_PTR)HandleToDump & KERNEL_HANDLE_MASK) == KERNEL_HANDLE_MASK))) {
  258. ULONG64 KernelTableAddr;
  259. KernelHandle = TRUE;
  260. KernelTableAddr = GetExpression( "nt!ObpKernelHandleTable" );
  261. if (!KernelTableAddr) {
  262. dprintf( "Unable to find ObpKernelHandleTable\n" );
  263. return FALSE;
  264. }
  265. if (!ReadPointer(KernelTableAddr, &ObjectTable)) {
  266. dprintf( "Unable to find ObpKernelHandleTable at %p\n", KernelTableAddr );
  267. return FALSE;
  268. }
  269. } else if (Flags & 0x20) {
  270. CidHandle = TRUE;
  271. ObjectTable = GetNtDebuggerDataValue(PspCidTable);
  272. if (!ObjectTable) {
  273. dprintf( "Unable to find PspCidTable\n" );
  274. return FALSE;
  275. }
  276. } else {
  277. if (Ioctl(IG_DUMP_SYMBOL_INFO, &handleSym, handleSym.size)) {
  278. dprintf("Unable to get ObjectTable address from process %I64x\n", RealProcessBase);
  279. return FALSE;
  280. }
  281. }
  282. ptrSize = DBG_PTR_SIZE;
  283. if (!ptrSize) {
  284. dprintf("Cannot get pointer size\n");
  285. return FALSE;
  286. }
  287. handleSym.sName = "nt!_HANDLE_TABLE"; handleSym.addr = ObjectTable;
  288. handleSym.nFields = sizeof (handleTblFields) / sizeof (FIELD_INFO);
  289. handleSym.Fields = &handleTblFields[0];
  290. if (!ObjectTable ||
  291. Ioctl(IG_DUMP_SYMBOL_INFO, &handleSym, handleSym.size)) {
  292. dprintf("%08p: Unable to read handle table\n",
  293. ObjectTable);
  294. return FALSE;
  295. }
  296. if (GetFieldValue(ObjectTable, "nt!_HANDLE_TABLE", "TableCode", Table)) {
  297. // Could be older build
  298. }
  299. if (Table != 0) {
  300. NewStyle = TRUE;
  301. LowLevelCounts = 512;
  302. MidLevelCounts = 1024;
  303. HighLevelCounts = 1024;
  304. TableLevel = (ULONG)(Table & 3);
  305. Table &= ~((ULONG64)3);
  306. } else if (GetFieldValue(ObjectTable, "nt!_HANDLE_TABLE", "Table", Table) ) {
  307. dprintf("%08p: Unable to read Table field from _HANDLE_TABLE\n",
  308. ObjectTable);
  309. return FALSE;
  310. }
  311. if (KernelHandle) {
  312. dprintf( "Kernel " );
  313. }
  314. else if (CidHandle) {
  315. dprintf( "Cid " );
  316. }
  317. dprintf("%s version of handle table at %p with %I64d %s in use\n",
  318. (NewStyle ? "New" : "Old"),
  319. Table,
  320. HandleCount,
  321. ((HandleCount == 1) ? "Entry" : "Entries"));
  322. hTableEntrySize = GetTypeSize("nt!_HANDLE_TABLE_ENTRY");
  323. if (ulHandleNum != 0) {
  324. if (NewStyle) {
  325. ULONG64 CrtTable = Table;
  326. ULONG64 CrtHandleNum = ulHandleNum;
  327. if (TableLevel == 2) {
  328. ULONG64 HighLevelIndex = ulHandleNum / (LowLevelCounts * MidLevelCounts);
  329. CrtTable = CrtTable + HighLevelIndex * ptrSize;
  330. if (!ReadPointer(CrtTable,
  331. &CrtTable)) {
  332. dprintf("%08p: Unable to read handle table level 3\n", CrtTable );
  333. return FALSE;
  334. }
  335. CrtHandleNum = ulHandleNum - HighLevelIndex * (LowLevelCounts * MidLevelCounts);
  336. }
  337. if (TableLevel == 1) {
  338. CrtTable = CrtTable + (CrtHandleNum / LowLevelCounts) * ptrSize;
  339. if (!ReadPointer(CrtTable,
  340. &CrtTable)) {
  341. dprintf("%08p: Unable to read handle table level 2\n", CrtTable );
  342. return FALSE;
  343. }
  344. CrtHandleNum = CrtHandleNum % LowLevelCounts;
  345. }
  346. tablePtr = CrtTable + CrtHandleNum * hTableEntrySize;
  347. } else {
  348. //
  349. // Read the 3 level table stage by stage to find the specific entry
  350. //
  351. tablePtr = Table + ((ulHandleNum & 0x00FF0000) >> 16) * ptrSize;
  352. ulTopLevel = 0;
  353. if (!ReadPointer(tablePtr,
  354. &ulTopLevel)) {
  355. dprintf("%08p: Unable to read handle table level 3\n", tablePtr );
  356. return FALSE;
  357. }
  358. if (!ulTopLevel) {
  359. dprintf("Invalid handle: 0x%x\n", ulHandleNum);
  360. return FALSE;
  361. }
  362. tablePtr = ulTopLevel + ((ulHandleNum & 0x0000FF00) >> 8) * ptrSize;
  363. ulMidLevel = 0;
  364. if (!ReadPointer(tablePtr,
  365. &ulMidLevel)) {
  366. dprintf("%08p: Unable to read handle table level 2\n", tablePtr);
  367. return FALSE;
  368. }
  369. if (!ulMidLevel) {
  370. dprintf("Invalid handle: 0x%x\n", ulHandleNum);
  371. return FALSE;
  372. }
  373. //
  374. // Read the specific entry req. and dump it
  375. //
  376. tablePtr = (ulMidLevel + (0x000000ff & ulHandleNum) * hTableEntrySize);
  377. }
  378. DumpHandle(tablePtr, HandleToDump, pObjectType, Flags);
  379. } else {
  380. //
  381. // loop over all the possible parts of the table
  382. //
  383. for (iIndex1=0; iIndex1 < HighLevelCounts; iIndex1++) {
  384. //
  385. // check for ctrl-c to abort
  386. //
  387. if (CheckControlC()) {
  388. return FALSE;
  389. }
  390. if (TableLevel < 2) {
  391. tablePtr = Table;
  392. ulTopLevel = tablePtr;
  393. //
  394. // We break the loop second time if we don't have the table level 2
  395. //
  396. if (iIndex1 > 0) {
  397. break;
  398. }
  399. } else {
  400. //
  401. // Read the 3 level table stage by stage to find the specific entry
  402. //
  403. tablePtr = Table + iIndex1 * ptrSize;
  404. ulTopLevel = 0;
  405. if (!ReadPointer(tablePtr,
  406. &ulTopLevel)) {
  407. dprintf("%08p: Unable to read handle table top level\n",
  408. tablePtr);
  409. return FALSE;
  410. }
  411. if (!ulTopLevel) {
  412. continue;
  413. }
  414. }
  415. for (iIndex2=0; iIndex2 < MidLevelCounts; iIndex2++) {
  416. //
  417. // check for ctrl-c to abort
  418. //
  419. if (CheckControlC()) {
  420. return FALSE;
  421. }
  422. if (TableLevel < 1) {
  423. tablePtr = Table;
  424. ulMidLevel = tablePtr;
  425. //
  426. // We break the loop second time if we don't have the table level 1
  427. //
  428. if (iIndex2 > 0) {
  429. break;
  430. }
  431. } else {
  432. tablePtr = ulTopLevel + iIndex2 * ptrSize;
  433. ulMidLevel = 0;
  434. if (!ReadPointer(tablePtr,
  435. &ulMidLevel)) {
  436. dprintf("%08p: Unable to read handle table middle level\n",
  437. tablePtr);
  438. return FALSE;
  439. }
  440. if (!ulMidLevel) {
  441. continue;
  442. }
  443. }
  444. //
  445. // now read all the entries in this segment of the table and dump them
  446. // Note: Handle Number = 6 unused bits + 8 bits high + 8 bits mid +
  447. // 8 bits low + 2 bits user defined
  448. //
  449. for (iIndex3 = 0; iIndex3 < LowLevelCounts; iIndex3++) {
  450. //
  451. // check for ctrl-c to abort
  452. //
  453. if (CheckControlC()) {
  454. return FALSE;
  455. }
  456. DumpHandle(ulMidLevel + iIndex3*hTableEntrySize,
  457. (iIndex3 + (iIndex2 + iIndex1 * MidLevelCounts) * LowLevelCounts) * 4,
  458. pObjectType, Flags);
  459. }
  460. }
  461. } // end outermost for
  462. } // endif on a specific handle
  463. return TRUE;
  464. } // DumpHandles
  465. //+---------------------------------------------------------------------------
  466. //
  467. // Function: DumpHandle
  468. //
  469. // Synopsis: Dump a particular Handle
  470. //
  471. // Arguments: [pHandleTableEntry] -- entry to dump
  472. // [Handle] -- handle number of entry
  473. // [pObjectType] -- only dump if object type matches this
  474. // if NULL dump everything
  475. // [Flags] -- flags if 0x2 also dump the object
  476. // if 0x4 dump free entries
  477. //
  478. // Returns:
  479. //
  480. // History: 1-12-1998 benl Created
  481. // 1-12-1998 benl modified
  482. //
  483. // Notes:
  484. //
  485. //----------------------------------------------------------------------------
  486. BOOLEAN
  487. DumpHandle(
  488. IN ULONG64 pHandleTableEntry,
  489. IN ULONG64 Handle,
  490. IN ULONG64 pObjectType,
  491. IN ULONG Flags
  492. )
  493. {
  494. ULONG64 ulObjectHeaderAddr;
  495. ULONG Result;
  496. ULONG HandleAttributes;
  497. // OBJECT_HEADER ObjectHeader;
  498. ULONG64 ObjectBody;
  499. ULONG GrantedAccess=0;
  500. ULONG64 Object=0, ObjType=0;
  501. FIELD_INFO hTableEntryFields[] = {
  502. {"Object", "", 0, DBG_DUMP_FIELD_COPY_FIELD_DATA, 0, (PVOID) &Object},
  503. {"GrantedAccess", "", 0, DBG_DUMP_FIELD_COPY_FIELD_DATA, 0, (PVOID) &GrantedAccess},
  504. };
  505. FIELD_INFO ObjHeaderFields[] = {
  506. {"Type", "", 0, DBG_DUMP_FIELD_COPY_FIELD_DATA, 0, (PVOID) &ObjType},
  507. {"Body", "", 0, DBG_DUMP_FIELD_RETURN_ADDRESS, 0, NULL},
  508. };
  509. SYM_DUMP_PARAM ObjSym = {
  510. sizeof (SYM_DUMP_PARAM), "nt!_HANDLE_TABLE_ENTRY", DBG_DUMP_NO_PRINT, pHandleTableEntry,
  511. NULL, NULL, NULL, sizeof (hTableEntryFields) /sizeof (FIELD_INFO), &hTableEntryFields[0],
  512. };
  513. if (Ioctl (IG_DUMP_SYMBOL_INFO, &ObjSym, ObjSym.size)) {
  514. dprintf("Unable to get _HANDLE_TABLE_ENTRY : %p\n", pHandleTableEntry);
  515. return FALSE;
  516. }
  517. if (!(Object)) {
  518. //only print if flag is set to 4
  519. if (Flags & 4)
  520. {
  521. dprintf("%04lx: free handle\n", Handle);
  522. }
  523. return TRUE;
  524. }
  525. if (BuildNo > 2230) {
  526. // if (GetExpression( "nt!ObpAccessProtectCloseBit" )) {
  527. //
  528. // we have a new handle table style
  529. //
  530. //actual hdr has the lowest 3 bits cancelled out
  531. //lower 3 bits mark auditing, inheritance and lock
  532. ulObjectHeaderAddr = (Object) & ~(0x7);
  533. //
  534. // Apply the sign extension, if the highest bit is set
  535. //
  536. if ( !IsPtr64() &&
  537. (Object & 0x80000000)) {
  538. ulObjectHeaderAddr |= 0xFFFFFFFF00000000L;
  539. }
  540. } else {
  541. //actual hdr is sign extend value with the lowest 3 bits cancelled out
  542. //top bit marks whether entry is locked
  543. //lower 3 bits mark auditing, inheritance and protection
  544. if (!IsPtr64()) {
  545. ulObjectHeaderAddr = ((Object) & ~(0x7)) | 0xFFFFFFFF80000000L;
  546. } else {
  547. ulObjectHeaderAddr = ((Object) & ~(0x7)) | 0x8000000000000000L;
  548. }
  549. }
  550. ObjSym.sName = "nt!_OBJECT_HEADER"; ObjSym.addr = ulObjectHeaderAddr;
  551. ObjSym.nFields = sizeof (ObjHeaderFields) / sizeof (FIELD_INFO);
  552. ObjSym.Fields = &ObjHeaderFields[0];
  553. if (Ioctl ( IG_DUMP_SYMBOL_INFO, &ObjSym, ObjSym.size)) {
  554. dprintf("%08p: Unable to read nonpaged object header\n",
  555. ulObjectHeaderAddr);
  556. return FALSE;
  557. }
  558. if (pObjectType != 0 && ObjType != pObjectType) {
  559. return TRUE;
  560. }
  561. if (Flags & 0x20) {
  562. //
  563. // PspCidTable contains pointer to object, not object header
  564. // Compute header address based on object.
  565. //
  566. ObjectBody = ulObjectHeaderAddr;
  567. ulObjectHeaderAddr -= ObjHeaderFields[1].address-ulObjectHeaderAddr;
  568. }
  569. else {
  570. ObjectBody = ObjHeaderFields[1].address;
  571. }
  572. dprintf("%04I64lx: Object: %08p GrantedAccess: %08lx",
  573. Handle,
  574. ObjectBody,
  575. (GrantedAccess & ~MAXIMUM_ALLOWED));
  576. if (BuildNo > 2230) {
  577. // if (GetExpression( "nt!ObpAccessProtectCloseBit" )) {
  578. //
  579. // New handle table style
  580. //
  581. if (((ULONG) Object & 1) == 0) {
  582. dprintf(" (Locked)");
  583. }
  584. if (GrantedAccess & MAXIMUM_ALLOWED) {
  585. dprintf(" (Protected)");
  586. }
  587. } else {
  588. if (IsPtr64()) {
  589. if (Object & 0x8000000000000000L) {
  590. dprintf(" (Locked)");
  591. }
  592. } else if ((ULONG) Object & 0x80000000) {
  593. dprintf(" (Locked)");
  594. }
  595. if (Object & 1) {
  596. dprintf(" (Protected)");
  597. }
  598. }
  599. if (Object & 2) {
  600. dprintf(" (Inherit)");
  601. }
  602. if (Object & 4) {
  603. dprintf(" (Audit)");
  604. }
  605. dprintf("\n");
  606. if (Flags & 2) {
  607. DumpObject( " ", ObjectBody, Flags );
  608. }
  609. EXPRLastDump = ObjectBody;
  610. dprintf("\n");
  611. return TRUE;
  612. } // DumpHandle