//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1999 - 2000 // // File: moduleinfocache.cpp // //-------------------------------------------------------------------------- // ModuleInfoCache.cpp: implementation of the CModuleInfoCache class. // ////////////////////////////////////////////////////////////////////// #ifndef NO_STRICT #ifndef STRICT #define STRICT 1 #endif #endif /* NO_STRICT */ #include #include #include #include "ModuleInfoCache.h" #include "ModuleInfo.h" #include "ModuleInfoNode.h" #include "ProgramOptions.h" #include "Globals.h" #include "UtilityFunctions.h" ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CModuleInfoCache::CModuleInfoCache() { m_iModulesInCache = 0; m_iNumberOfErrors = 0; m_iTotalNumberOfModulesVerified = 0; m_lpModuleInfoNodeHead = NULL; } CModuleInfoCache::~CModuleInfoCache() { // Delete all the Module Info Objects... WaitForSingleObject(m_hModuleInfoCacheMutex, INFINITE); if (m_lpModuleInfoNodeHead) { CModuleInfoNode * lpModuleInfoNodePointer = m_lpModuleInfoNodeHead; CModuleInfoNode * lpModuleInfoNodePointerToDelete = m_lpModuleInfoNodeHead; // Traverse the linked list to the end.. while (lpModuleInfoNodePointer) { // Keep looking for the end... // Advance our pointer to the next node... lpModuleInfoNodePointer = lpModuleInfoNodePointer->m_lpNextModuleInfoNode; // Delete the Module Info Object we have... delete lpModuleInfoNodePointerToDelete->m_lpModuleInfo; // Delete the Module Info Node Object behind us... delete lpModuleInfoNodePointerToDelete; // Set the node to delete to the current... lpModuleInfoNodePointerToDelete = lpModuleInfoNodePointer; } // Now, clear out the Head pointer... m_lpModuleInfoNodeHead = NULL; } // Be a good citizen and release the Mutex ReleaseMutex(m_hModuleInfoCacheMutex); // Now, close the Mutex if (m_hModuleInfoCacheMutex) { CloseHandle(m_hModuleInfoCacheMutex); m_hModuleInfoCacheMutex = NULL; } } // Search for the provided module path, return a pointer to the // ModuleInfo object if we find it... CModuleInfo * CModuleInfoCache::SearchForModuleInfoObject(LPTSTR tszModulePath) { if (tszModulePath == NULL) return NULL; CModuleInfo * lpModuleInfoObjectToReturn = NULL; // Search all the Module Info Objects... WaitForSingleObject(m_hModuleInfoCacheMutex, INFINITE); if (m_lpModuleInfoNodeHead) { CModuleInfoNode * lpCurrentModuleInfoNodePointer = m_lpModuleInfoNodeHead; CModuleInfoNode * lpParentModuleInfoNodePointer = NULL; DWORD dwParentModuleInfoRefCount = 0; DWORD dwModuleInfoRefCount = 0; // Traverse the linked list to the end.. while (lpCurrentModuleInfoNodePointer ) { // Do we have a match? if ( 0 == _tcscmp(tszModulePath, lpCurrentModuleInfoNodePointer->m_lpModuleInfo->GetModulePath()) ) { // Yee haa... We have a match!!! lpModuleInfoObjectToReturn = lpCurrentModuleInfoNodePointer->m_lpModuleInfo; // Increment the refcount... of the new Object... dwModuleInfoRefCount = lpModuleInfoObjectToReturn->AddRef(); #ifdef _DEBUG_MODCACHE _tprintf(TEXT("MODULE CACHE: Module FOUND in Cache [%s] (New Ref Count = %d)\n"), tszModulePath, dwModuleInfoRefCount); #endif // If we have a parent... and we find that it's refcount is below ours // we'll want to move ourself into the correct position... if ( lpParentModuleInfoNodePointer && ( dwParentModuleInfoRefCount < dwModuleInfoRefCount ) ) { // First... pop us off the list... lpParentModuleInfoNodePointer->m_lpNextModuleInfoNode = lpCurrentModuleInfoNodePointer->m_lpNextModuleInfoNode; // Set the Parent Node pointer to NULL (so we can tell if there is a parent) lpParentModuleInfoNodePointer = NULL; // Now, starting from the top of the list... figure out where to stuff us... CModuleInfoNode * lpTempModuleInfoNodePointer = m_lpModuleInfoNodeHead; // Keep looking... while (lpTempModuleInfoNodePointer) { // We're looking for a place where our ref count is greater than // the node we're pointing at... if ( dwModuleInfoRefCount > lpTempModuleInfoNodePointer->m_lpModuleInfo->GetRefCount()) { // Bingo... // Do we have the highest refcount? if (lpParentModuleInfoNodePointer == NULL) { // We are to become the head... // Make our node point to where the head currently points. lpCurrentModuleInfoNodePointer->m_lpNextModuleInfoNode = m_lpModuleInfoNodeHead; // Set the current NodeHead to ours... m_lpModuleInfoNodeHead = lpCurrentModuleInfoNodePointer; } else { // We're not the head... // Save where the parent currently points... lpCurrentModuleInfoNodePointer->m_lpNextModuleInfoNode = lpParentModuleInfoNodePointer->m_lpNextModuleInfoNode; // Set the parent to point to us... lpParentModuleInfoNodePointer->m_lpNextModuleInfoNode = lpCurrentModuleInfoNodePointer; } goto cleanup; } // Save the old pointer (it's now the parent) lpParentModuleInfoNodePointer = lpTempModuleInfoNodePointer; // Let's try the next one... lpTempModuleInfoNodePointer = lpTempModuleInfoNodePointer->m_lpNextModuleInfoNode; } } break; } // Save parent location (we need it for popping our object from the list) lpParentModuleInfoNodePointer = lpCurrentModuleInfoNodePointer ; // Save our parent's ref count... dwParentModuleInfoRefCount = lpCurrentModuleInfoNodePointer->m_lpModuleInfo->GetRefCount(); // Advance to the next object... lpCurrentModuleInfoNodePointer = lpCurrentModuleInfoNodePointer->m_lpNextModuleInfoNode; } } cleanup: // Be a good citizen and release the Mutex ReleaseMutex(m_hModuleInfoCacheMutex); #ifdef _DEBUG_MODCACHE if (!lpModuleInfoObjectToReturn) _tprintf(TEXT("MODULE CACHE: Module not found in Cache [%s]\n"), tszModulePath); #endif return lpModuleInfoObjectToReturn; } /*** ** CModuleInfoCache::AddNewModuleInfoObject() ** ** This routine accepts a path to the module, and either returns the ** Module Info object from the cache, or creates a new object that needs ** to be populated. */ CModuleInfo * CModuleInfoCache::AddNewModuleInfoObject(LPTSTR tszModulePath, bool * pfNew) { if (tszModulePath == NULL) return NULL; CModuleInfo * lpModuleInfoObjectToReturn = NULL; CModuleInfoNode * lpModuleInfoNode = NULL; *pfNew = false; // Acquire Mutex object to protect the linked-list... WaitForSingleObject(m_hModuleInfoCacheMutex, INFINITE); _tcsupr(tszModulePath); // Upper case the module path... makes it faster on search... lpModuleInfoObjectToReturn = SearchForModuleInfoObject(tszModulePath); if (lpModuleInfoObjectToReturn) { // Success... since it already exists, we just return this object... goto cleanup; } // We need to create a new object then... lpModuleInfoObjectToReturn = new CModuleInfo(); if (NULL == lpModuleInfoObjectToReturn) goto error_cleanup; // This is bad... get out... // Set the module path (that's the only thing we have to set at this exact moment if (!lpModuleInfoObjectToReturn->SetModulePath(tszModulePath)) goto cleanup; *pfNew = true; // Now, create a new ModuleInfoNode, and add this new object to it... lpModuleInfoNode = new CModuleInfoNode(lpModuleInfoObjectToReturn); if (NULL == lpModuleInfoNode) goto error_cleanup; if (!lpModuleInfoNode->AddModuleInfoNodeToTail(&m_lpModuleInfoNodeHead)) goto error_cleanup; #ifdef _DEBUG_MODCACHE _tprintf(TEXT("MODULE CACHE: Module added to Cache [%s]\n"), tszModulePath); #endif InterlockedIncrement(&m_iModulesInCache); // Success... goto cleanup; error_cleanup: if (lpModuleInfoObjectToReturn) { delete lpModuleInfoObjectToReturn; lpModuleInfoObjectToReturn = NULL; } cleanup: // Release the Mutex... ReleaseMutex(m_hModuleInfoCacheMutex); return lpModuleInfoObjectToReturn; } bool CModuleInfoCache::Initialize(CSymbolVerification * lpSymbolVerification) { // Let's save the symbol verification object here... m_lpSymbolVerification = lpSymbolVerification; m_hModuleInfoCacheMutex = CreateMutex(NULL, FALSE, NULL); if (m_hModuleInfoCacheMutex == NULL) return false; return true; } bool CModuleInfoCache::VerifySymbols(bool fQuietMode) { enum { iTotalNumberOfDotsToPrint = 60 }; unsigned int iDotsPrinted = 0; unsigned int iDotsToPrint; long iTotalNumberOfModulesProcessed = 0; unsigned int iTotalNumberOfModules = GetNumberOfModulesInCache(); bool fDebugSearchPaths = g_lpProgramOptions->fDebugSearchPaths(); bool fBadSymbol = true; // Acquire Mutex object to protect the linked-list... WaitForSingleObject(m_hModuleInfoCacheMutex, INFINITE); if (m_lpModuleInfoNodeHead) { CModuleInfoNode * lpCurrentModuleInfoNode = m_lpModuleInfoNodeHead; while (lpCurrentModuleInfoNode) { fBadSymbol = true; // We have a node... verify the Module Info for it... if (lpCurrentModuleInfoNode->m_lpModuleInfo) { #ifdef _DEBUG_MODCACHE _tprintf(TEXT("MODULE CACHE: Verifying Symbols for [%s] (Refcount=%d)\n"), lpCurrentModuleInfoNode->m_lpModuleInfo->GetModulePath(), lpCurrentModuleInfoNode->m_lpModuleInfo->GetRefCount() ); #endif if (fDebugSearchPaths && lpCurrentModuleInfoNode->m_lpModuleInfo->GetPESymbolInformation() != CModuleInfo::SYMBOL_INFORMATION_UNKNOWN) { CUtilityFunctions::OutputLineOfDashes(); _tprintf(TEXT("Verifying Symbols for [%s]\n"), lpCurrentModuleInfoNode->m_lpModuleInfo->GetModulePath()); CUtilityFunctions::OutputLineOfDashes(); } // Invoke the ModuleInfo's VerifySymbols method... the cache doesn't know // how to verify symbols, but the ModuleInfo knows how to get this done... fBadSymbol = !lpCurrentModuleInfoNode->m_lpModuleInfo->VerifySymbols(m_lpSymbolVerification) || !lpCurrentModuleInfoNode->m_lpModuleInfo->GoodSymbolNotFound(); // Increment total number of modules verified iTotalNumberOfModulesProcessed++; // Increment total number of modules verified for actual PE images... only... if (lpCurrentModuleInfoNode->m_lpModuleInfo->GetPESymbolInformation() != CModuleInfo::SYMBOL_INFORMATION_UNKNOWN) { InterlockedIncrement(&m_iTotalNumberOfModulesVerified); if (fBadSymbol) InterlockedIncrement(&m_iNumberOfErrors); } if (!fQuietMode && !fDebugSearchPaths) { // Let's see if we should print a status dot... there will be room for 80 dots // but we'll just print 60 for now... iDotsToPrint = (iTotalNumberOfDotsToPrint * iTotalNumberOfModulesProcessed) / iTotalNumberOfModules; // Print out any dots if we need to... while (iDotsToPrint > iDotsPrinted) { _tprintf(TEXT(".")); iDotsPrinted++; } } } lpCurrentModuleInfoNode = lpCurrentModuleInfoNode->m_lpNextModuleInfoNode; } if (!fQuietMode && iDotsPrinted && !fDebugSearchPaths) _tprintf(TEXT("\n\n")); } // Be a good citizen and release the Mutex ReleaseMutex(m_hModuleInfoCacheMutex); return true; }