PPH_SYMBOL_PROVIDER PhCreateSymbolProvider( _In_opt_ HANDLE ProcessId ) { PPH_SYMBOL_PROVIDER symbolProvider; if (!NT_SUCCESS(PhCreateObject( &symbolProvider, sizeof(PH_SYMBOL_PROVIDER), 0, PhSymbolProviderType ))) return NULL; InitializeListHead(&symbolProvider->ModulesListHead); PhInitializeQueuedLock(&symbolProvider->ModulesListLock); PhInitializeAvlTree(&symbolProvider->ModulesSet, PhpSymbolModuleCompareFunction); PhInitializeCallback(&symbolProvider->EventCallback); if (ProcessId) { static ACCESS_MASK accesses[] = { STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xfff, // pre-Vista full access PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_DUP_HANDLE, PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, MAXIMUM_ALLOWED }; ULONG i; symbolProvider->IsRealHandle = FALSE; // Try to open the process with many different accesses. // This handle will be re-used when walking stacks, and doing // various other things. for (i = 0; i < sizeof(accesses) / sizeof(ACCESS_MASK); i++) { if (NT_SUCCESS(PhOpenProcess(&symbolProvider->ProcessHandle, accesses[i], ProcessId))) { symbolProvider->IsRealHandle = TRUE; break; } } } else { symbolProvider->IsRealHandle = FALSE; } if (!symbolProvider->IsRealHandle) { HANDLE fakeHandle; // Just generate a fake handle. fakeHandle = (HANDLE)_InterlockedExchangeAddPointer((PLONG_PTR)&PhNextFakeHandle, 4); // Add one to make sure it isn't divisible // by 4 (so it can't be mistaken for a real // handle). fakeHandle = (HANDLE)((ULONG_PTR)fakeHandle + 1); symbolProvider->ProcessHandle = fakeHandle; } symbolProvider->IsRegistered = FALSE; #ifdef PH_SYMBOL_PROVIDER_DELAY_INIT PhInitializeInitOnce(&symbolProvider->InitOnce); #else PhpRegisterSymbolProvider(symbolProvider); #endif return symbolProvider; }
/** * Dequeues the appropriate number of wait blocks in * a queued lock. * * \param QueuedLock A queued lock. * \param Value The current value of the queued lock. * \param IgnoreOwned TRUE to ignore lock state, FALSE * to conduct normal checks. * \param WakeAll TRUE to remove all wait blocks, FALSE * to decide based on the wait block type. */ FORCEINLINE PPH_QUEUED_WAIT_BLOCK PhpPrepareToWakeQueuedLock( __inout PPH_QUEUED_LOCK QueuedLock, __in ULONG_PTR Value, __in BOOLEAN IgnoreOwned, __in BOOLEAN WakeAll ) { ULONG_PTR value; ULONG_PTR newValue; PPH_QUEUED_WAIT_BLOCK waitBlock; PPH_QUEUED_WAIT_BLOCK firstWaitBlock; PPH_QUEUED_WAIT_BLOCK lastWaitBlock; PPH_QUEUED_WAIT_BLOCK previousWaitBlock; value = Value; while (TRUE) { // If there are multiple shared owners, no one is going // to wake waiters since the lock would still be owned. // Also if there are multiple shared owners they may be // traversing the list. While that is safe when // done concurrently with list optimization, we may be // removing and waking waiters. assert(!(value & PH_QUEUED_LOCK_MULTIPLE_SHARED)); assert(IgnoreOwned || (value & PH_QUEUED_LOCK_TRAVERSING)); // There's no point in waking a waiter if the lock // is owned. Clear the traversing bit. while (!IgnoreOwned && (value & PH_QUEUED_LOCK_OWNED)) { newValue = value - PH_QUEUED_LOCK_TRAVERSING; if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer( (PPVOID)&QueuedLock->Value, (PVOID)newValue, (PVOID)value )) == value) return NULL; value = newValue; } // Finish up any needed optimization (setting the // Previous pointers) while finding the last wait // block. waitBlock = PhGetQueuedLockWaitBlock(value); firstWaitBlock = waitBlock; while (TRUE) { lastWaitBlock = waitBlock->Last; if (lastWaitBlock) { waitBlock = lastWaitBlock; break; } previousWaitBlock = waitBlock; waitBlock = waitBlock->Next; waitBlock->Previous = previousWaitBlock; } // Unlink the relevant wait blocks and clear the // traversing bit before we wake waiters. if ( !WakeAll && (waitBlock->Flags & PH_QUEUED_WAITER_EXCLUSIVE) && (previousWaitBlock = waitBlock->Previous) ) { // We have an exclusive waiter and there are // multiple waiters. // We'll only be waking this waiter. // Unlink the wait block from the list. // Although other wait blocks may have their // Last pointers set to this wait block, // the algorithm to find the last wait block // will stop here. Likewise the Next pointers // are never followed beyond this point, so // we don't need to clear those. firstWaitBlock->Last = previousWaitBlock; // Make sure we only wake this waiter. waitBlock->Previous = NULL; if (!IgnoreOwned) { // Clear the traversing bit. _InterlockedExchangeAddPointer((PLONG_PTR)&QueuedLock->Value, -(LONG_PTR)PH_QUEUED_LOCK_TRAVERSING); } break; } else { // We're waking an exclusive waiter and there // is only one waiter, or we are waking // a shared waiter and possibly others. newValue = 0; if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer( (PPVOID)&QueuedLock->Value, (PVOID)newValue, (PVOID)value )) == value) break; // Someone changed the lock (acquired it or // pushed a wait block). value = newValue; } } return waitBlock; }