Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

371 lines
11 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1999 - 2000
  6. //
  7. // File: moduleinfocache.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. // ModuleInfoCache.cpp: implementation of the CModuleInfoCache class.
  11. //
  12. //////////////////////////////////////////////////////////////////////
  13. #ifndef NO_STRICT
  14. #ifndef STRICT
  15. #define STRICT 1
  16. #endif
  17. #endif /* NO_STRICT */
  18. #include <WINDOWS.H>
  19. #include <STDIO.H>
  20. #include <TCHAR.H>
  21. #include "ModuleInfoCache.h"
  22. #include "ModuleInfo.h"
  23. #include "ModuleInfoNode.h"
  24. #include "ProgramOptions.h"
  25. #include "Globals.h"
  26. #include "UtilityFunctions.h"
  27. //////////////////////////////////////////////////////////////////////
  28. // Construction/Destruction
  29. //////////////////////////////////////////////////////////////////////
  30. CModuleInfoCache::CModuleInfoCache()
  31. {
  32. m_iModulesInCache = 0;
  33. m_iNumberOfErrors = 0;
  34. m_iTotalNumberOfModulesVerified = 0;
  35. m_lpModuleInfoNodeHead = NULL;
  36. }
  37. CModuleInfoCache::~CModuleInfoCache()
  38. {
  39. // Delete all the Module Info Objects...
  40. WaitForSingleObject(m_hModuleInfoCacheMutex, INFINITE);
  41. if (m_lpModuleInfoNodeHead)
  42. {
  43. CModuleInfoNode * lpModuleInfoNodePointer = m_lpModuleInfoNodeHead;
  44. CModuleInfoNode * lpModuleInfoNodePointerToDelete = m_lpModuleInfoNodeHead;
  45. // Traverse the linked list to the end..
  46. while (lpModuleInfoNodePointer)
  47. { // Keep looking for the end...
  48. // Advance our pointer to the next node...
  49. lpModuleInfoNodePointer = lpModuleInfoNodePointer->m_lpNextModuleInfoNode;
  50. // Delete the Module Info Object we have...
  51. delete lpModuleInfoNodePointerToDelete->m_lpModuleInfo;
  52. // Delete the Module Info Node Object behind us...
  53. delete lpModuleInfoNodePointerToDelete;
  54. // Set the node to delete to the current...
  55. lpModuleInfoNodePointerToDelete = lpModuleInfoNodePointer;
  56. }
  57. // Now, clear out the Head pointer...
  58. m_lpModuleInfoNodeHead = NULL;
  59. }
  60. // Be a good citizen and release the Mutex
  61. ReleaseMutex(m_hModuleInfoCacheMutex);
  62. // Now, close the Mutex
  63. if (m_hModuleInfoCacheMutex)
  64. {
  65. CloseHandle(m_hModuleInfoCacheMutex);
  66. m_hModuleInfoCacheMutex = NULL;
  67. }
  68. }
  69. // Search for the provided module path, return a pointer to the
  70. // ModuleInfo object if we find it...
  71. CModuleInfo * CModuleInfoCache::SearchForModuleInfoObject(LPTSTR tszModulePath)
  72. {
  73. if (tszModulePath == NULL)
  74. return NULL;
  75. CModuleInfo * lpModuleInfoObjectToReturn = NULL;
  76. // Search all the Module Info Objects...
  77. WaitForSingleObject(m_hModuleInfoCacheMutex, INFINITE);
  78. if (m_lpModuleInfoNodeHead)
  79. {
  80. CModuleInfoNode * lpCurrentModuleInfoNodePointer = m_lpModuleInfoNodeHead;
  81. CModuleInfoNode * lpParentModuleInfoNodePointer = NULL;
  82. DWORD dwParentModuleInfoRefCount = 0;
  83. DWORD dwModuleInfoRefCount = 0;
  84. // Traverse the linked list to the end..
  85. while (lpCurrentModuleInfoNodePointer )
  86. {
  87. // Do we have a match?
  88. if ( 0 == _tcscmp(tszModulePath, lpCurrentModuleInfoNodePointer->m_lpModuleInfo->GetModulePath()) )
  89. {
  90. // Yee haa... We have a match!!!
  91. lpModuleInfoObjectToReturn = lpCurrentModuleInfoNodePointer->m_lpModuleInfo;
  92. // Increment the refcount... of the new Object...
  93. dwModuleInfoRefCount = lpModuleInfoObjectToReturn->AddRef();
  94. #ifdef _DEBUG_MODCACHE
  95. _tprintf(TEXT("MODULE CACHE: Module FOUND in Cache [%s] (New Ref Count = %d)\n"), tszModulePath, dwModuleInfoRefCount);
  96. #endif
  97. // If we have a parent... and we find that it's refcount is below ours
  98. // we'll want to move ourself into the correct position...
  99. if ( lpParentModuleInfoNodePointer &&
  100. ( dwParentModuleInfoRefCount < dwModuleInfoRefCount )
  101. )
  102. {
  103. // First... pop us off the list...
  104. lpParentModuleInfoNodePointer->m_lpNextModuleInfoNode =
  105. lpCurrentModuleInfoNodePointer->m_lpNextModuleInfoNode;
  106. // Set the Parent Node pointer to NULL (so we can tell if there is a parent)
  107. lpParentModuleInfoNodePointer = NULL;
  108. // Now, starting from the top of the list... figure out where to stuff us...
  109. CModuleInfoNode * lpTempModuleInfoNodePointer = m_lpModuleInfoNodeHead;
  110. // Keep looking...
  111. while (lpTempModuleInfoNodePointer)
  112. {
  113. // We're looking for a place where our ref count is greater than
  114. // the node we're pointing at...
  115. if ( dwModuleInfoRefCount >
  116. lpTempModuleInfoNodePointer->m_lpModuleInfo->GetRefCount())
  117. {
  118. // Bingo...
  119. // Do we have the highest refcount?
  120. if (lpParentModuleInfoNodePointer == NULL)
  121. {
  122. // We are to become the head...
  123. // Make our node point to where the head currently points.
  124. lpCurrentModuleInfoNodePointer->m_lpNextModuleInfoNode = m_lpModuleInfoNodeHead;
  125. // Set the current NodeHead to ours...
  126. m_lpModuleInfoNodeHead = lpCurrentModuleInfoNodePointer;
  127. } else
  128. {
  129. // We're not the head...
  130. // Save where the parent currently points...
  131. lpCurrentModuleInfoNodePointer->m_lpNextModuleInfoNode = lpParentModuleInfoNodePointer->m_lpNextModuleInfoNode;
  132. // Set the parent to point to us...
  133. lpParentModuleInfoNodePointer->m_lpNextModuleInfoNode = lpCurrentModuleInfoNodePointer;
  134. }
  135. goto cleanup;
  136. }
  137. // Save the old pointer (it's now the parent)
  138. lpParentModuleInfoNodePointer = lpTempModuleInfoNodePointer;
  139. // Let's try the next one...
  140. lpTempModuleInfoNodePointer = lpTempModuleInfoNodePointer->m_lpNextModuleInfoNode;
  141. }
  142. }
  143. break;
  144. }
  145. // Save parent location (we need it for popping our object from the list)
  146. lpParentModuleInfoNodePointer = lpCurrentModuleInfoNodePointer ;
  147. // Save our parent's ref count...
  148. dwParentModuleInfoRefCount = lpCurrentModuleInfoNodePointer->m_lpModuleInfo->GetRefCount();
  149. // Advance to the next object...
  150. lpCurrentModuleInfoNodePointer = lpCurrentModuleInfoNodePointer->m_lpNextModuleInfoNode;
  151. }
  152. }
  153. cleanup:
  154. // Be a good citizen and release the Mutex
  155. ReleaseMutex(m_hModuleInfoCacheMutex);
  156. #ifdef _DEBUG_MODCACHE
  157. if (!lpModuleInfoObjectToReturn)
  158. _tprintf(TEXT("MODULE CACHE: Module not found in Cache [%s]\n"), tszModulePath);
  159. #endif
  160. return lpModuleInfoObjectToReturn;
  161. }
  162. /***
  163. ** CModuleInfoCache::AddNewModuleInfoObject()
  164. **
  165. ** This routine accepts a path to the module, and either returns the
  166. ** Module Info object from the cache, or creates a new object that needs
  167. ** to be populated.
  168. */
  169. CModuleInfo * CModuleInfoCache::AddNewModuleInfoObject(LPTSTR tszModulePath, bool * pfNew)
  170. {
  171. if (tszModulePath == NULL)
  172. return NULL;
  173. CModuleInfo * lpModuleInfoObjectToReturn = NULL;
  174. CModuleInfoNode * lpModuleInfoNode = NULL;
  175. *pfNew = false;
  176. // Acquire Mutex object to protect the linked-list...
  177. WaitForSingleObject(m_hModuleInfoCacheMutex, INFINITE);
  178. _tcsupr(tszModulePath); // Upper case the module path... makes it faster on search...
  179. lpModuleInfoObjectToReturn = SearchForModuleInfoObject(tszModulePath);
  180. if (lpModuleInfoObjectToReturn)
  181. {
  182. // Success... since it already exists, we just return this object...
  183. goto cleanup;
  184. }
  185. // We need to create a new object then...
  186. lpModuleInfoObjectToReturn = new CModuleInfo();
  187. if (NULL == lpModuleInfoObjectToReturn)
  188. goto error_cleanup; // This is bad... get out...
  189. // Set the module path (that's the only thing we have to set at this exact moment
  190. if (!lpModuleInfoObjectToReturn->SetModulePath(tszModulePath))
  191. goto cleanup;
  192. *pfNew = true;
  193. // Now, create a new ModuleInfoNode, and add this new object to it...
  194. lpModuleInfoNode = new CModuleInfoNode(lpModuleInfoObjectToReturn);
  195. if (NULL == lpModuleInfoNode)
  196. goto error_cleanup;
  197. if (!lpModuleInfoNode->AddModuleInfoNodeToTail(&m_lpModuleInfoNodeHead))
  198. goto error_cleanup;
  199. #ifdef _DEBUG_MODCACHE
  200. _tprintf(TEXT("MODULE CACHE: Module added to Cache [%s]\n"), tszModulePath);
  201. #endif
  202. InterlockedIncrement(&m_iModulesInCache);
  203. // Success...
  204. goto cleanup;
  205. error_cleanup:
  206. if (lpModuleInfoObjectToReturn)
  207. {
  208. delete lpModuleInfoObjectToReturn;
  209. lpModuleInfoObjectToReturn = NULL;
  210. }
  211. cleanup:
  212. // Release the Mutex...
  213. ReleaseMutex(m_hModuleInfoCacheMutex);
  214. return lpModuleInfoObjectToReturn;
  215. }
  216. bool CModuleInfoCache::Initialize(CSymbolVerification * lpSymbolVerification)
  217. {
  218. // Let's save the symbol verification object here...
  219. m_lpSymbolVerification = lpSymbolVerification;
  220. m_hModuleInfoCacheMutex = CreateMutex(NULL, FALSE, NULL);
  221. if (m_hModuleInfoCacheMutex == NULL)
  222. return false;
  223. return true;
  224. }
  225. bool CModuleInfoCache::VerifySymbols(bool fQuietMode)
  226. {
  227. enum { iTotalNumberOfDotsToPrint = 60 };
  228. unsigned int iDotsPrinted = 0;
  229. unsigned int iDotsToPrint;
  230. long iTotalNumberOfModulesProcessed = 0;
  231. unsigned int iTotalNumberOfModules = GetNumberOfModulesInCache();
  232. bool fDebugSearchPaths = g_lpProgramOptions->fDebugSearchPaths();
  233. bool fBadSymbol = true;
  234. // Acquire Mutex object to protect the linked-list...
  235. WaitForSingleObject(m_hModuleInfoCacheMutex, INFINITE);
  236. if (m_lpModuleInfoNodeHead)
  237. {
  238. CModuleInfoNode * lpCurrentModuleInfoNode = m_lpModuleInfoNodeHead;
  239. while (lpCurrentModuleInfoNode)
  240. {
  241. fBadSymbol = true;
  242. // We have a node... verify the Module Info for it...
  243. if (lpCurrentModuleInfoNode->m_lpModuleInfo)
  244. {
  245. #ifdef _DEBUG_MODCACHE
  246. _tprintf(TEXT("MODULE CACHE: Verifying Symbols for [%s] (Refcount=%d)\n"),
  247. lpCurrentModuleInfoNode->m_lpModuleInfo->GetModulePath(),
  248. lpCurrentModuleInfoNode->m_lpModuleInfo->GetRefCount() );
  249. #endif
  250. if (fDebugSearchPaths && lpCurrentModuleInfoNode->m_lpModuleInfo->GetPESymbolInformation() != CModuleInfo::SYMBOL_INFORMATION_UNKNOWN)
  251. {
  252. CUtilityFunctions::OutputLineOfDashes();
  253. _tprintf(TEXT("Verifying Symbols for [%s]\n"), lpCurrentModuleInfoNode->m_lpModuleInfo->GetModulePath());
  254. CUtilityFunctions::OutputLineOfDashes();
  255. }
  256. // Invoke the ModuleInfo's VerifySymbols method... the cache doesn't know
  257. // how to verify symbols, but the ModuleInfo knows how to get this done...
  258. fBadSymbol = !lpCurrentModuleInfoNode->m_lpModuleInfo->VerifySymbols(m_lpSymbolVerification) || !lpCurrentModuleInfoNode->m_lpModuleInfo->GoodSymbolNotFound();
  259. // Increment total number of modules verified
  260. iTotalNumberOfModulesProcessed++;
  261. // Increment total number of modules verified for actual PE images... only...
  262. if (lpCurrentModuleInfoNode->m_lpModuleInfo->GetPESymbolInformation() != CModuleInfo::SYMBOL_INFORMATION_UNKNOWN)
  263. {
  264. InterlockedIncrement(&m_iTotalNumberOfModulesVerified);
  265. if (fBadSymbol)
  266. InterlockedIncrement(&m_iNumberOfErrors);
  267. }
  268. if (!fQuietMode && !fDebugSearchPaths)
  269. {
  270. // Let's see if we should print a status dot... there will be room for 80 dots
  271. // but we'll just print 60 for now...
  272. iDotsToPrint = (iTotalNumberOfDotsToPrint * iTotalNumberOfModulesProcessed) / iTotalNumberOfModules;
  273. // Print out any dots if we need to...
  274. while (iDotsToPrint > iDotsPrinted)
  275. {
  276. _tprintf(TEXT("."));
  277. iDotsPrinted++;
  278. }
  279. }
  280. }
  281. lpCurrentModuleInfoNode = lpCurrentModuleInfoNode->m_lpNextModuleInfoNode;
  282. }
  283. if (!fQuietMode && iDotsPrinted && !fDebugSearchPaths)
  284. _tprintf(TEXT("\n\n"));
  285. }
  286. // Be a good citizen and release the Mutex
  287. ReleaseMutex(m_hModuleInfoCacheMutex);
  288. return true;
  289. }