xref: /reactos/ntoskrnl/ex/handle.c (revision f59c58d8)
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