1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/ex/handle.c 5 * PURPOSE: Generic Executive Handle Tables 6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 * Thomas Weidenmueller <w3seek@reactos.com> 8 */ 9 10 /* INCLUDES ******************************************************************/ 11 12 #include <ntoskrnl.h> 13 #define NDEBUG 14 #include <debug.h> 15 16 /* GLOBALS *******************************************************************/ 17 18 LIST_ENTRY HandleTableListHead; 19 EX_PUSH_LOCK HandleTableListLock; 20 #define SizeOfHandle(x) (sizeof(HANDLE) * (x)) 21 #define INDEX_TO_HANDLE_VALUE(x) ((x) << HANDLE_TAG_BITS) 22 23 /* PRIVATE FUNCTIONS *********************************************************/ 24 25 CODE_SEG("INIT") 26 VOID 27 NTAPI 28 ExpInitializeHandleTables(VOID) 29 { 30 /* Initialize the list of handle tables and the lock */ 31 InitializeListHead(&HandleTableListHead); 32 ExInitializePushLock(&HandleTableListLock); 33 } 34 35 PHANDLE_TABLE_ENTRY 36 NTAPI 37 ExpLookupHandleTableEntry(IN PHANDLE_TABLE HandleTable, 38 IN EXHANDLE Handle) 39 { 40 ULONG TableLevel; 41 ULONG_PTR TableBase; 42 PHANDLE_TABLE_ENTRY HandleArray, Entry; 43 PVOID *PointerArray; 44 45 /* Clear the tag bits */ 46 Handle.TagBits = 0; 47 48 /* Check if the handle is in the allocated range */ 49 if (Handle.Value >= HandleTable->NextHandleNeedingPool) 50 { 51 return NULL; 52 } 53 54 /* Get the table code */ 55 TableBase = HandleTable->TableCode; 56 57 /* Extract the table level and actual table base */ 58 TableLevel = (ULONG)(TableBase & 3); 59 TableBase &= ~3; 60 61 PointerArray = (PVOID*)TableBase; 62 HandleArray = (PHANDLE_TABLE_ENTRY)TableBase; 63 64 /* Check what level we're running at */ 65 switch (TableLevel) 66 { 67 case 2: 68 69 /* Get the mid level pointer array */ 70 PointerArray = PointerArray[Handle.HighIndex]; 71 ASSERT(PointerArray != NULL); 72 73 /* Fall through */ 74 case 1: 75 76 /* Get the handle array */ 77 HandleArray = PointerArray[Handle.MidIndex]; 78 ASSERT(HandleArray != NULL); 79 80 /* Fall through */ 81 case 0: 82 83 /* Get the entry using the low index */ 84 Entry = &HandleArray[Handle.LowIndex]; 85 86 /* All done */ 87 break; 88 89 default: 90 91 ASSERT(FALSE); 92 Entry = NULL; 93 } 94 95 /* Return the handle entry */ 96 return Entry; 97 } 98 99 PVOID 100 NTAPI 101 ExpAllocateTablePagedPool(IN PEPROCESS Process OPTIONAL, 102 IN SIZE_T Size) 103 { 104 PVOID Buffer; 105 NTSTATUS Status; 106 107 /* Do the allocation */ 108 Buffer = ExAllocatePoolWithTag(PagedPool, Size, TAG_OBJECT_TABLE); 109 if (Buffer) 110 { 111 /* Clear the memory */ 112 RtlZeroMemory(Buffer, Size); 113 114 /* Check if we have a process to charge quota */ 115 if (Process) 116 { 117 /* Charge quota */ 118 Status = PsChargeProcessPagedPoolQuota(Process, Size); 119 if (!NT_SUCCESS(Status)) 120 { 121 ExFreePoolWithTag(Buffer, TAG_OBJECT_TABLE); 122 return NULL; 123 } 124 } 125 } 126 127 /* Return the allocated memory */ 128 return Buffer; 129 } 130 131 PVOID 132 NTAPI 133 ExpAllocateTablePagedPoolNoZero(IN PEPROCESS Process OPTIONAL, 134 IN SIZE_T Size) 135 { 136 PVOID Buffer; 137 NTSTATUS Status; 138 139 /* Do the allocation */ 140 Buffer = ExAllocatePoolWithTag(PagedPool, Size, TAG_OBJECT_TABLE); 141 if (Buffer) 142 { 143 /* Check if we have a process to charge quota */ 144 if (Process) 145 { 146 /* Charge quota */ 147 Status = PsChargeProcessPagedPoolQuota(Process, Size); 148 if (!NT_SUCCESS(Status)) 149 { 150 ExFreePoolWithTag(Buffer, TAG_OBJECT_TABLE); 151 return NULL; 152 } 153 } 154 } 155 156 /* Return the allocated memory */ 157 return Buffer; 158 } 159 160 VOID 161 NTAPI 162 ExpFreeTablePagedPool(IN PEPROCESS Process OPTIONAL, 163 IN PVOID Buffer, 164 IN SIZE_T Size) 165 { 166 /* Free the buffer */ 167 ExFreePoolWithTag(Buffer, TAG_OBJECT_TABLE); 168 if (Process) 169 { 170 /* Release quota */ 171 PsReturnProcessPagedPoolQuota(Process, Size); 172 } 173 } 174 175 VOID 176 NTAPI 177 ExpFreeLowLevelTable(IN PEPROCESS Process, 178 IN PHANDLE_TABLE_ENTRY TableEntry) 179 { 180 /* Check if we have an entry */ 181 if (TableEntry[0].Object) 182 { 183 /* Free the entry */ 184 ExpFreeTablePagedPool(Process, 185 TableEntry[0].Object, 186 LOW_LEVEL_ENTRIES * 187 sizeof(HANDLE_TABLE_ENTRY_INFO)); 188 } 189 190 /* Free the table */ 191 ExpFreeTablePagedPool(Process, TableEntry, PAGE_SIZE); 192 } 193 194 VOID 195 NTAPI 196 ExpFreeHandleTable(IN PHANDLE_TABLE HandleTable) 197 { 198 PEPROCESS Process = HandleTable->QuotaProcess; 199 ULONG i, j; 200 ULONG_PTR TableCode = HandleTable->TableCode; 201 ULONG_PTR TableBase = TableCode & ~3; 202 ULONG TableLevel = (ULONG)(TableCode & 3); 203 PHANDLE_TABLE_ENTRY Level1, *Level2, **Level3; 204 PAGED_CODE(); 205 206 /* Check which level we're at */ 207 if (TableLevel == 0) 208 { 209 /* Select the first level table base and just free it */ 210 Level1 = (PVOID)TableBase; 211 ExpFreeLowLevelTable(Process, Level1); 212 } 213 else if (TableLevel == 1) 214 { 215 /* Select the second level table base */ 216 Level2 = (PVOID)TableBase; 217 218 /* Loop each mid level entry */ 219 for (i = 0; i < MID_LEVEL_ENTRIES; i++) 220 { 221 /* Leave if we've reached the last entry */ 222 if (!Level2[i]) break; 223 224 /* Free the second level table */ 225 ExpFreeLowLevelTable(Process, Level2[i]); 226 } 227 228 /* Free the second level table */ 229 ExpFreeTablePagedPool(Process, Level2, PAGE_SIZE); 230 } 231 else 232 { 233 /* Select the third level table base */ 234 Level3 = (PVOID)TableBase; 235 236 /* Loop each high level entry */ 237 for (i = 0; i < HIGH_LEVEL_ENTRIES; i++) 238 { 239 /* Leave if we've reached the last entry */ 240 if (!Level3[i]) break; 241 242 /* Loop each mid level entry */ 243 for (j = 0; j < MID_LEVEL_ENTRIES; j++) 244 { 245 /* Leave if we've reached the last entry */ 246 if (!Level3[i][j]) break; 247 248 /* Free the second level table */ 249 ExpFreeLowLevelTable(Process, Level3[i][j]); 250 } 251 252 /* Free the third level table entry */ 253 ExpFreeTablePagedPool(Process, Level3[i], PAGE_SIZE); 254 } 255 256 /* Free the third level table */ 257 ExpFreeTablePagedPool(Process, 258 Level3, 259 SizeOfHandle(HIGH_LEVEL_ENTRIES)); 260 } 261 262 /* Free the actual table and check if we need to release quota */ 263 ExFreePoolWithTag(HandleTable, TAG_OBJECT_TABLE); 264 if (Process) 265 { 266 /* Release the quota it was taking up */ 267 PsReturnProcessPagedPoolQuota(Process, sizeof(HANDLE_TABLE)); 268 } 269 } 270 271 VOID 272 NTAPI 273 ExpFreeHandleTableEntry(IN PHANDLE_TABLE HandleTable, 274 IN EXHANDLE Handle, 275 IN PHANDLE_TABLE_ENTRY HandleTableEntry) 276 { 277 ULONG OldValue, *Free; 278 ULONG LockIndex; 279 PAGED_CODE(); 280 281 /* Sanity checks */ 282 ASSERT(HandleTableEntry->Object == NULL); 283 ASSERT(HandleTableEntry == ExpLookupHandleTableEntry(HandleTable, Handle)); 284 285 /* Decrement the handle count */ 286 InterlockedDecrement(&HandleTable->HandleCount); 287 288 /* Mark the handle as free */ 289 Handle.TagBits = 0; 290 291 /* Check if we're FIFO */ 292 if (!HandleTable->StrictFIFO) 293 { 294 /* Select a lock index */ 295 LockIndex = Handle.Index % 4; 296 297 /* Select which entry to use */ 298 Free = (HandleTable->HandleTableLock[LockIndex].Locked) ? 299 &HandleTable->FirstFree : &HandleTable->LastFree; 300 } 301 else 302 { 303 /* No need to worry about locking, take the last entry */ 304 Free = &HandleTable->LastFree; 305 } 306 307 /* Start value change loop */ 308 for (;;) 309 { 310 /* Get the current value and write */ 311 OldValue = *Free; 312 HandleTableEntry->NextFreeTableEntry = OldValue; 313 if (InterlockedCompareExchange((PLONG)Free, Handle.AsULONG, OldValue) == OldValue) 314 { 315 /* Break out, we're done. Make sure the handle value makes sense */ 316 ASSERT((OldValue & FREE_HANDLE_MASK) < 317 HandleTable->NextHandleNeedingPool); 318 break; 319 } 320 } 321 } 322 323 PHANDLE_TABLE 324 NTAPI 325 ExpAllocateHandleTable(IN PEPROCESS Process OPTIONAL, 326 IN BOOLEAN NewTable) 327 { 328 PHANDLE_TABLE HandleTable; 329 PHANDLE_TABLE_ENTRY HandleTableTable, HandleEntry; 330 ULONG i; 331 NTSTATUS Status; 332 PAGED_CODE(); 333 334 /* Allocate the table */ 335 HandleTable = ExAllocatePoolWithTag(PagedPool, 336 sizeof(HANDLE_TABLE), 337 TAG_OBJECT_TABLE); 338 if (!HandleTable) return NULL; 339 340 /* Check if we have a process */ 341 if (Process) 342 { 343 /* Charge quota */ 344 Status = PsChargeProcessPagedPoolQuota(Process, sizeof(HANDLE_TABLE)); 345 if (!NT_SUCCESS(Status)) 346 { 347 ExFreePoolWithTag(HandleTable, TAG_OBJECT_TABLE); 348 return NULL; 349 } 350 } 351 352 /* Clear the table */ 353 RtlZeroMemory(HandleTable, sizeof(HANDLE_TABLE)); 354 355 /* Now allocate the first level structures */ 356 HandleTableTable = ExpAllocateTablePagedPoolNoZero(Process, PAGE_SIZE); 357 if (!HandleTableTable) 358 { 359 /* Failed, free the table */ 360 ExFreePoolWithTag(HandleTable, TAG_OBJECT_TABLE); 361 362 /* Return the quota it was taking up */ 363 if (Process) 364 { 365 PsReturnProcessPagedPoolQuota(Process, sizeof(HANDLE_TABLE)); 366 } 367 368 return NULL; 369 } 370 371 /* Write the pointer to our first level structures */ 372 HandleTable->TableCode = (ULONG_PTR)HandleTableTable; 373 374 /* Initialize the first entry */ 375 HandleEntry = &HandleTableTable[0]; 376 HandleEntry->NextFreeTableEntry = -2; 377 HandleEntry->Value = 0; 378 379 /* Check if this is a new table */ 380 if (NewTable) 381 { 382 /* Go past the root entry */ 383 HandleEntry++; 384 385 /* Loop every low level entry */ 386 for (i = 1; i < (LOW_LEVEL_ENTRIES - 1); i++) 387 { 388 /* Set up the free data */ 389 HandleEntry->Value = 0; 390 HandleEntry->NextFreeTableEntry = INDEX_TO_HANDLE_VALUE(i + 1); 391 392 /* Move to the next entry */ 393 HandleEntry++; 394 } 395 396 /* Terminate the last entry */ 397 HandleEntry->Value = 0; 398 HandleEntry->NextFreeTableEntry = 0; 399 HandleTable->FirstFree = INDEX_TO_HANDLE_VALUE(1); 400 } 401 402 /* Set the next handle needing pool after our allocated page from above */ 403 HandleTable->NextHandleNeedingPool = INDEX_TO_HANDLE_VALUE(LOW_LEVEL_ENTRIES); 404 405 /* Setup the rest of the handle table data */ 406 HandleTable->QuotaProcess = Process; 407 HandleTable->UniqueProcessId = PsGetCurrentProcess()->UniqueProcessId; 408 HandleTable->Flags = 0; 409 410 /* Loop all the handle table locks */ 411 for (i = 0; i < 4; i++) 412 { 413 /* Initialize the handle table lock */ 414 ExInitializePushLock(&HandleTable->HandleTableLock[i]); 415 } 416 417 /* Initialize the contention event lock and return the lock */ 418 ExInitializePushLock(&HandleTable->HandleContentionEvent); 419 return HandleTable; 420 } 421 422 PHANDLE_TABLE_ENTRY 423 NTAPI 424 ExpAllocateLowLevelTable(IN PHANDLE_TABLE HandleTable, 425 IN BOOLEAN DoInit) 426 { 427 ULONG i, Base; 428 PHANDLE_TABLE_ENTRY Low, HandleEntry; 429 430 /* Allocate the low level table */ 431 Low = ExpAllocateTablePagedPoolNoZero(HandleTable->QuotaProcess, 432 PAGE_SIZE); 433 if (!Low) return NULL; 434 435 /* Setup the initial entry */ 436 HandleEntry = &Low[0]; 437 HandleEntry->NextFreeTableEntry = -2; 438 HandleEntry->Value = 0; 439 440 /* Check if we're initializing */ 441 if (DoInit) 442 { 443 /* Go to the next entry and the base entry */ 444 HandleEntry++; 445 Base = HandleTable->NextHandleNeedingPool + INDEX_TO_HANDLE_VALUE(2); 446 447 /* Loop each entry */ 448 for (i = Base; 449 i < Base + INDEX_TO_HANDLE_VALUE(LOW_LEVEL_ENTRIES - 2); 450 i += INDEX_TO_HANDLE_VALUE(1)) 451 { 452 /* Free this entry and move on to the next one */ 453 HandleEntry->NextFreeTableEntry = i; 454 HandleEntry->Value = 0; 455 HandleEntry++; 456 } 457 458 /* Terminate the last entry */ 459 HandleEntry->NextFreeTableEntry = 0; 460 HandleEntry->Value = 0; 461 } 462 463 /* Return the low level table */ 464 return Low; 465 } 466 467 PHANDLE_TABLE_ENTRY* 468 NTAPI 469 ExpAllocateMidLevelTable(IN PHANDLE_TABLE HandleTable, 470 IN BOOLEAN DoInit, 471 OUT PHANDLE_TABLE_ENTRY *LowTableEntry) 472 { 473 PHANDLE_TABLE_ENTRY *Mid, Low; 474 475 /* Allocate the mid level table */ 476 Mid = ExpAllocateTablePagedPool(HandleTable->QuotaProcess, PAGE_SIZE); 477 if (!Mid) return NULL; 478 479 /* Allocate a new low level for it */ 480 Low = ExpAllocateLowLevelTable(HandleTable, DoInit); 481 if (!Low) 482 { 483 /* We failed, free the mid table */ 484 ExpFreeTablePagedPool(HandleTable->QuotaProcess, Mid, PAGE_SIZE); 485 return NULL; 486 } 487 488 /* Link the tables and return the pointer */ 489 Mid[0] = Low; 490 *LowTableEntry = Low; 491 return Mid; 492 } 493 494 BOOLEAN 495 NTAPI 496 ExpAllocateHandleTableEntrySlow(IN PHANDLE_TABLE HandleTable, 497 IN BOOLEAN DoInit) 498 { 499 ULONG i, j, Index; 500 PHANDLE_TABLE_ENTRY Low = NULL, *Mid, **High, *SecondLevel, **ThirdLevel; 501 ULONG NewFree, FirstFree; 502 PVOID Value; 503 ULONG_PTR TableCode = HandleTable->TableCode; 504 ULONG_PTR TableBase = TableCode & ~3; 505 ULONG TableLevel = (ULONG)(TableCode & 3); 506 PAGED_CODE(); 507 508 /* Check how many levels we already have */ 509 if (TableLevel == 0) 510 { 511 /* Allocate a mid level, since we only have a low level */ 512 Mid = ExpAllocateMidLevelTable(HandleTable, DoInit, &Low); 513 if (!Mid) return FALSE; 514 515 /* Link up the tables */ 516 Mid[1] = Mid[0]; 517 Mid[0] = (PVOID)TableBase; 518 519 /* Write the new level and attempt to change the table code */ 520 TableBase = ((ULONG_PTR)Mid) | 1; 521 Value = InterlockedExchangePointer((PVOID*)&HandleTable->TableCode, (PVOID)TableBase); 522 } 523 else if (TableLevel == 1) 524 { 525 /* Setup the 2nd level table */ 526 SecondLevel = (PVOID)TableBase; 527 528 /* Get if the next index can fit in the table */ 529 i = HandleTable->NextHandleNeedingPool / 530 INDEX_TO_HANDLE_VALUE(LOW_LEVEL_ENTRIES); 531 if (i < MID_LEVEL_ENTRIES) 532 { 533 /* We need to allocate a new table */ 534 Low = ExpAllocateLowLevelTable(HandleTable, DoInit); 535 if (!Low) return FALSE; 536 537 /* Update the table */ 538 Value = InterlockedExchangePointer((PVOID*)&SecondLevel[i], Low); 539 ASSERT(Value == NULL); 540 } 541 else 542 { 543 /* We need a new high level table */ 544 High = ExpAllocateTablePagedPool(HandleTable->QuotaProcess, 545 SizeOfHandle(HIGH_LEVEL_ENTRIES)); 546 if (!High) return FALSE; 547 548 /* Allocate a new mid level table as well */ 549 Mid = ExpAllocateMidLevelTable(HandleTable, DoInit, &Low); 550 if (!Mid) 551 { 552 /* We failed, free the high level table as well */ 553 ExpFreeTablePagedPool(HandleTable->QuotaProcess, 554 High, 555 SizeOfHandle(HIGH_LEVEL_ENTRIES)); 556 return FALSE; 557 } 558 559 /* Link up the tables */ 560 High[0] = (PVOID)TableBase; 561 High[1] = Mid; 562 563 /* Write the new table and change the table code */ 564 TableBase = ((ULONG_PTR)High) | 2; 565 Value = InterlockedExchangePointer((PVOID*)&HandleTable->TableCode, 566 (PVOID)TableBase); 567 } 568 } 569 else if (TableLevel == 2) 570 { 571 /* Setup the 3rd level table */ 572 ThirdLevel = (PVOID)TableBase; 573 574 /* Get the index and check if it can fit */ 575 i = HandleTable->NextHandleNeedingPool / INDEX_TO_HANDLE_VALUE(MAX_MID_INDEX); 576 if (i >= HIGH_LEVEL_ENTRIES) return FALSE; 577 578 /* Check if there's no mid-level table */ 579 if (!ThirdLevel[i]) 580 { 581 /* Allocate a new mid level table */ 582 Mid = ExpAllocateMidLevelTable(HandleTable, DoInit, &Low); 583 if (!Mid) return FALSE; 584 585 /* Update the table pointer */ 586 Value = InterlockedExchangePointer((PVOID*)&ThirdLevel[i], Mid); 587 ASSERT(Value == NULL); 588 } 589 else 590 { 591 /* We have one, check at which index we should insert our entry */ 592 Index = (HandleTable->NextHandleNeedingPool / INDEX_TO_HANDLE_VALUE(1)) - 593 i * MAX_MID_INDEX; 594 j = Index / LOW_LEVEL_ENTRIES; 595 596 /* Allocate a new low level */ 597 Low = ExpAllocateLowLevelTable(HandleTable, DoInit); 598 if (!Low) return FALSE; 599 600 /* Update the table pointer */ 601 Value = InterlockedExchangePointer((PVOID*)&ThirdLevel[i][j], Low); 602 ASSERT(Value == NULL); 603 } 604 } 605 else 606 { 607 /* Something is really broken */ 608 ASSERT(FALSE); 609 } 610 611 /* Update the index of the next handle */ 612 Index = InterlockedExchangeAdd((PLONG) &HandleTable->NextHandleNeedingPool, 613 INDEX_TO_HANDLE_VALUE(LOW_LEVEL_ENTRIES)); 614 615 /* Check if need to initialize the table */ 616 if (DoInit) 617 { 618 /* Create a new index number */ 619 Index += INDEX_TO_HANDLE_VALUE(1); 620 621 /* Start free index change loop */ 622 for (;;) 623 { 624 /* Setup the first free index */ 625 FirstFree = HandleTable->FirstFree; 626 Low[LOW_LEVEL_ENTRIES - 1].NextFreeTableEntry = FirstFree; 627 628 /* Change the index */ 629 NewFree = InterlockedCompareExchange((PLONG) &HandleTable->FirstFree, 630 Index, 631 FirstFree); 632 if (NewFree == FirstFree) break; 633 } 634 } 635 636 /* All done */ 637 return TRUE; 638 } 639 640 ULONG 641 NTAPI 642 ExpMoveFreeHandles(IN PHANDLE_TABLE HandleTable) 643 { 644 ULONG LastFree, i; 645 646 /* Clear the last free index */ 647 LastFree = InterlockedExchange((PLONG) &HandleTable->LastFree, 0); 648 649 /* Check if we had no index */ 650 if (!LastFree) return LastFree; 651 652 /* Acquire the locks we need */ 653 for (i = 1; i < 4; i++) 654 { 655 /* Acquire this lock exclusively */ 656 ExWaitOnPushLock(&HandleTable->HandleTableLock[i]); 657 } 658 659 /* Check if we're not strict FIFO */ 660 if (!HandleTable->StrictFIFO) 661 { 662 /* Update the first free index */ 663 if (!InterlockedCompareExchange((PLONG) &HandleTable->FirstFree, LastFree, 0)) 664 { 665 /* We're done, exit */ 666 return LastFree; 667 } 668 } 669 670 /* We are strict FIFO, we need to reverse the entries */ 671 ASSERT(FALSE); 672 return LastFree; 673 } 674 675 PHANDLE_TABLE_ENTRY 676 NTAPI 677 ExpAllocateHandleTableEntry(IN PHANDLE_TABLE HandleTable, 678 OUT PEXHANDLE NewHandle) 679 { 680 ULONG OldValue, NewValue, NewValue1; 681 PHANDLE_TABLE_ENTRY Entry; 682 EXHANDLE Handle, OldHandle; 683 BOOLEAN Result; 684 ULONG i; 685 686 /* Start allocation loop */ 687 for (;;) 688 { 689 /* Get the current link */ 690 OldValue = HandleTable->FirstFree; 691 while (!OldValue) 692 { 693 /* No free entries remain, lock the handle table */ 694 KeEnterCriticalRegion(); 695 ExAcquirePushLockExclusive(&HandleTable->HandleTableLock[0]); 696 697 /* Check the value again */ 698 OldValue = HandleTable->FirstFree; 699 if (OldValue) 700 { 701 /* Another thread has already created a new level, bail out */ 702 ExReleasePushLockExclusive(&HandleTable->HandleTableLock[0]); 703 KeLeaveCriticalRegion(); 704 break; 705 } 706 707 /* Now move any free handles */ 708 OldValue = ExpMoveFreeHandles(HandleTable); 709 if (OldValue) 710 { 711 /* Another thread has already moved them, bail out */ 712 ExReleasePushLockExclusive(&HandleTable->HandleTableLock[0]); 713 KeLeaveCriticalRegion(); 714 break; 715 } 716 717 /* We're the first one through, so do the actual allocation */ 718 Result = ExpAllocateHandleTableEntrySlow(HandleTable, TRUE); 719 720 /* Unlock the table and get the value now */ 721 ExReleasePushLockExclusive(&HandleTable->HandleTableLock[0]); 722 KeLeaveCriticalRegion(); 723 OldValue = HandleTable->FirstFree; 724 725 /* Check if allocation failed */ 726 if (!Result) 727 { 728 /* Check if nobody else went through here */ 729 if (!OldValue) 730 { 731 /* We're still the only thread around, so fail */ 732 NewHandle->GenericHandleOverlay = NULL; 733 return NULL; 734 } 735 } 736 } 737 738 /* We made it, write the current value */ 739 Handle.Value = (OldValue & FREE_HANDLE_MASK); 740 741 /* Lookup the entry for this handle */ 742 Entry = ExpLookupHandleTableEntry(HandleTable, Handle); 743 744 /* Get an available lock and acquire it */ 745 OldHandle.Value = OldValue; 746 i = OldHandle.Index % 4; 747 KeEnterCriticalRegion(); 748 ExAcquirePushLockShared(&HandleTable->HandleTableLock[i]); 749 750 /* Check if the value changed after acquiring the lock */ 751 if (OldValue != *(volatile ULONG*)&HandleTable->FirstFree) 752 { 753 /* It did, so try again */ 754 ExReleasePushLockShared(&HandleTable->HandleTableLock[i]); 755 KeLeaveCriticalRegion(); 756 continue; 757 } 758 759 /* Now get the next value and do the compare */ 760 NewValue = *(volatile ULONG*)&Entry->NextFreeTableEntry; 761 NewValue1 = InterlockedCompareExchange((PLONG) &HandleTable->FirstFree, 762 NewValue, 763 OldValue); 764 765 /* The change was done, so release the lock */ 766 ExReleasePushLockShared(&HandleTable->HandleTableLock[i]); 767 KeLeaveCriticalRegion(); 768 769 /* Check if the compare was successful */ 770 if (NewValue1 == OldValue) 771 { 772 /* Make sure that the new handle is in range, and break out */ 773 ASSERT((NewValue & FREE_HANDLE_MASK) < 774 HandleTable->NextHandleNeedingPool); 775 break; 776 } 777 else 778 { 779 /* The compare failed, make sure we expected it */ 780 ASSERT((NewValue1 & FREE_HANDLE_MASK) != 781 (OldValue & FREE_HANDLE_MASK)); 782 } 783 } 784 785 /* Increase the number of handles */ 786 InterlockedIncrement(&HandleTable->HandleCount); 787 788 /* Return the handle and the entry */ 789 *NewHandle = Handle; 790 return Entry; 791 } 792 793 PHANDLE_TABLE 794 NTAPI 795 ExCreateHandleTable(IN PEPROCESS Process OPTIONAL) 796 { 797 PHANDLE_TABLE HandleTable; 798 PAGED_CODE(); 799 800 /* Allocate the handle table */ 801 HandleTable = ExpAllocateHandleTable(Process, TRUE); 802 if (!HandleTable) return NULL; 803 804 /* Acquire the handle table lock */ 805 KeEnterCriticalRegion(); 806 ExAcquirePushLockExclusive(&HandleTableListLock); 807 808 /* Insert it into the list */ 809 InsertTailList(&HandleTableListHead, &HandleTable->HandleTableList); 810 811 /* Release the lock */ 812 ExReleasePushLockExclusive(&HandleTableListLock); 813 KeLeaveCriticalRegion(); 814 815 /* Return the handle table */ 816 return HandleTable; 817 } 818 819 HANDLE 820 NTAPI 821 ExCreateHandle(IN PHANDLE_TABLE HandleTable, 822 IN PHANDLE_TABLE_ENTRY HandleTableEntry) 823 { 824 EXHANDLE Handle; 825 PHANDLE_TABLE_ENTRY NewEntry; 826 PAGED_CODE(); 827 828 /* Start with a clean handle */ 829 Handle.GenericHandleOverlay = NULL; 830 831 /* Allocate a new entry */ 832 NewEntry = ExpAllocateHandleTableEntry(HandleTable, &Handle); 833 if (NewEntry) 834 { 835 /* Enter a critical region */ 836 KeEnterCriticalRegion(); 837 838 /* Write the entry */ 839 *NewEntry = *HandleTableEntry; 840 841 /* Unlock it and leave the critical region */ 842 ExUnlockHandleTableEntry(HandleTable, NewEntry); 843 KeLeaveCriticalRegion(); 844 } 845 846 /* Return the handle value */ 847 return Handle.GenericHandleOverlay; 848 } 849 850 VOID 851 NTAPI 852 ExpBlockOnLockedHandleEntry(IN PHANDLE_TABLE HandleTable, 853 IN PHANDLE_TABLE_ENTRY HandleTableEntry) 854 { 855 LONG_PTR OldValue; 856 EX_PUSH_LOCK_WAIT_BLOCK WaitBlock; 857 858 /* Block on the pushlock */ 859 ExBlockPushLock(&HandleTable->HandleContentionEvent, &WaitBlock); 860 861 /* Get the current value and check if it's been unlocked */ 862 OldValue = HandleTableEntry->Value; 863 if (!(OldValue) || (OldValue & EXHANDLE_TABLE_ENTRY_LOCK_BIT)) 864 { 865 /* Unblock the pushlock and return */ 866 ExfUnblockPushLock(&HandleTable->HandleContentionEvent, &WaitBlock); 867 } 868 else 869 { 870 /* Wait for it to be unblocked */ 871 ExWaitForUnblockPushLock(&HandleTable->HandleContentionEvent, 872 &WaitBlock); 873 } 874 } 875 876 BOOLEAN 877 NTAPI 878 ExpLockHandleTableEntry(IN PHANDLE_TABLE HandleTable, 879 IN PHANDLE_TABLE_ENTRY HandleTableEntry) 880 { 881 LONG_PTR NewValue, OldValue; 882 883 /* Sanity check */ 884 ASSERT((KeGetCurrentThread()->CombinedApcDisable != 0) || 885 (KeGetCurrentIrql() == APC_LEVEL)); 886 887 /* Start lock loop */ 888 for (;;) 889 { 890 /* Get the current value and check if it's locked */ 891 OldValue = *(volatile LONG_PTR *)&HandleTableEntry->Object; 892 if (OldValue & EXHANDLE_TABLE_ENTRY_LOCK_BIT) 893 { 894 /* It's not locked, remove the lock bit to lock it */ 895 NewValue = OldValue & ~EXHANDLE_TABLE_ENTRY_LOCK_BIT; 896 if (InterlockedCompareExchangePointer(&HandleTableEntry->Object, 897 (PVOID)NewValue, 898 (PVOID)OldValue) == (PVOID)OldValue) 899 { 900 /* We locked it, get out */ 901 return TRUE; 902 } 903 } 904 else 905 { 906 /* We couldn't lock it, bail out if it's been freed */ 907 if (!OldValue) return FALSE; 908 } 909 910 /* It's locked, wait for it to be unlocked */ 911 ExpBlockOnLockedHandleEntry(HandleTable, HandleTableEntry); 912 } 913 } 914 915 VOID 916 NTAPI 917 ExUnlockHandleTableEntry(IN PHANDLE_TABLE HandleTable, 918 IN PHANDLE_TABLE_ENTRY HandleTableEntry) 919 { 920 LONG_PTR OldValue; 921 PAGED_CODE(); 922 923 /* Sanity check */ 924 ASSERT((KeGetCurrentThread()->CombinedApcDisable != 0) || 925 (KeGetCurrentIrql() == APC_LEVEL)); 926 927 /* Set the lock bit and make sure it wasn't earlier */ 928 OldValue = InterlockedOr((PLONG) &HandleTableEntry->Value, 929 EXHANDLE_TABLE_ENTRY_LOCK_BIT); 930 ASSERT((OldValue & EXHANDLE_TABLE_ENTRY_LOCK_BIT) == 0); 931 932 /* Unblock any waiters */ 933 ExfUnblockPushLock(&HandleTable->HandleContentionEvent, NULL); 934 } 935 936 VOID 937 NTAPI 938 ExRemoveHandleTable(IN PHANDLE_TABLE HandleTable) 939 { 940 PAGED_CODE(); 941 942 /* Acquire the table lock */ 943 KeEnterCriticalRegion(); 944 ExAcquirePushLockExclusive(&HandleTableListLock); 945 946 /* Remove the table and reset the list */ 947 RemoveEntryList(&HandleTable->HandleTableList); 948 InitializeListHead(&HandleTable->HandleTableList); 949 950 /* Release the lock */ 951 ExReleasePushLockExclusive(&HandleTableListLock); 952 KeLeaveCriticalRegion(); 953 } 954 955 VOID 956 NTAPI 957 ExDestroyHandleTable(IN PHANDLE_TABLE HandleTable, 958 IN PVOID DestroyHandleProcedure OPTIONAL) 959 { 960 PAGED_CODE(); 961 962 /* Remove the handle from the list */ 963 ExRemoveHandleTable(HandleTable); 964 965 /* Check if we have a destroy callback */ 966 if (DestroyHandleProcedure) 967 { 968 /* FIXME: */ 969 ASSERT(FALSE); 970 } 971 972 /* Free the handle table */ 973 ExpFreeHandleTable(HandleTable); 974 } 975 976 BOOLEAN 977 NTAPI 978 ExDestroyHandle(IN PHANDLE_TABLE HandleTable, 979 IN HANDLE Handle, 980 IN PHANDLE_TABLE_ENTRY HandleTableEntry OPTIONAL) 981 { 982 EXHANDLE ExHandle; 983 PVOID Object; 984 PAGED_CODE(); 985 986 /* Setup the actual handle value */ 987 ExHandle.GenericHandleOverlay = Handle; 988 989 /* Enter a critical region and check if we have to lookup the handle */ 990 KeEnterCriticalRegion(); 991 if (!HandleTableEntry) 992 { 993 /* Lookup the entry */ 994 HandleTableEntry = ExpLookupHandleTableEntry(HandleTable, ExHandle); 995 996 /* Make sure that we found an entry, and that it's valid */ 997 if (!(HandleTableEntry) || 998 !(HandleTableEntry->Object) || 999 (HandleTableEntry->NextFreeTableEntry == -2)) 1000 { 1001 /* Invalid handle, fail */ 1002 KeLeaveCriticalRegion(); 1003 return FALSE; 1004 } 1005 1006 /* Lock the entry */ 1007 if (!ExpLockHandleTableEntry(HandleTable, HandleTableEntry)) 1008 { 1009 /* Couldn't lock, fail */ 1010 KeLeaveCriticalRegion(); 1011 return FALSE; 1012 } 1013 } 1014 else 1015 { 1016 /* Make sure the handle is locked */ 1017 ASSERT((HandleTableEntry->Value & EXHANDLE_TABLE_ENTRY_LOCK_BIT) == 0); 1018 } 1019 1020 /* Clear the handle */ 1021 Object = InterlockedExchangePointer((PVOID*)&HandleTableEntry->Object, NULL); 1022 1023 /* Sanity checks */ 1024 ASSERT(Object != NULL); 1025 ASSERT((((ULONG_PTR)Object) & EXHANDLE_TABLE_ENTRY_LOCK_BIT) == 0); 1026 1027 /* Unblock the pushlock */ 1028 ExfUnblockPushLock(&HandleTable->HandleContentionEvent, NULL); 1029 1030 /* Free the actual entry */ 1031 ExpFreeHandleTableEntry(HandleTable, ExHandle, HandleTableEntry); 1032 1033 /* If we got here, return success */ 1034 KeLeaveCriticalRegion(); 1035 return TRUE; 1036 } 1037 1038 PHANDLE_TABLE_ENTRY 1039 NTAPI 1040 ExMapHandleToPointer(IN PHANDLE_TABLE HandleTable, 1041 IN HANDLE Handle) 1042 { 1043 EXHANDLE ExHandle; 1044 PHANDLE_TABLE_ENTRY HandleTableEntry; 1045 PAGED_CODE(); 1046 1047 /* Set the handle value */ 1048 ExHandle.GenericHandleOverlay = Handle; 1049 1050 /* Fail if we got an invalid index */ 1051 if (!(ExHandle.Index & (LOW_LEVEL_ENTRIES - 1))) return NULL; 1052 1053 /* Do the lookup */ 1054 HandleTableEntry = ExpLookupHandleTableEntry(HandleTable, ExHandle); 1055 if (!HandleTableEntry) return NULL; 1056 1057 /* Lock it */ 1058 if (!ExpLockHandleTableEntry(HandleTable, HandleTableEntry)) return NULL; 1059 1060 /* Return the entry */ 1061 return HandleTableEntry; 1062 } 1063 1064 PHANDLE_TABLE 1065 NTAPI 1066 ExDupHandleTable(IN PEPROCESS Process, 1067 IN PHANDLE_TABLE HandleTable, 1068 IN PEX_DUPLICATE_HANDLE_CALLBACK DupHandleProcedure, 1069 IN ULONG_PTR Mask) 1070 { 1071 PHANDLE_TABLE NewTable; 1072 EXHANDLE Handle; 1073 PHANDLE_TABLE_ENTRY HandleTableEntry, NewEntry; 1074 BOOLEAN Failed = FALSE; 1075 PAGED_CODE(); 1076 1077 /* Allocate the duplicated copy */ 1078 NewTable = ExpAllocateHandleTable(Process, FALSE); 1079 if (!NewTable) return NULL; 1080 1081 /* Loop each entry */ 1082 while (NewTable->NextHandleNeedingPool < 1083 HandleTable->NextHandleNeedingPool) 1084 { 1085 /* Insert it into the duplicated copy */ 1086 if (!ExpAllocateHandleTableEntrySlow(NewTable, FALSE)) 1087 { 1088 /* Insert failed, free the new copy and return */ 1089 ExpFreeHandleTable(NewTable); 1090 return NULL; 1091 } 1092 } 1093 1094 /* Setup the initial handle table data */ 1095 NewTable->HandleCount = 0; 1096 NewTable->ExtraInfoPages = 0; 1097 NewTable->FirstFree = 0; 1098 1099 /* Setup the first handle value */ 1100 Handle.Value = INDEX_TO_HANDLE_VALUE(1); 1101 1102 /* Enter a critical region and lookup the new entry */ 1103 KeEnterCriticalRegion(); 1104 while ((NewEntry = ExpLookupHandleTableEntry(NewTable, Handle))) 1105 { 1106 /* Lookup the old entry */ 1107 HandleTableEntry = ExpLookupHandleTableEntry(HandleTable, Handle); 1108 1109 /* Loop each entry */ 1110 do 1111 { 1112 /* Check if it doesn't match the audit mask */ 1113 if (!(HandleTableEntry->Value & Mask)) 1114 { 1115 /* Free it since we won't use it */ 1116 Failed = TRUE; 1117 } 1118 else 1119 { 1120 /* Lock the entry */ 1121 if (!ExpLockHandleTableEntry(HandleTable, HandleTableEntry)) 1122 { 1123 /* Free it since we can't lock it, so we won't use it */ 1124 Failed = TRUE; 1125 } 1126 else 1127 { 1128 /* Copy the handle value */ 1129 *NewEntry = *HandleTableEntry; 1130 1131 /* Call the duplicate callback */ 1132 if (DupHandleProcedure(Process, 1133 HandleTable, 1134 HandleTableEntry, 1135 NewEntry)) 1136 { 1137 /* Clear failure flag */ 1138 Failed = FALSE; 1139 1140 /* Lock the entry, increase the handle count */ 1141 NewEntry->Value |= EXHANDLE_TABLE_ENTRY_LOCK_BIT; 1142 NewTable->HandleCount++; 1143 } 1144 else 1145 { 1146 /* Duplication callback refused, fail */ 1147 Failed = TRUE; 1148 } 1149 } 1150 } 1151 1152 /* Check if we failed earlier and need to free */ 1153 if (Failed) 1154 { 1155 /* Free this entry */ 1156 NewEntry->Object = NULL; 1157 NewEntry->NextFreeTableEntry = NewTable->FirstFree; 1158 NewTable->FirstFree = (ULONG)Handle.Value; 1159 } 1160 1161 /* Increase the handle value and move to the next entry */ 1162 Handle.Value += INDEX_TO_HANDLE_VALUE(1); 1163 NewEntry++; 1164 HandleTableEntry++; 1165 } while (Handle.Value % INDEX_TO_HANDLE_VALUE(LOW_LEVEL_ENTRIES)); 1166 1167 /* We're done, skip the last entry */ 1168 Handle.Value += INDEX_TO_HANDLE_VALUE(1); 1169 } 1170 1171 /* Acquire the table lock and insert this new table into the list */ 1172 ExAcquirePushLockExclusive(&HandleTableListLock); 1173 InsertTailList(&HandleTableListHead, &NewTable->HandleTableList); 1174 ExReleasePushLockExclusive(&HandleTableListLock); 1175 1176 /* Leave the critical region we entered previously and return the table */ 1177 KeLeaveCriticalRegion(); 1178 return NewTable; 1179 } 1180 1181 BOOLEAN 1182 NTAPI 1183 ExChangeHandle(IN PHANDLE_TABLE HandleTable, 1184 IN HANDLE Handle, 1185 IN PEX_CHANGE_HANDLE_CALLBACK ChangeRoutine, 1186 IN ULONG_PTR Context) 1187 { 1188 EXHANDLE ExHandle; 1189 PHANDLE_TABLE_ENTRY HandleTableEntry; 1190 BOOLEAN Result = FALSE; 1191 PAGED_CODE(); 1192 1193 /* Set the handle value */ 1194 ExHandle.GenericHandleOverlay = Handle; 1195 1196 /* Find the entry for this handle */ 1197 HandleTableEntry = ExpLookupHandleTableEntry(HandleTable, ExHandle); 1198 1199 /* Make sure that we found an entry, and that it's valid */ 1200 if (!(HandleTableEntry) || 1201 !(HandleTableEntry->Object) || 1202 (HandleTableEntry->NextFreeTableEntry == -2)) 1203 { 1204 /* It isn't, fail */ 1205 return FALSE; 1206 } 1207 1208 /* Enter a critical region */ 1209 KeEnterCriticalRegion(); 1210 1211 /* Try locking the handle entry */ 1212 if (ExpLockHandleTableEntry(HandleTable, HandleTableEntry)) 1213 { 1214 /* Call the change routine and unlock the entry */ 1215 Result = ChangeRoutine(HandleTableEntry, Context); 1216 ExUnlockHandleTableEntry(HandleTable, HandleTableEntry); 1217 } 1218 1219 /* Leave the critical region and return the callback result */ 1220 KeLeaveCriticalRegion(); 1221 return Result; 1222 } 1223 1224 VOID 1225 NTAPI 1226 ExSweepHandleTable(IN PHANDLE_TABLE HandleTable, 1227 IN PEX_SWEEP_HANDLE_CALLBACK EnumHandleProcedure, 1228 IN PVOID Context) 1229 { 1230 EXHANDLE Handle; 1231 PHANDLE_TABLE_ENTRY HandleTableEntry; 1232 PAGED_CODE(); 1233 1234 /* Set the initial value and loop the entries */ 1235 Handle.Value = INDEX_TO_HANDLE_VALUE(1); 1236 while ((HandleTableEntry = ExpLookupHandleTableEntry(HandleTable, Handle))) 1237 { 1238 /* Loop each handle */ 1239 do 1240 { 1241 /* Lock the entry */ 1242 if (ExpLockHandleTableEntry(HandleTable, HandleTableEntry)) 1243 { 1244 /* Notify the callback routine */ 1245 EnumHandleProcedure(HandleTableEntry, 1246 Handle.GenericHandleOverlay, 1247 Context); 1248 } 1249 1250 /* Go to the next handle and entry */ 1251 Handle.Value += INDEX_TO_HANDLE_VALUE(1); 1252 HandleTableEntry++; 1253 } while (Handle.Value % INDEX_TO_HANDLE_VALUE(LOW_LEVEL_ENTRIES)); 1254 1255 /* Skip past the last entry */ 1256 Handle.Value += INDEX_TO_HANDLE_VALUE(1); 1257 } 1258 } 1259 1260 /* 1261 * @implemented 1262 */ 1263 BOOLEAN 1264 NTAPI 1265 ExEnumHandleTable(IN PHANDLE_TABLE HandleTable, 1266 IN PEX_ENUM_HANDLE_CALLBACK EnumHandleProcedure, 1267 IN OUT PVOID Context, 1268 OUT PHANDLE EnumHandle OPTIONAL) 1269 { 1270 EXHANDLE Handle; 1271 PHANDLE_TABLE_ENTRY HandleTableEntry; 1272 BOOLEAN Result = FALSE; 1273 PAGED_CODE(); 1274 1275 /* Enter a critical region */ 1276 KeEnterCriticalRegion(); 1277 1278 /* Set the initial value and loop the entries */ 1279 Handle.Value = 0; 1280 while ((HandleTableEntry = ExpLookupHandleTableEntry(HandleTable, Handle))) 1281 { 1282 /* Validate the entry */ 1283 if ((HandleTableEntry->Object) && 1284 (HandleTableEntry->NextFreeTableEntry != -2)) 1285 { 1286 /* Lock the entry */ 1287 if (ExpLockHandleTableEntry(HandleTable, HandleTableEntry)) 1288 { 1289 /* Notify the callback routine */ 1290 Result = EnumHandleProcedure(HandleTableEntry, 1291 Handle.GenericHandleOverlay, 1292 Context); 1293 1294 /* Unlock it */ 1295 ExUnlockHandleTableEntry(HandleTable, HandleTableEntry); 1296 1297 /* Was this the one looked for? */ 1298 if (Result) 1299 { 1300 /* If so, return it if requested */ 1301 if (EnumHandle) *EnumHandle = Handle.GenericHandleOverlay; 1302 break; 1303 } 1304 } 1305 } 1306 1307 /* Go to the next entry */ 1308 Handle.Value += INDEX_TO_HANDLE_VALUE(1); 1309 } 1310 1311 /* Leave the critical region and return callback result */ 1312 KeLeaveCriticalRegion(); 1313 return Result; 1314 } 1315 1316 #if DBG && defined(KDBG) 1317 BOOLEAN ExpKdbgExtHandle(ULONG Argc, PCHAR Argv[]) 1318 { 1319 USHORT i; 1320 char *endptr; 1321 HANDLE ProcessId; 1322 EXHANDLE ExHandle; 1323 PLIST_ENTRY Entry; 1324 PEPROCESS Process; 1325 WCHAR KeyPath[256]; 1326 PFILE_OBJECT FileObject; 1327 PHANDLE_TABLE HandleTable; 1328 POBJECT_HEADER ObjectHeader; 1329 PHANDLE_TABLE_ENTRY TableEntry; 1330 ULONG NeededLength = 0; 1331 ULONG NameLength; 1332 PCM_KEY_CONTROL_BLOCK Kcb, CurrentKcb; 1333 POBJECT_HEADER_NAME_INFO ObjectNameInfo; 1334 1335 if (Argc > 1) 1336 { 1337 /* Get EPROCESS address or PID */ 1338 i = 0; 1339 while (Argv[1][i]) 1340 { 1341 if (!isdigit(Argv[1][i])) 1342 { 1343 i = 0; 1344 break; 1345 } 1346 1347 ++i; 1348 } 1349 1350 if (i == 0) 1351 { 1352 if (!KdbpGetHexNumber(Argv[1], (PVOID)&Process)) 1353 { 1354 KdbpPrint("Invalid parameter: %s\n", Argv[1]); 1355 return TRUE; 1356 } 1357 1358 /* In the end, we always want a PID */ 1359 ProcessId = PsGetProcessId(Process); 1360 } 1361 else 1362 { 1363 ProcessId = (HANDLE)strtoul(Argv[1], &endptr, 10); 1364 if (*endptr != '\0') 1365 { 1366 KdbpPrint("Invalid parameter: %s\n", Argv[1]); 1367 return TRUE; 1368 } 1369 } 1370 } 1371 else 1372 { 1373 ProcessId = PsGetCurrentProcessId(); 1374 } 1375 1376 for (Entry = HandleTableListHead.Flink; 1377 Entry != &HandleTableListHead; 1378 Entry = Entry->Flink) 1379 { 1380 /* Only return matching PID 1381 * 0 matches everything 1382 */ 1383 HandleTable = CONTAINING_RECORD(Entry, HANDLE_TABLE, HandleTableList); 1384 if (ProcessId != 0 && HandleTable->UniqueProcessId != ProcessId) 1385 { 1386 continue; 1387 } 1388 1389 KdbpPrint("\n"); 1390 1391 KdbpPrint("Handle table at %p with %d entries in use\n", HandleTable, HandleTable->HandleCount); 1392 1393 ExHandle.Value = 0; 1394 while ((TableEntry = ExpLookupHandleTableEntry(HandleTable, ExHandle))) 1395 { 1396 if ((TableEntry->Object) && 1397 (TableEntry->NextFreeTableEntry != -2)) 1398 { 1399 ObjectHeader = ObpGetHandleObject(TableEntry); 1400 1401 KdbpPrint("%p: Object: %p GrantedAccess: %x Entry: %p\n", ExHandle.Value, &ObjectHeader->Body, TableEntry->GrantedAccess, TableEntry); 1402 KdbpPrint("Object: %p Type: (%x) %wZ\n", &ObjectHeader->Body, ObjectHeader->Type, &ObjectHeader->Type->Name); 1403 KdbpPrint("\tObjectHeader: %p\n", ObjectHeader); 1404 KdbpPrint("\t\tHandleCount: %u PointerCount: %u\n", ObjectHeader->HandleCount, ObjectHeader->PointerCount); 1405 1406 /* Specific objects debug prints */ 1407 1408 /* For file, display path */ 1409 if (ObjectHeader->Type == IoFileObjectType) 1410 { 1411 FileObject = (PFILE_OBJECT)&ObjectHeader->Body; 1412 1413 KdbpPrint("\t\t\tName: %wZ\n", &FileObject->FileName); 1414 } 1415 1416 /* For directory, and win32k objects, display object name */ 1417 else if (ObjectHeader->Type == ObpDirectoryObjectType || 1418 ObjectHeader->Type == ExWindowStationObjectType || 1419 ObjectHeader->Type == ExDesktopObjectType || 1420 ObjectHeader->Type == MmSectionObjectType) 1421 { 1422 ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader); 1423 if (ObjectNameInfo != NULL && ObjectNameInfo->Name.Buffer != NULL) 1424 { 1425 KdbpPrint("\t\t\tName: %wZ\n", &ObjectNameInfo->Name); 1426 } 1427 } 1428 1429 /* For registry keys, display full path */ 1430 else if (ObjectHeader->Type == CmpKeyObjectType) 1431 { 1432 Kcb = ((PCM_KEY_BODY)&ObjectHeader->Body)->KeyControlBlock; 1433 if (!Kcb->Delete) 1434 { 1435 CurrentKcb = Kcb; 1436 1437 /* See: CmpQueryNameInformation() */ 1438 1439 while (CurrentKcb != NULL) 1440 { 1441 if (CurrentKcb->NameBlock->Compressed) 1442 NeededLength += CmpCompressedNameSize(CurrentKcb->NameBlock->Name, CurrentKcb->NameBlock->NameLength); 1443 else 1444 NeededLength += CurrentKcb->NameBlock->NameLength; 1445 1446 NeededLength += sizeof(OBJ_NAME_PATH_SEPARATOR); 1447 1448 CurrentKcb = CurrentKcb->ParentKcb; 1449 } 1450 1451 if (NeededLength < sizeof(KeyPath)) 1452 { 1453 CurrentKcb = Kcb; 1454 1455 while (CurrentKcb != NULL) 1456 { 1457 if (CurrentKcb->NameBlock->Compressed) 1458 { 1459 NameLength = CmpCompressedNameSize(CurrentKcb->NameBlock->Name, CurrentKcb->NameBlock->NameLength); 1460 CmpCopyCompressedName(&KeyPath[(NeededLength - NameLength)/sizeof(WCHAR)], 1461 NameLength, 1462 CurrentKcb->NameBlock->Name, 1463 CurrentKcb->NameBlock->NameLength); 1464 } 1465 else 1466 { 1467 NameLength = CurrentKcb->NameBlock->NameLength; 1468 RtlCopyMemory(&KeyPath[(NeededLength - NameLength)/sizeof(WCHAR)], 1469 CurrentKcb->NameBlock->Name, 1470 NameLength); 1471 } 1472 1473 NeededLength -= NameLength; 1474 NeededLength -= sizeof(OBJ_NAME_PATH_SEPARATOR); 1475 KeyPath[NeededLength/sizeof(WCHAR)] = OBJ_NAME_PATH_SEPARATOR; 1476 1477 CurrentKcb = CurrentKcb->ParentKcb; 1478 } 1479 } 1480 1481 KdbpPrint("\t\t\tName: %S\n", KeyPath); 1482 } 1483 } 1484 } 1485 1486 ExHandle.Value += INDEX_TO_HANDLE_VALUE(1); 1487 } 1488 } 1489 1490 return TRUE; 1491 } 1492 #endif 1493