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.

507 lines
11 KiB

  1. #include "pch.h"
  2. #pragma hdrstop
  3. #include "modset.h"
  4. #include "modtree.h"
  5. #include "ncstl.h"
  6. struct GMBCONTEXT
  7. {
  8. // The tree to reference for generating the set.
  9. //
  10. IN const CModuleTree* pTree;
  11. // The module to start with when generating the set.
  12. //
  13. IN const CModule* pSourceMod;
  14. // INS_FLAGS to use when adding DepChain to the set.
  15. //
  16. IN DWORD dwFlags;
  17. // The module list set to generate based on pSourceMod.
  18. //
  19. IN OUT CModuleListSet* pSet;
  20. // The result of the operation.
  21. //
  22. OUT HRESULT hr;
  23. // This module list is built up via recursion. It is
  24. // temporary. It represents a depenedency chain sourced
  25. // at pSourceMod. It is added to the set when the depth
  26. // of the chain (or a circular reference) is detected.
  27. //
  28. CModuleList DepChain;
  29. };
  30. VOID
  31. GetModuleBindings (
  32. IN const CModule* pMod,
  33. IN OUT GMBCONTEXT* pCtx)
  34. {
  35. BOOL fFoundOne = FALSE;
  36. const CModuleTreeEntry* pScan;
  37. Assert (pCtx);
  38. Assert (pCtx->pSourceMod);
  39. Assert (pCtx->pSet);
  40. Assert (pCtx->pTree);
  41. // Append this module to te end of the context's working
  42. // dependency chain.
  43. //
  44. pCtx->hr = pCtx->DepChain.HrInsertModule (pMod,
  45. INS_ASSERT_IF_DUP | INS_APPEND);
  46. if (S_OK != pCtx->hr)
  47. {
  48. return;
  49. }
  50. // For all rows in the tree where the module is the one passed in...
  51. //
  52. for (pScan = pCtx->pTree->PFindFirstEntryWithModule (pMod);
  53. (pScan != pCtx->pTree->end()) && (pScan->m_pModule == pMod);
  54. pScan++)
  55. {
  56. fFoundOne = TRUE;
  57. // Detect circular import chains.
  58. //
  59. if (pCtx->DepChain.FLinearFindModuleByPointer (pScan->m_pImportModule))
  60. {
  61. pCtx->DepChain.m_fCircular = TRUE;
  62. continue;
  63. }
  64. GetModuleBindings (pScan->m_pImportModule, pCtx);
  65. if (S_OK != pCtx->hr)
  66. {
  67. return;
  68. }
  69. }
  70. // If we didnt find any rows with pMod as a module, it means we
  71. // hit the depth of the dependency chain. Time to add it to the set
  72. // unless this is the original module we were asked to find the
  73. // set for.
  74. //
  75. if (!fFoundOne && (pMod != pCtx->pSourceMod))
  76. {
  77. CHAR pszBuf [4096];
  78. ULONG cch = celems(pszBuf);
  79. pCtx->DepChain.FDumpToString (pszBuf, &cch);
  80. strcat(pszBuf, "\n");
  81. printf(pszBuf);
  82. pCtx->hr = pCtx->pSet->HrAddModuleList (&pCtx->DepChain,
  83. INS_APPEND | pCtx->dwFlags);
  84. }
  85. const CModule* pRemoved;
  86. pRemoved = pCtx->DepChain.RemoveLastModule();
  87. // This should be the component we appened above.
  88. //
  89. Assert (pRemoved == pMod);
  90. }
  91. CModuleTree::~CModuleTree ()
  92. {
  93. FreeCollectionAndItem (Modules);
  94. }
  95. HRESULT
  96. CModuleTree::HrAddEntry (
  97. IN CModule* pMod,
  98. IN CModule* pImport,
  99. IN DWORD dwFlags)
  100. {
  101. HRESULT hr;
  102. iterator InsertPosition = NULL;
  103. CModuleTreeEntry* pEntry;
  104. Assert (pMod);
  105. Assert (pImport);
  106. if (size() == capacity())
  107. {
  108. //fprintf(stderr, "growing module tree buffer\n");
  109. __try
  110. {
  111. reserve (size() + 16384);
  112. }
  113. __except(EXCEPTION_EXECUTE_HANDLER)
  114. {
  115. return E_OUTOFMEMORY;
  116. }
  117. }
  118. hr = S_OK;
  119. //pEntry = PFindFirstEntryAfterModuleGroup (pMod);
  120. pEntry = PBinarySearchEntryByModule (pMod, &InsertPosition);
  121. if (pEntry != end())
  122. {
  123. Assert (pEntry);
  124. CModuleTreeEntry* pScan;
  125. // Found an entry with a matching module. Need to scan backwards
  126. // in the module group looking for a duplicate. If not found,
  127. // Scan to the end looking for a duplicate and if we reach the
  128. // end of the group, we can insert this entry there.
  129. //
  130. pScan = pEntry;
  131. while (pScan != begin())
  132. {
  133. pScan--;
  134. if (pScan->m_pModule != pMod)
  135. {
  136. // Left the group without finding a dupliate.
  137. //
  138. break;
  139. }
  140. if (pScan->m_pImportModule == pImport)
  141. {
  142. // Don't insert duplicate entries.
  143. //
  144. return S_OK;
  145. }
  146. }
  147. Assert (pMod == pEntry->m_pModule);
  148. while (pEntry != end() && pEntry->m_pModule == pMod)
  149. {
  150. // Don't insert duplicate entries.
  151. //
  152. if (pEntry->m_pImportModule == pImport)
  153. {
  154. return S_OK;
  155. }
  156. pEntry++;
  157. }
  158. // Looks like we'll be inserting it.
  159. //
  160. InsertPosition = pEntry;
  161. }
  162. else
  163. {
  164. // InsertPosition is the correct insertion point.
  165. //
  166. Assert (InsertPosition);
  167. }
  168. __try
  169. {
  170. CModuleTreeEntry Entry;
  171. Entry.m_pModule = pMod;
  172. Entry.m_pImportModule = pImport;
  173. Entry.m_dwFlags = dwFlags;
  174. Assert (InsertPosition);
  175. insert (InsertPosition, Entry);
  176. Assert (S_OK == hr);
  177. DbgVerifySorted();
  178. }
  179. __except(EXCEPTION_EXECUTE_HANDLER)
  180. {
  181. hr = E_OUTOFMEMORY;
  182. }
  183. return hr;
  184. }
  185. HRESULT
  186. CModuleTree::HrGetModuleBindings (
  187. IN const CModule* pMod,
  188. IN DWORD dwFlags /* GMB_FLAGS */,
  189. OUT CModuleListSet* pSet) const
  190. {
  191. GMBCONTEXT Ctx;
  192. Assert (pMod);
  193. Assert (dwFlags);
  194. Assert (pSet);
  195. // Initialize the output parameter.
  196. //
  197. if (!(dwFlags & GMBF_ADD_TO_MLSET))
  198. {
  199. pSet->clear();
  200. }
  201. // Initialize members of the context structure for recursion.
  202. //
  203. ZeroMemory (&Ctx, sizeof(Ctx));
  204. Ctx.pTree = this;
  205. Ctx.pSourceMod = pMod;
  206. Ctx.dwFlags = (dwFlags & GMBF_ADD_TO_MLSET)
  207. ? INS_IGNORE_IF_DUP
  208. : INS_ASSERT_IF_DUP;
  209. Ctx.pSet = pSet;
  210. GetModuleBindings (pMod, &Ctx);
  211. return Ctx.hr;
  212. }
  213. CModuleTreeEntry*
  214. CModuleTree::PBinarySearchEntryByModule (
  215. IN const CModule* pMod,
  216. OUT CModuleTreeEntry** pInsertPosition OPTIONAL) const
  217. {
  218. Assert (pMod);
  219. // Find the module using a binary search.
  220. //
  221. if (size())
  222. {
  223. LONG Lo;
  224. LONG Hi;
  225. LONG Mid;
  226. INT Result;
  227. const CModuleTreeEntry* pScan;
  228. PCSTR pszFileName = pMod->m_pszFileName;
  229. Lo = 0;
  230. Hi = size() - 1;
  231. while (Hi >= Lo)
  232. {
  233. Mid = (Lo + Hi) / 2;
  234. Assert ((UINT)Mid < size());
  235. pScan = (begin() + Mid);
  236. Result = strcmp (pszFileName, pScan->m_pModule->m_pszFileName);
  237. if (Result < 0)
  238. {
  239. Hi = Mid - 1;
  240. }
  241. else if (Result > 0)
  242. {
  243. Lo = Mid + 1;
  244. }
  245. else
  246. {
  247. Assert (pMod == pScan->m_pModule);
  248. return const_cast<CModuleTreeEntry*>(pScan);
  249. }
  250. }
  251. // If we make it to here, the module was not found.
  252. //
  253. if (pInsertPosition)
  254. {
  255. CModule* pGroupMod;
  256. const CModuleTreeEntry* pPrev;
  257. // Seek to the beginning of this group. We need to insert
  258. // before the entire group, not just the one item we last found.
  259. //
  260. pScan = begin() + Lo;
  261. if (pScan != begin())
  262. {
  263. pGroupMod = pScan->m_pModule;
  264. do
  265. {
  266. pPrev = pScan - 1;
  267. if (pPrev->m_pModule == pGroupMod)
  268. {
  269. pScan = pPrev;
  270. }
  271. else
  272. {
  273. break;
  274. }
  275. } while (pPrev != begin());
  276. }
  277. *pInsertPosition = const_cast<CModuleTreeEntry*>(pScan);
  278. Assert (*pInsertPosition >= begin());
  279. Assert (*pInsertPosition <= end());
  280. }
  281. }
  282. else if (pInsertPosition)
  283. {
  284. // Empty collection. Insert position is at the beginning.
  285. //
  286. *pInsertPosition = const_cast<CModuleTreeEntry*>(begin());
  287. }
  288. return const_cast<CModuleTreeEntry*>(end());
  289. }
  290. CModuleTreeEntry*
  291. CModuleTree::PFindFirstEntryWithModule (
  292. IN const CModule* pMod) const
  293. {
  294. CModuleTreeEntry* pEntry;
  295. Assert (pMod);
  296. pEntry = PBinarySearchEntryByModule (pMod, NULL);
  297. if (pEntry != end())
  298. {
  299. Assert (pEntry);
  300. if (pEntry != begin())
  301. {
  302. CModuleTreeEntry* pPrev;
  303. Assert (pMod == pEntry->m_pModule);
  304. while (1)
  305. {
  306. pPrev = pEntry - 1;
  307. if (pPrev->m_pModule == pMod)
  308. {
  309. pEntry = pPrev;
  310. }
  311. else
  312. {
  313. break;
  314. }
  315. if (pPrev == begin())
  316. {
  317. break;
  318. }
  319. }
  320. }
  321. }
  322. return pEntry;
  323. }
  324. CModuleTreeEntry*
  325. CModuleTree::PFindFirstEntryAfterModuleGroup (
  326. IN const CModule* pMod) const
  327. {
  328. CModuleTreeEntry* pEntry;
  329. Assert (pMod);
  330. pEntry = PBinarySearchEntryByModule (pMod, NULL);
  331. if (pEntry != end())
  332. {
  333. Assert (pEntry);
  334. Assert (pMod == pEntry->m_pModule);
  335. while (pEntry != end() && pEntry->m_pModule == pMod)
  336. {
  337. pEntry++;
  338. }
  339. }
  340. return pEntry;
  341. }
  342. CModuleTreeEntry*
  343. CModuleTree::PBinarySearchEntry (
  344. IN const CModule* pMod,
  345. IN const CModule* pImport,
  346. OUT CModuleTreeEntry** pInsertPosition OPTIONAL) const
  347. {
  348. CModuleTreeEntry* pEntry;
  349. Assert (this);
  350. Assert (pMod);
  351. Assert (pImport);
  352. pEntry = PBinarySearchEntryByModule (pMod, pInsertPosition);
  353. if (pEntry != end())
  354. {
  355. Assert (pEntry);
  356. const CModuleTreeEntry* pScan;
  357. // Found an entry with a matching module. Need to scan backwards
  358. // in the module group looking for a match. If not found,
  359. // Scan to the end looking for a match and if we reach the
  360. // end of the group, that will be the insert position (if specified).
  361. //
  362. pScan = pEntry;
  363. while (pScan != begin())
  364. {
  365. pScan--;
  366. if (pScan->m_pModule != pMod)
  367. {
  368. // Left the group without finding a dupliate.
  369. //
  370. break;
  371. }
  372. if (pScan->m_pImportModule == pImport)
  373. {
  374. Assert (pScan->m_pModule == pMod);
  375. return const_cast<CModuleTreeEntry*>(pScan);
  376. }
  377. }
  378. pScan = pEntry;
  379. Assert (pMod == pScan->m_pModule);
  380. while (pScan != end() && pScan->m_pModule == pMod)
  381. {
  382. if (pScan->m_pImportModule == pImport)
  383. {
  384. Assert (pScan->m_pModule == pMod);
  385. return const_cast<CModuleTreeEntry*>(pScan);
  386. }
  387. pScan++;
  388. }
  389. if (pInsertPosition)
  390. {
  391. *pInsertPosition = const_cast<CModuleTreeEntry*>(pScan);
  392. }
  393. // No match.
  394. pEntry = const_cast<CModuleTreeEntry*>(end());
  395. }
  396. return pEntry;
  397. }
  398. #if DBG
  399. VOID
  400. CModuleTree::DbgVerifySorted ()
  401. {
  402. CModuleTreeEntry* pScan;
  403. CModuleTreeEntry* pPrev = NULL;
  404. if (size() > 1)
  405. {
  406. for (pPrev = begin(), pScan = begin() + 1; pScan != end(); pScan++)
  407. {
  408. Assert (strcmp(pPrev->m_pModule->m_pszFileName,
  409. pScan->m_pModule->m_pszFileName) <= 0);
  410. pPrev = pScan;
  411. }
  412. }
  413. }
  414. #endif