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