Windows NT 4.0 source code leak
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.

705 lines
18 KiB

4 years ago
  1. /***********************************************************************
  2. * Microsoft (R) 32-Bit Incremental Linker
  3. *
  4. * Copyright (C) Microsoft Corp 1992-1996. All rights reserved.
  5. *
  6. * File: cv.cpp
  7. *
  8. * File Comments:
  9. *
  10. * Routines to support CodeView information in a PE image.
  11. *
  12. ***********************************************************************/
  13. #include "link.h"
  14. #include "cvinfo.h"
  15. CVSEG *
  16. PcvsegMapPmod(PMOD pmod, WORD *pccvseg, PIMAGE pimage)
  17. // Generates a list of CVSEG's for the specified module (one for each
  18. // contiguous region of some segment).
  19. //
  20. // NOTE: we do not attempt to merge CVSEG's (we just add new CON's at
  21. // the beginning or end) so out-of-order CON's may cause extra CVSEG's
  22. // to be created (and therefore the sstSrcModule might be larger than
  23. // necessary). I think this will happen only if -order is being used.
  24. //
  25. {
  26. ENM_SRC enmSrc;
  27. CVSEG *pcvsegHead;
  28. pcvsegHead = NULL;
  29. *pccvseg = 0;
  30. for (InitEnmSrc(&enmSrc, pmod); FNextEnmSrc(&enmSrc); ) {
  31. CVSEG *pcvsegPrev;
  32. CVSEG *pcvsegNext;
  33. CVSEG *pcvsegNew;
  34. if (enmSrc.pcon->flags & IMAGE_SCN_LNK_REMOVE) {
  35. continue;
  36. }
  37. if (enmSrc.pcon->cbRawData == 0) {
  38. continue;
  39. }
  40. if (PsecPCON(enmSrc.pcon) == psecDebug) {
  41. continue;
  42. }
  43. if (pimage->Switch.Link.fTCE) {
  44. if (FDiscardPCON_TCE(enmSrc.pcon)) {
  45. // Discarded comdat
  46. continue;
  47. }
  48. }
  49. // Find location of this CON in linked list sorted by RVA.
  50. pcvsegPrev = NULL;
  51. for (pcvsegNext = pcvsegHead;
  52. pcvsegNext != NULL;
  53. pcvsegNext = pcvsegNext->pcvsegNext) {
  54. if (pcvsegNext->pconFirst->rva > enmSrc.pcon->rva) {
  55. break;
  56. }
  57. pcvsegPrev = pcvsegNext;
  58. }
  59. if (FetchContent(PsecPCON(enmSrc.pcon)->flags) == IMAGE_SCN_CNT_CODE) {
  60. // Check if we can combine with adjacent CVSEG.
  61. if ((pcvsegPrev != NULL) &&
  62. (pcvsegPrev->pconLast->pconNext == enmSrc.pcon)) {
  63. // New CON follows existing CVSEG. Extend forward.
  64. pcvsegPrev->pconLast = enmSrc.pcon;
  65. continue;
  66. }
  67. if ((pcvsegNext != NULL) &&
  68. (pcvsegNext->pconFirst == enmSrc.pcon->pconNext)) {
  69. // New CON preceeds existing CVSEG. Extend backward.
  70. pcvsegNext->pconFirst = enmSrc.pcon;
  71. continue;
  72. }
  73. }
  74. pcvsegNew = (CVSEG *) PvAlloc(sizeof(CVSEG));
  75. pcvsegNew->pgrp = enmSrc.pcon->pgrpBack;
  76. pcvsegNew->pconFirst = pcvsegNew->pconLast = enmSrc.pcon;
  77. pcvsegNew->pcvsegNext = pcvsegNext;
  78. if (pcvsegPrev != NULL) {
  79. pcvsegPrev->pcvsegNext = pcvsegNew;
  80. } else {
  81. pcvsegHead = pcvsegNew;
  82. }
  83. (*pccvseg)++;
  84. }
  85. return(pcvsegHead);
  86. }
  87. void
  88. ChainCvPublics (
  89. PIMAGE pimage
  90. )
  91. /*++
  92. Routine Description:
  93. Writes the cv publics to disk.
  94. Arguments:
  95. PtrExtern - Pointer to external structure.
  96. Return Value:
  97. None.
  98. --*/
  99. {
  100. PPEXTERNAL rgpexternal;
  101. DWORD ipexternal;
  102. DWORD cpexternal;
  103. rgpexternal = RgpexternalByName(pimage->pst);
  104. cpexternal = Cexternal(pimage->pst);
  105. for (ipexternal = 0; ipexternal < cpexternal; ipexternal++) {
  106. PMOD pmod;
  107. PCON pcon;
  108. PEXTERNAL pext;
  109. pext = rgpexternal[ipexternal];
  110. if ((pext->Flags & EXTERN_DEFINED) == 0) {
  111. continue;
  112. }
  113. pcon = pext->pcon;
  114. if (pcon == NULL) {
  115. continue;
  116. }
  117. if (pcon->flags & IMAGE_SCN_LNK_REMOVE) {
  118. continue;
  119. }
  120. if (pimage->Switch.Link.fTCE) {
  121. if (FDiscardPCON_TCE(pcon)) {
  122. // Discarded comdat
  123. continue;
  124. }
  125. }
  126. pmod = PmodPCON(pcon);
  127. if (pmod == NULL) {
  128. // Ignore internal things
  129. continue;
  130. }
  131. if (pmod == pmodLinkerDefined) {
  132. // The symbol is not defined by a user module, but we need to emit a public
  133. // for it anyway, so we arbitrarily assign it to the first module.
  134. if (NextCvObject == 0) {
  135. // There is no first module
  136. continue;
  137. }
  138. pmod = CvInfo[0].pmod;
  139. }
  140. AddToLext(&pmod->plextPublic, pext);
  141. }
  142. }
  143. void
  144. EmitOneCvPublic(PIMAGE pimage, PEXTERNAL pext, SHORT isecAbsolute)
  145. {
  146. PUBSYM32 pub;
  147. const char *szName;
  148. BYTE cbName;
  149. if (pext->pcon == NULL) {
  150. pub.off = pext->FinalValue;
  151. pub.seg = isecAbsolute;
  152. } else if (pimage->Switch.Link.fTCE && FDiscardPCON_TCE(pext->pcon)) {
  153. // Don't emit discarded symbols
  154. return;
  155. } else {
  156. PSEC psec;
  157. psec = PsecPCON(pext->pcon);
  158. if (fM68K) {
  159. pub.off = pext->FinalValue;
  160. } else {
  161. pub.off = pext->FinalValue - psec->rva;
  162. }
  163. pub.seg = psec->isec;
  164. }
  165. szName = SzNamePext(pext, pimage->pst);
  166. // Record length doesn't include cb WORD
  167. // Name is a length preceeded string and length field is only one byte
  168. cbName = (BYTE) __min(0xff, strlen(szName));
  169. pub.reclen = (WORD) (sizeof(pub) - sizeof(WORD) + cbName);
  170. pub.rectyp = S_PUB32;
  171. pub.typind = T_NOTYPE;
  172. // and the name length byte is included in the sizeof pub - so subtract one on
  173. // the write
  174. FileWrite(FileWriteHandle, &pub, sizeof(pub) - 1);
  175. FileWrite(FileWriteHandle, &cbName, sizeof(BYTE));
  176. FileWrite(FileWriteHandle, szName, cbName);
  177. }
  178. void
  179. EmitCvPublics (
  180. PIMAGE pimage,
  181. PCVINFO CvInfo
  182. )
  183. /*++
  184. Routine Description:
  185. Writes the cv publics to disk.
  186. Arguments:
  187. PtrExtern - Pointer to external structure.
  188. Return Value:
  189. None.
  190. --*/
  191. {
  192. SHORT isecAbsolute = (SHORT) (pimage->ImgFileHdr.NumberOfSections + 1);
  193. LEXT *plext;
  194. LEXT *plextNext;
  195. for (plext = CvInfo->pmod->plextPublic; plext != NULL; plext = plextNext) {
  196. EmitOneCvPublic(pimage, plext->pext, isecAbsolute);
  197. plextNext = plext->plextNext;
  198. FreePv(plext);
  199. }
  200. // Walk the common vars which this module saw first, and emit public
  201. // records for them here.
  202. while (CvInfo->pmod->plextCommon != NULL) {
  203. LEXT *plext = CvInfo->pmod->plextCommon;
  204. // Make sure the symbol is still COMMON and defined
  205. if ((plext->pext->Flags & (EXTERN_DEFINED | EXTERN_COMMON)) ==
  206. (EXTERN_DEFINED | EXTERN_COMMON))
  207. {
  208. EmitOneCvPublic(pimage, plext->pext, isecAbsolute);
  209. }
  210. CvInfo->pmod->plextCommon = plext->plextNext;
  211. FreePv(plext);
  212. }
  213. }
  214. void
  215. EmitCvInfo (
  216. PIMAGE pimage)
  217. /*++
  218. Routine Description:
  219. Arguments:
  220. None.
  221. Return Value:
  222. None.
  223. --*/
  224. {
  225. WORD i;
  226. DWORD li;
  227. DWORD lj;
  228. DWORD nameLen;
  229. DWORD numSubsections;
  230. DWORD numLocals = 0;
  231. DWORD numTypes = 0;
  232. DWORD numLinenums = 0;
  233. DWORD libStartSeek;
  234. DWORD libEndSeek;
  235. DWORD segTableStartSeek;
  236. DWORD segTableEndSeek;
  237. BYTE cbFilename;
  238. char *szFilename;
  239. ENM_SEC enm_sec;
  240. ENM_LIB enm_lib;
  241. PSEC psec;
  242. PLIB plib;
  243. DWORD csstPublicSym;
  244. DWORD cSstSrcModule=0;
  245. struct {
  246. WORD cbDirHeader;
  247. WORD cbDirEntry;
  248. DWORD cDir;
  249. DWORD lfoNextDir;
  250. DWORD flags;
  251. } dirHdr;
  252. struct {
  253. WORD subsection;
  254. WORD imod;
  255. DWORD lfo;
  256. DWORD cb;
  257. } subDir;
  258. struct {
  259. WORD ovlNumber;
  260. WORD iLib;
  261. WORD cSeg;
  262. WORD style;
  263. } entry;
  264. struct {
  265. WORD seg;
  266. WORD pad;
  267. DWORD offset;
  268. DWORD cbSeg;
  269. } entrySegArray;
  270. struct {
  271. WORD flags;
  272. WORD iovl;
  273. WORD igr;
  274. WORD isgPhy;
  275. WORD isegName;
  276. WORD iClassName;
  277. DWORD segOffset;
  278. DWORD cbSeg;
  279. } segTable;
  280. // Count the number of sstSymbols, sstTypes, sstSrcLnSeg
  281. // we have gathered from the object files.
  282. for (li = 0; li < NextCvObject; li++) {
  283. if (CvInfo[li].Locals.PointerToSubsection) {
  284. ++numLocals;
  285. }
  286. if (CvInfo[li].Types.PointerToSubsection) {
  287. ++numTypes;
  288. }
  289. if (CvInfo[li].Linenumbers.PointerToSubsection) {
  290. ++numLinenums;
  291. }
  292. }
  293. // Emit the sstModule subsection.
  294. entry.ovlNumber = 0;
  295. entry.style = 0x5643; // "CV"
  296. for (li = 0; li < NextCvObject; li++) {
  297. CVSEG *pcvseg = PcvsegMapPmod(CvInfo[li].pmod, &entry.cSeg, pimage);
  298. WORD icvseg;
  299. szFilename = CvInfo[li].ObjectFilename;
  300. cbFilename = (BYTE) strlen(szFilename);
  301. nameLen = cbFilename;
  302. i = 0;
  303. if (FIsLibPMOD(CvInfo[li].pmod)) {
  304. InitEnmLib(&enm_lib, pimage->libs.plibHead);
  305. while (FNextEnmLib(&enm_lib)) {
  306. plib = enm_lib.plib;
  307. if (plib->szName != NULL) {
  308. // Only named libraries are counted
  309. i++;
  310. if (plib == CvInfo[li].pmod->plibBack) {
  311. break;
  312. }
  313. }
  314. }
  315. EndEnmLib(&enm_lib);
  316. }
  317. entry.iLib = i;
  318. CvInfo[li].Module.PointerToSubsection = FileTell(FileWriteHandle);
  319. FileWrite(FileWriteHandle, &entry, sizeof(entry));
  320. // Generate the section array for this sstModule.
  321. for (icvseg = 0; icvseg < entry.cSeg; icvseg++) {
  322. CVSEG *pcvsegNext;
  323. entrySegArray.seg = PsecPCON(pcvseg->pconFirst)->isec;
  324. entrySegArray.pad = 0;
  325. entrySegArray.offset = pcvseg->pconFirst->rva -
  326. PsecPCON(pcvseg->pconFirst)->rva;
  327. entrySegArray.cbSeg =
  328. (pcvseg->pconLast->rva + pcvseg->pconLast->cbRawData) -
  329. pcvseg->pconFirst->rva;
  330. FileWrite(FileWriteHandle, &entrySegArray, sizeof(entrySegArray));
  331. pcvsegNext = pcvseg->pcvsegNext;
  332. FreePv(pcvseg);
  333. pcvseg = pcvsegNext;
  334. }
  335. assert(pcvseg == NULL);
  336. FileWrite(FileWriteHandle, &cbFilename, sizeof(BYTE));
  337. FileWrite(FileWriteHandle, szFilename, nameLen);
  338. CvInfo[li].Module.SizeOfSubsection =
  339. FileTell(FileWriteHandle) - CvInfo[li].Module.PointerToSubsection;
  340. }
  341. // Emit the sstPublicSym subsection.
  342. csstPublicSym = 0; // actual number of such subsections
  343. ChainCvPublics(pimage);
  344. for (li = 0; li < NextCvObject; li++) {
  345. DWORD icvOther;
  346. if (CvInfo[li].Publics.PointerToSubsection == 0xFFFFFFFF) {
  347. // This is a dup of another module that has been emitted
  348. CvInfo[li].Publics.PointerToSubsection = 0;
  349. continue;
  350. }
  351. csstPublicSym++;
  352. CvInfo[li].Publics.PointerToSubsection = FileTell(FileWriteHandle);
  353. // Write signature
  354. lj = 1;
  355. FileWrite(FileWriteHandle, &lj, sizeof(DWORD));
  356. EmitCvPublics(pimage, &CvInfo[li]);
  357. if (FIsLibPMOD(CvInfo[li].pmod)) {
  358. for (icvOther = li + 1; icvOther < NextCvObject; icvOther++) {
  359. // Emit this module if
  360. // (Module is from same library as current module AND
  361. // Module has the same name as the current module)
  362. if (CvInfo[li].pmod->plibBack != CvInfo[icvOther].pmod->plibBack) {
  363. continue;
  364. }
  365. if (strcmp(CvInfo[li].ObjectFilename, CvInfo[icvOther].ObjectFilename) != 0) {
  366. continue;
  367. }
  368. EmitCvPublics(pimage, &CvInfo[icvOther]);
  369. CvInfo[icvOther].Publics.PointerToSubsection = 0xFFFFFFFF;
  370. }
  371. }
  372. CvInfo[li].Publics.SizeOfSubsection =
  373. FileTell(FileWriteHandle) - CvInfo[li].Publics.PointerToSubsection;
  374. }
  375. // The sstSymbols and sstTypes subsections have already been
  376. // emitted directly from the object files. The sstSrcLnSeg
  377. // have also been emitted indirectly from the object files.
  378. // Emit the sstLibraries subsection.
  379. libStartSeek = FileTell(FileWriteHandle);
  380. nameLen = 0;
  381. FileWrite(FileWriteHandle, &nameLen, sizeof(BYTE));
  382. InitEnmLib(&enm_lib, pimage->libs.plibHead);
  383. while (FNextEnmLib(&enm_lib)) {
  384. plib = enm_lib.plib;
  385. if (plib->szName != NULL) {
  386. nameLen = (BYTE) strlen(plib->szName);
  387. FileWrite(FileWriteHandle, &nameLen, sizeof(BYTE));
  388. FileWrite(FileWriteHandle, plib->szName, nameLen);
  389. }
  390. }
  391. libEndSeek = FileTell(FileWriteHandle);
  392. // Emit the sstSegTable subsection.
  393. segTableStartSeek = FileTell(FileWriteHandle);
  394. i = (WORD) (pimage->ImgFileHdr.NumberOfSections + 1);
  395. FileWrite(FileWriteHandle, &i, sizeof(WORD));
  396. FileWrite(FileWriteHandle, &i, sizeof(WORD));
  397. segTable.iovl = 0;
  398. segTable.igr = 0;
  399. for (i = 1; i <= pimage->ImgFileHdr.NumberOfSections; i++) {
  400. InitEnmSec(&enm_sec, &pimage->secs);
  401. while (FNextEnmSec(&enm_sec)) {
  402. psec = enm_sec.psec;
  403. if (psec->isec == i) {
  404. break;
  405. }
  406. }
  407. EndEnmSec(&enm_sec);
  408. segTable.flags = 0x0108;
  409. if (psec->flags & IMAGE_SCN_MEM_READ) {
  410. segTable.flags |= 0x1;
  411. }
  412. if (psec->flags & IMAGE_SCN_MEM_WRITE) {
  413. segTable.flags |= 0x2;
  414. }
  415. if (psec->flags & IMAGE_SCN_MEM_EXECUTE) {
  416. segTable.flags |= 0x4;
  417. }
  418. // In the case of M68K pass the MacResource number
  419. // instead of the actual section number.
  420. segTable.isgPhy = fM68K ? psec->iResMac : i;
  421. segTable.isegName = 0xffff; // No name
  422. segTable.iClassName = 0xffff; // No name
  423. // If it is M68K and the psec->iResMac is 0, then
  424. // provide the offset from the beginning of the data0
  425. segTable.segOffset = fM68K ? psec->dwM68KDataOffset : 0;
  426. segTable.cbSeg = psec->cbVirtualSize;
  427. FileWrite(FileWriteHandle, &segTable, sizeof(segTable));
  428. }
  429. // Write another sstSegMap entry for all absolute symbols.
  430. segTable.flags = 0x0208; // absolute
  431. segTable.isgPhy = 0;
  432. segTable.isegName = 0xffff; // No name
  433. segTable.iClassName = 0xffff; // No name
  434. segTable.cbSeg = 0xffffffff; // Allow full 32 bit range
  435. FileWrite(FileWriteHandle, &segTable, sizeof(segTable));
  436. segTableEndSeek = FileTell(FileWriteHandle);
  437. // Write SstSrcModul entries
  438. for(li = 0; li < NextCvObject; li++) // for each module
  439. {
  440. if (CvInfo[li].pmod->pModDebugInfoApi == NULL) {
  441. // Don't write linenumber records if there aren't any
  442. CvInfo[li].pmod->PointerToSubsection = 0;
  443. } else {
  444. CvInfo[li].pmod->PointerToSubsection = FileTell(FileWriteHandle);
  445. FileWrite(FileWriteHandle,CvInfo[li].pmod->pSstSrcModInfo,CvInfo[li].pmod->cbSstSrcModInfo);
  446. cSstSrcModule++;
  447. }
  448. }
  449. // Emit the Subsection directory.
  450. CvSeeks.SubsectionDir = FileTell(FileWriteHandle);
  451. // We'll have a sstModule for every object, an sstPublicSym for every
  452. // object with a unique name, and optionaly some
  453. // sstSymbols and sstTypes.
  454. numSubsections = NextCvObject + csstPublicSym +
  455. numLocals +
  456. numTypes +
  457. numLinenums +
  458. cSstSrcModule +
  459. 2; // include sstLibraries & sstSegTable
  460. dirHdr.cbDirHeader = sizeof(dirHdr);
  461. dirHdr.cbDirEntry = sizeof(subDir);
  462. dirHdr.cDir = numSubsections;
  463. dirHdr.lfoNextDir = 0;
  464. dirHdr.flags = 0;
  465. FileWrite(FileWriteHandle, &dirHdr, sizeof(dirHdr));
  466. // Emit the sstModule entries.
  467. subDir.subsection = 0x120;
  468. for (li = 0; li < NextCvObject; li++) {
  469. subDir.imod = (WORD)(li + 1);
  470. subDir.lfo = CvInfo[li].Module.PointerToSubsection - CvSeeks.Base;
  471. subDir.cb = CvInfo[li].Module.SizeOfSubsection;
  472. FileWrite(FileWriteHandle, &subDir, sizeof(subDir));
  473. }
  474. // Emit the sstPublicSym entries.
  475. subDir.subsection = 0x123; // sstPublicSym
  476. for (li = 0; li < NextCvObject; li++) {
  477. if (CvInfo[li].Publics.PointerToSubsection == 0) {
  478. // this module doesn't have one (duplicate name)
  479. continue;
  480. }
  481. subDir.imod = (WORD)(li + 1);
  482. subDir.lfo = CvInfo[li].Publics.PointerToSubsection - CvSeeks.Base;
  483. subDir.cb = CvInfo[li].Publics.SizeOfSubsection;
  484. FileWrite(FileWriteHandle, &subDir, sizeof(subDir));
  485. }
  486. // Emit the sstSymbols entries.
  487. subDir.subsection = 0x124; // sstSymbols
  488. for (li = 0; li < NextCvObject; li++) {
  489. if (CvInfo[li].Locals.PointerToSubsection) {
  490. subDir.imod = (WORD)(li + 1);
  491. subDir.lfo = CvInfo[li].Locals.PointerToSubsection - CvSeeks.Base;
  492. subDir.cb = CvInfo[li].Locals.SizeOfSubsection;
  493. FileWrite(FileWriteHandle, &subDir, sizeof(subDir));
  494. }
  495. }
  496. // Emit the SstSrcModule entries
  497. subDir.subsection=0x127; // SstSrcModule
  498. for(li = 0; li < NextCvObject ; li++) {
  499. if (CvInfo[li].pmod->PointerToSubsection) {
  500. subDir.imod = (WORD)(li + 1);
  501. subDir.lfo = CvInfo[li].pmod->PointerToSubsection - CvSeeks.Base;
  502. subDir.cb = CvInfo[li].pmod->cbSstSrcModInfo;
  503. FileWrite(FileWriteHandle,&subDir,sizeof(subDir));
  504. }
  505. }
  506. // Emit the sstTypes entries.
  507. for (li = 0; li < NextCvObject; li++) {
  508. if (CvInfo[li].Types.PointerToSubsection) {
  509. subDir.subsection = (WORD) (CvInfo[li].Types.Precompiled ? 0x12f : 0x121);
  510. subDir.imod = (WORD)(li + 1);
  511. subDir.lfo = CvInfo[li].Types.PointerToSubsection - CvSeeks.Base;
  512. subDir.cb = CvInfo[li].Types.SizeOfSubsection;
  513. FileWrite(FileWriteHandle, &subDir, sizeof(subDir));
  514. }
  515. }
  516. // Emit the sstLibraries entry.
  517. subDir.subsection = 0x128;
  518. subDir.imod = 0xffff; // -1
  519. subDir.lfo = libStartSeek - CvSeeks.Base;
  520. subDir.cb = libEndSeek - libStartSeek;
  521. FileWrite(FileWriteHandle, &subDir, sizeof(subDir));
  522. // Emit the sstSegTable entry.
  523. subDir.subsection = 0x12d;
  524. subDir.imod = 0xffff; // -1
  525. subDir.lfo = segTableStartSeek - CvSeeks.Base;
  526. subDir.cb = segTableEndSeek - segTableStartSeek;
  527. FileWrite(FileWriteHandle, &subDir, sizeof(subDir));
  528. }