Leaked source code of windows server 2003
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.

2517 lines
74 KiB

  1. /*
  2. * Copyright Microsoft Corporation 1985-1987
  3. *
  4. * This Module contains Proprietary Information of Microsoft
  5. * Corporation and should be treated as Confidential.
  6. */
  7. /****************************************************************
  8. * *
  9. * NEWDEB.C *
  10. * *
  11. * Symbolic debugging support. *
  12. * *
  13. ****************************************************************/
  14. #include <minlit.h> /* Basic types and constants */
  15. #include <bndtrn.h> /* More types and constants */
  16. #include <bndrel.h> /* Types and constants */
  17. #include <lnkio.h> /* Linker input/output */
  18. #if OIAPX286
  19. #include <xenfmt.h> /* Xenix executable format defs. */
  20. #endif
  21. #if OEXE
  22. #include <newexe.h> /* Segmented executable format */
  23. #endif
  24. #if EXE386
  25. #include <exe386.h>
  26. #endif
  27. #include <lnkmsg.h> /* Error messages */
  28. #include <extern.h> /* External function declarations */
  29. #ifndef CVVERSION
  30. #if OIAPX286
  31. #define CVVERSION 0 /* Assume new CV exe format */
  32. #else
  33. #define CVVERSION 1 /* Assume new CV exe format */
  34. #endif
  35. #endif
  36. #if (CPU8086 OR CPU286)
  37. #define TFAR far
  38. #else
  39. #define TFAR
  40. #endif
  41. #include <newdeb.h> /* Symbolic debug types */
  42. extern SEGTYPE segAdjCom; /* Segment moved by 0x100 in .com programs */
  43. #if AUTOVM
  44. BYTE FAR * NEAR FetchSym1(RBTYPE rb, WORD Dirty);
  45. #define FETCHSYM FetchSym1
  46. #define PROPSYMLOOKUP EnterName
  47. #else
  48. #define FETCHSYM FetchSym
  49. #define PROPSYMLOOKUP EnterName
  50. #endif
  51. #define CVDEBUG FALSE
  52. #define SRCDEBUG FALSE
  53. #define DNT_START 64
  54. #define Round2Dword(x) (((x) + 3L) & ~3L)
  55. typedef struct raPair
  56. {
  57. DWORD raStart;
  58. DWORD raEnd;
  59. }
  60. RAPAIR;
  61. /*
  62. * FUNCTION PROTOTYPES
  63. */
  64. LOCAL WORD NEAR IsDebTyp(APROPSNPTR prop);
  65. LOCAL WORD NEAR IsDebSym(APROPSNPTR prop);
  66. LOCAL int NEAR OutLibSec(void);
  67. void NEAR GetName(AHTEPTR ahte, BYTE *pBuf);
  68. LOCAL DWORD NEAR OutSrcModule(CVSRC FAR *pSrcLines);
  69. LOCAL void NEAR PutDnt(DNT *pDnt);
  70. LOCAL WORD NEAR HasCVinfo(APROPFILEPTR apropFile);
  71. LOCAL void NEAR OutModules(void);
  72. LOCAL void NEAR Pad2Dword(void);
  73. #if CVDEBUG
  74. LOCAL void NEAR DumpDNT(DNT *pDnt);
  75. #endif
  76. extern long lfaBase; /* Base address */
  77. extern int fSameComdat; /* Set if LINSYM to the same COMDAT */
  78. /*
  79. * CodeView signature - if changes notify the developers of the
  80. * following programs:
  81. * - QuickC
  82. * - Resource Compiler - Windows and PM
  83. * - CodeView and its utilities
  84. */
  85. char szSignature[4] = "NB05";
  86. RBTYPE rhteDebSrc; /* Class "DEBSRC" virt addr */
  87. RBTYPE rhteDebSym; /* Class "DEBSYM" virt addr */
  88. RBTYPE rhteDebTyp; /* Class "DEBTYP" virt addr */
  89. RBTYPE rhteTypes;
  90. RBTYPE rhteSymbols;
  91. RBTYPE rhte0Types;
  92. RBTYPE rhte0Symbols;
  93. LOCAL SBTYPE sbLastModule; /* Name of THEADR last observed */
  94. #if NOT CVVERSION
  95. LOCAL long lfaDebHdr; /* Position of section table */
  96. LOCAL long lfaSegMod;
  97. #endif
  98. LOCAL WORD dntMax; // DNT table size
  99. LOCAL WORD dntMac; // Count of DNT entries in table
  100. LOCAL DNT FAR *rgDnt; // Table of DNT entries
  101. LOCAL DWORD FAR *fileBase; // Table of offsets to source file info
  102. LOCAL RAPAIR FAR *raSeg; // Table of physical starting and ending offsets
  103. // of the contribution to the logical segments
  104. LOCAL WORD FAR *segNo; // Table of physical segment indicies
  105. LOCAL WORD cMac; // Current number of elements in the above tables
  106. #ifdef CVPACK_MONDO
  107. #define CVPACK_SHARED 1
  108. #define REVERSE_MODULE_ORDER_FOR_CVPACK 1
  109. #else
  110. #define CVPACK_SHARED 0
  111. #define REVERSE_MODULE_ORDER_FOR_CVPACK 0
  112. #endif
  113. //these macros help to make the source not so cluttered with #ifdefs...
  114. #if CVPACK_SHARED
  115. #define IF_NOT_CVPACK_SHARED(x)
  116. #define WriteCopy(x,y) WriteSave(TRUE, x, y)
  117. #define WriteNocopy(x,y) WriteSave(FALSE, x, y)
  118. #define FTELL_BSRUNFILE() lposCur
  119. #define LINK_TRACE(x)
  120. // cvpack might read parts of the header more than once, we use this
  121. // constant to ensure that at least CB_HEADER_SAVE bytes are always
  122. // available to be re-read by cvpack
  123. #define CB_HEADER_SAVE 128
  124. void WriteSave(FTYPE fCopy, void *pv, UINT cb);
  125. void WriteFlushSignature(void);
  126. void WriteFlushAll(void);
  127. // cvpack cached blocks...
  128. typedef struct _BL
  129. {
  130. long lpos; // position of this block in the file
  131. BYTE * pb; // pointer to bytes in this block
  132. } BL;
  133. #define iblNil (-1)
  134. static long lposCur; // current position in the file
  135. static long lposMac; // size of the file
  136. static long iblLim; // number of blocks used
  137. static long iblCur; // current block we are reading
  138. static long iblMac; // number of blocks allocated
  139. static long cbRealBytes; // number of bytes actually written to the file
  140. static int ichCur; // index within the current block
  141. static int cbCur; // number of bytes left in the current block
  142. static BL *rgbl; // array of buffered write blocks
  143. // number of bytes in a particular block
  144. __inline int CbIbl(int ibl)
  145. {
  146. // compute the difference between this block and the next block
  147. // unless this is the last block then use lposMac
  148. if (ibl == iblLim - 1)
  149. return lposMac - rgbl[ibl].lpos;
  150. else
  151. return rgbl[ibl+1].lpos - rgbl[ibl].lpos;
  152. }
  153. #define C_BL_INIT 256
  154. #else
  155. #define IF_NOT_CVPACK_SHARED(x) x
  156. #define WriteCopy(x,y) WriteExe(x,y)
  157. #define WriteNocopy(x,y) WriteExe(x,y)
  158. #define FTELL_BSRUNFILE() ftell(bsRunfile)
  159. #define LINK_TRACE(x)
  160. #endif
  161. #if CVDEBUG
  162. LOCAL void NEAR DumpDNT(DNT *pDnt)
  163. {
  164. if (pDnt == NULL)
  165. return;
  166. fprintf(stdout, "iMod = %d(0x%x)", pDnt->iMod, pDnt->iMod);
  167. switch (pDnt->sst)
  168. {
  169. case SSTMODULES:
  170. case SSTMODULES4:
  171. fprintf(stdout, " SSTMODULES: ");
  172. break;
  173. case SSTTYPES:
  174. case SSTTYPES4:
  175. fprintf(stdout, " SSTYPES: ");
  176. break;
  177. case SSTPUBLICS:
  178. case SSTPUBLICS4:
  179. fprintf(stdout, " SSTPUBLICS: ");
  180. break;
  181. case SSTPUBLICSYM:
  182. fprintf(stdout, " SSTPUBLICSYM: ");
  183. break;
  184. case SSTSYMBOLS:
  185. case SSTSYMBOLS4:
  186. fprintf(stdout, " SSTSYMBOLS: ");
  187. break;
  188. case SSTALIGNSYM:
  189. fprintf(stdout, " SSTALIGNSYM: ");
  190. break;
  191. case SSTSRCLINES:
  192. case SSTNSRCLINES:
  193. case SSTSRCLNSEG:
  194. fprintf(stdout, " SSTSRCLINES: ");
  195. break;
  196. case SSTSRCMODULE:
  197. fprintf(stdout, " SSTSRCMODULE: ");
  198. break;
  199. case SSTLIBRARIES:
  200. case SSTLIBRARIES4:
  201. fprintf(stdout, " SSTLIBRARIES: ");
  202. break;
  203. case SSTGLOBALSYM:
  204. fprintf(stdout, " SSTGLOBALSYM: ");
  205. break;
  206. case SSTGLOBALPUB:
  207. fprintf(stdout, " SSTGLOBALPUB: ");
  208. break;
  209. case SSTGLOBALTYPES:
  210. fprintf(stdout, " SSTGLOBALTYPES: ");
  211. break;
  212. case SSTMPC:
  213. fprintf(stdout, " SSTMPC: ");
  214. break;
  215. case SSTSEGMAP:
  216. fprintf(stdout, " SSTSEGMAP: ");
  217. break;
  218. case SSTSEGNAME:
  219. fprintf(stdout, " SSTSEGNAME: ");
  220. break;
  221. case SSTIMPORTS:
  222. fprintf(stdout, " SSTIMPORTS: ");
  223. break;
  224. default:
  225. fprintf(stdout, " UNKNOWN !?!: ");
  226. break;
  227. }
  228. fprintf(stdout, "file offset 0x%lx; size 0x%x\r\n",
  229. lfaBase+pDnt->lfo, pDnt->cb);
  230. }
  231. #endif
  232. #if SRCDEBUG
  233. LOCAL void NEAR DumpSrcLines(DWORD vLines)
  234. {
  235. CVSRC cvSrc;
  236. CVGSN cvGsn;
  237. CVLINE cvLine;
  238. DWORD curSrc;
  239. DWORD curGsn;
  240. DWORD curLine;
  241. SBTYPE fileName;
  242. DWORD i;
  243. WORD j;
  244. fprintf(stdout, "\r\nList at %lx\r\n\r\n", vLines);
  245. for (curSrc = vLines; curSrc != 0L; curSrc = cvSrc.vpNext)
  246. {
  247. memcpy(&cvSrc, mapva(curSrc, FALSE), sizeof(CVSRC));
  248. memcpy(fileName, mapva(cvSrc.vpFileName, FALSE), cvSrc.cbName);
  249. fileName[cvSrc.cbName] = '\0';
  250. fprintf(stdout, "'%s' --> code segments: %lu; source lines: %lu\r\n", fileName, cvSrc.cSegs, cvSrc.cLines);
  251. for (curGsn = cvSrc.vpGsnFirst; curGsn != 0L; curGsn = cvGsn.vpNext)
  252. {
  253. memcpy(&cvGsn, mapva(curGsn, FALSE), sizeof(CVGSN));
  254. fprintf(stdout, " Logical segment %d; source lines: %d; start: %lx; end: %lx\r\n", cvGsn.seg, cvGsn.cLines, cvGsn.raStart, cvGsn.raEnd);
  255. for (curLine = cvGsn.vpLineFirst, i = 1L; curLine != 0L; curLine = cvLine.vpNext)
  256. {
  257. memcpy(&cvLine, mapva(curLine, FALSE), sizeof(CVLINE));
  258. for (j = 0; j < cvLine.cPair; j++, i++)
  259. fprintf(stdout, " %8lu: %u:%lx\r\n", i, cvLine.rgLn[j], cvLine.rgOff[j]);
  260. }
  261. }
  262. }
  263. }
  264. #endif
  265. /****************************************************************
  266. * *
  267. * Initialize variables for symbolic debug processing. *
  268. * Pass 1. *
  269. * *
  270. ****************************************************************/
  271. void NEAR InitDeb1 (void)
  272. {
  273. #if ODOS3EXE
  274. if (vfDSAlloc)
  275. {
  276. OutWarn(ER_dbgdsa);
  277. vfDSAlloc = FALSE;
  278. }
  279. #endif
  280. #if FEXEPACK
  281. if (fExePack)
  282. {
  283. OutWarn(ER_dbgexe);
  284. fExePack = FALSE;
  285. }
  286. #endif
  287. }
  288. void InitDbRhte ()
  289. {
  290. PROPSYMLOOKUP((BYTE *) "\006DEBTYP", ATTRNIL, TRUE);
  291. rhteDebTyp = vrhte;
  292. PROPSYMLOOKUP((BYTE *) "\006DEBSYM", ATTRNIL, TRUE);
  293. rhteDebSym = vrhte;
  294. PROPSYMLOOKUP((BYTE *) "\006 TYPES", ATTRNIL, TRUE);
  295. rhte0Types = vrhte;
  296. PROPSYMLOOKUP((BYTE *) "\010 SYMBOLS", ATTRNIL, TRUE);
  297. rhte0Symbols = vrhte;
  298. PROPSYMLOOKUP((BYTE *) "\007$$TYPES", ATTRNIL, TRUE);
  299. rhteTypes = vrhte;
  300. PROPSYMLOOKUP((BYTE *) "\011$$SYMBOLS", ATTRNIL, TRUE);
  301. rhteSymbols = vrhte;
  302. }
  303. LOCAL void NEAR Pad2Dword(void)
  304. {
  305. WORD cb; // Number of bytes to write
  306. static DWORD dwZero;
  307. // Calculate needed padding
  308. cb = (WORD)(sizeof(DWORD)-((WORD) FTELL_BSRUNFILE() % sizeof(DWORD)));
  309. if (cb != sizeof(DWORD))
  310. WriteCopy(&dwZero, cb);
  311. }
  312. /*** GetName - get symbol associated with given property cell
  313. *
  314. * Purpose:
  315. * Find the symbol which has given property.
  316. *
  317. * Input:
  318. * - ahte - pointer to property cell
  319. * - pBuf - pointer to ASCII buffer
  320. *
  321. * Output:
  322. * No explicit value is passed. If symbol is found the it is
  323. * copied into buffer
  324. *
  325. * Exceptions:
  326. * None.
  327. *
  328. * Notes:
  329. * This functional duplicate of GetPropName, but we want to
  330. * call both function as near.
  331. *
  332. *************************************************************************/
  333. void NEAR GetName(AHTEPTR ahte, BYTE *pBuf)
  334. {
  335. while(ahte->attr != ATTRNIL)
  336. ahte = (AHTEPTR ) FETCHSYM(ahte->rhteNext, FALSE);
  337. FMEMCPY((char FAR *) pBuf, ahte->cch, B2W(ahte->cch[0]) + 1);
  338. if (B2W(pBuf[0]) < SBLEN)
  339. pBuf[pBuf[0] + 1] = '\0';
  340. else
  341. pBuf[pBuf[0]] = '\0';
  342. }
  343. /*** DebPublic - prepare symbols for debugger
  344. *
  345. * Purpose:
  346. * When the /CODEVIEW option is used then all PUBDEFs and COMDEFs
  347. * defined in a given object file are linked into one list. This
  348. * function adds one symbol to the list and updates the combined
  349. * size of symbols
  350. *
  351. * Input:
  352. * vrprop - virtual pointer to symbol descriptor
  353. * rt - OMF record type
  354. *
  355. * Output:
  356. * No explicit value is returned.
  357. * Side effects:
  358. * - symbol is attached to the module symbol list
  359. *
  360. * Exceptions:
  361. * None.
  362. *
  363. * Notes:
  364. * Symbols are placed on the list in reverse order of their apperance
  365. * in the object file.
  366. *
  367. *************************************************************************/
  368. void DebPublic(RBTYPE vrprop, WORD rt)
  369. {
  370. APROPFILEPTR apropFile; // Pointer to file entry
  371. APROPNAMEPTR apropName; // Real pointer to PUBDEF descriptor
  372. APROPUNDEFPTR apropUndef; // Real pointer to COMDEF descriptor
  373. APROPALIASPTR apropAlias; // Real pointer to ALIAS descriptor
  374. RBTYPE symNext; // Virtual pointer to the next symbol
  375. // Update the appropriate field in the current file symtab entry
  376. apropFile = ((APROPFILEPTR ) FETCHSYM(vrpropFile, TRUE));
  377. symNext = apropFile->af_publics;
  378. apropFile->af_publics = vrprop;
  379. apropName = (APROPNAMEPTR) FETCHSYM(vrprop, TRUE);
  380. if (TYPEOF(rt) == PUBDEF)
  381. apropName->an_sameMod = symNext;
  382. else if (TYPEOF(rt) == COMDEF)
  383. {
  384. apropUndef = (APROPUNDEFPTR) apropName;
  385. apropUndef->au_sameMod = symNext;
  386. }
  387. else if (TYPEOF(rt) == ALIAS)
  388. {
  389. apropAlias = (APROPALIASPTR) apropName;
  390. apropAlias->al_sameMod = symNext;
  391. }
  392. }
  393. LOCAL WORD NEAR IsDebTyp (prop)
  394. APROPSNPTR prop; /* Pointer to segment record */
  395. {
  396. return(prop->as_attr == ATTRLSN && prop->as_rCla == rhteDebTyp);
  397. }
  398. LOCAL WORD NEAR IsDebSym (prop)
  399. APROPSNPTR prop; /* Pointer to segment record */
  400. {
  401. return(prop->as_attr == ATTRLSN && prop->as_rCla == rhteDebSym);
  402. }
  403. /*** DoDebSrc - store source line information
  404. *
  405. * Purpose:
  406. * Stores source line information from object file.
  407. *
  408. * Input:
  409. * No explicit value is passed.
  410. *
  411. * Global variables:
  412. * - vaCVMac - virtual pointer to the free space in the CV info buffer
  413. *
  414. * Output:
  415. * Returns TRUE if the cv info has been stored in the VM ,or FALSE otherwise.
  416. * Side effects:
  417. * - source line information is stored in the VM
  418. *
  419. * Exceptions:
  420. * More than 32Mb of CV information - dispaly error and quit
  421. *
  422. * Notes:
  423. * None.
  424. *
  425. *************************************************************************/
  426. #pragma check_stack(on)
  427. WORD DoDebSrc(void)
  428. {
  429. WORD cbRecSav; // LINNUM record size
  430. APROPFILEPTR apropFile; // Current object file property cell
  431. static SATYPE prevGsn = 0; // GSN of previous LINNUM record
  432. GSNINFO gsnInfo; // GSN info for this LINNUM
  433. static CVSRC FAR *pCurSrc; // Pointer to the current file source info
  434. CVGSN FAR *pCurGsn; // Pointer to the current code segment descriptor
  435. CVGSN FAR *pcvGsn; // Real pointer to the code segment descriptor
  436. CVLINE FAR *pCurLine; // Pointer to the current offset/line pair bucket
  437. RATYPE ra = 0; // Offset
  438. WORD line; // Line number
  439. RATYPE raPrev; // Offset of the previous line
  440. WORD fChangeInSource;
  441. WORD fComdatSplit;
  442. DWORD gsnStart; // Start of this gsn
  443. APROPSNPTR apropSn;
  444. WORD align;
  445. WORD threshold;
  446. #if !defined( M_I386 ) && !defined( _WIN32 )
  447. SBTYPE nameBuf;
  448. #endif
  449. cbRecSav = cbRec;
  450. if (!GetGsnInfo(&gsnInfo))
  451. return(FALSE);
  452. // If LINNUM record is empty, don't do anything
  453. if (cbRec == 1)
  454. return(FALSE);
  455. apropFile = (APROPFILEPTR ) FETCHSYM(vrpropFile, TRUE);
  456. // If there is a new source file allocate new CVSRC structure
  457. // and link it to the current object file descriptor
  458. fChangeInSource = (WORD) (apropFile->af_Src == 0 || !SbCompare(sbModule, sbLastModule,TRUE));
  459. if (fChangeInSource)
  460. {
  461. #if CVDEBUG
  462. sbModule[sbModule[0]+1]='\0';
  463. sbLastModule[sbLastModule[0]+1]='\0';
  464. fprintf(stdout, "Change in source file; from '%s' to '%s'\r\n", &sbLastModule[1], &sbModule[1]);
  465. #endif
  466. // Search the list of CVSRC structures for this object
  467. // file and find out if we heave already seen this source file
  468. for (pCurSrc = apropFile->af_Src; pCurSrc;)
  469. {
  470. #if defined(M_I386) || defined( _WIN32 )
  471. if (SbCompare(sbModule, pCurSrc->fname, TRUE))
  472. #else
  473. FMEMCPY((char FAR *) nameBuf, pCurSrc->fname, pCurSrc->fname[0] + 1);
  474. if (SbCompare(sbModule, nameBuf, TRUE))
  475. #endif
  476. break;
  477. else
  478. pCurSrc = pCurSrc->next;
  479. }
  480. if (pCurSrc == NULL)
  481. {
  482. // New source file
  483. pCurSrc = (CVSRC FAR *) GetMem(sizeof(CVSRC));
  484. pCurSrc->fname = GetMem(sbModule[0] + 1);
  485. FMEMCPY(pCurSrc->fname, (char FAR *) sbModule, sbModule[0] + 1);
  486. if (apropFile->af_Src == NULL)
  487. apropFile->af_Src = pCurSrc;
  488. else
  489. apropFile->af_SrcLast->next = pCurSrc;
  490. apropFile->af_SrcLast = pCurSrc;
  491. }
  492. else
  493. {
  494. // We have already seen this source file
  495. }
  496. memcpy(sbLastModule, sbModule, B2W(sbModule[0]) + 1);
  497. }
  498. else
  499. {
  500. // Use descriptor set last time we changed source files
  501. }
  502. // Allocate the new CVGSN structure if any of the following is true
  503. //
  504. // - this is first batch of source lines
  505. // - there is a change in GSNs
  506. // - there is a change in source file
  507. // - we have source lines for explicitly allocated COMDAT
  508. // In this last case we assume that the begin portion of a
  509. // given logical segment (gsn) has been filled with contributions
  510. // from many object files. Because COMDATs are allocated after all
  511. // the object files are read, then adding source
  512. // lines of COMDAT to the source lines of preceeding LEDATA records
  513. // will mask the contributions from other object files, as the picture
  514. // below shows:
  515. //
  516. // +-------------+<--+
  517. // | | |
  518. // | LEDATA from | |
  519. // | a.obj | |
  520. // | | |
  521. // +-------------+ |
  522. // | | | Without splitting into fake CVGSN
  523. // | LEDATA from | \ the source line for a.obj will
  524. // | b.obj | / hide the LEDATA contribution from b.obj
  525. // | | |
  526. // +-------------+ |
  527. // | | |
  528. // | COMDAT from | |
  529. // | a.obj | |
  530. // | | |
  531. // +-------------+<--+
  532. // | |
  533. // | COMDAT from |
  534. // | b.obj |
  535. // | |
  536. // +-------------+
  537. //
  538. // This will be unnecessary only if COMDAT from a.obj immediately
  539. // follows LEDATA from a.obj
  540. fComdatSplit = FALSE;
  541. pCurGsn = pCurSrc->pGsnLast;
  542. if (pCurGsn)
  543. {
  544. // Assume we will be using the current CVGSN
  545. if (gsnInfo.fComdat)
  546. {
  547. // Source lines from LINSYM - Calculate the threshold
  548. apropSn = (APROPSNPTR ) FETCHSYM(mpgsnrprop[gsnInfo.gsn], FALSE);
  549. if (gsnInfo.comdatAlign)
  550. align = gsnInfo.comdatAlign;
  551. else
  552. align = (WORD) ((apropSn->as_tysn >> 2) & 7);
  553. threshold = 1;
  554. switch (align)
  555. {
  556. case ALGNWRD:
  557. threshold = 2;
  558. break;
  559. #if OMF386
  560. case ALGNDBL:
  561. threshold = 4;
  562. break;
  563. #endif
  564. case ALGNPAR:
  565. threshold = 16;
  566. break;
  567. case ALGNPAG:
  568. threshold = 256;
  569. break;
  570. }
  571. // Check if we have to split CVGSN for this COMDAT
  572. fComdatSplit = !fSameComdat &&
  573. !(apropSn->as_fExtra & COMDAT_SEG) &&
  574. (gsnInfo.comdatRa - pCurGsn->raEnd > threshold);
  575. }
  576. else
  577. {
  578. // Source lines from LINNUM
  579. if (pCurGsn->flags & SPLIT_GSN)
  580. {
  581. // The LINNUM record following the LINSYM record that
  582. // caused CVGSN split - we have to move back on CVGSN
  583. // list until we find first CVGSN not marked as SPLIT_GSN
  584. for (pcvGsn = pCurGsn->prev; pcvGsn != (CVGSN FAR *) pCurSrc;)
  585. {
  586. if (!(pcvGsn->flags & SPLIT_GSN))
  587. break;
  588. else
  589. pcvGsn = pcvGsn->prev;
  590. }
  591. if (pcvGsn == (CVGSN FAR *) pCurSrc)
  592. {
  593. // There are only SPLIT_GSN on the list - make new CVGSN
  594. prevGsn = 0;
  595. }
  596. else
  597. {
  598. // Use the first non SPLIT_GSN CVGSN as current one
  599. pCurGsn = pcvGsn;
  600. }
  601. }
  602. }
  603. }
  604. if ((prevGsn == 0) ||
  605. (mpgsnseg[gsnInfo.gsn] != mpgsnseg[prevGsn]) ||
  606. fChangeInSource ||
  607. fComdatSplit)
  608. {
  609. // Make new CVGSN
  610. // Remember LOGICAL segment
  611. pCurGsn = (CVGSN FAR *) GetMem(sizeof(CVGSN));
  612. pCurGsn->seg = mpgsnseg[gsnInfo.gsn];
  613. // The start and end offset will be derived from line number/offset pairs
  614. pCurGsn->raStart = 0xffffffff;
  615. if (fComdatSplit)
  616. pCurGsn->flags |= SPLIT_GSN;
  617. if (pCurSrc->pGsnFirst == NULL)
  618. {
  619. pCurSrc->pGsnFirst = pCurGsn;
  620. pCurGsn->prev = (CVGSN FAR *) pCurSrc;
  621. }
  622. else
  623. {
  624. pCurSrc->pGsnLast->next = pCurGsn;
  625. pCurGsn->prev = pCurSrc->pGsnLast;
  626. }
  627. pCurSrc->pGsnLast = pCurGsn;
  628. pCurSrc->cSegs++;
  629. #if CVDEBUG
  630. sbModule[sbModule[0]+1] = '\0';
  631. fprintf(stdout, "New code segment in '%s'; prevGsn = %x; newGsn = %x %s\r\n", &sbModule[1], prevGsn, gsnInfo.gsn, fComdatSplit ? "COMDAT split" : "");
  632. #endif
  633. prevGsn = gsnInfo.gsn;
  634. }
  635. // Get the offset/line bucket
  636. if (pCurGsn->pLineFirst == NULL)
  637. {
  638. pCurLine = (CVLINE FAR *) GetMem(sizeof(CVLINE));
  639. pCurGsn->pLineFirst = pCurLine;
  640. pCurGsn->pLineLast = pCurLine;
  641. }
  642. else
  643. pCurLine = pCurGsn->pLineLast;
  644. // Fill in offset/line bucket
  645. if (gsnInfo.fComdat)
  646. gsnStart = gsnInfo.comdatRa;
  647. else
  648. gsnStart = mpgsndra[gsnInfo.gsn] - mpsegraFirst[pCurGsn->seg];
  649. raPrev = 0xffff;
  650. while (cbRec > 1) // While not at checksum
  651. {
  652. GetLineOff(&line, &ra);
  653. ra += gsnStart;
  654. // We have to eliminate line pairs with same ra (for MASM 5.1)
  655. if(ra == raPrev)
  656. continue;
  657. raPrev = ra;
  658. // Remember the smallest LOGICAL offset for source line
  659. if (ra < pCurGsn->raStart)
  660. pCurGsn->raStart = ra;
  661. if (line != 0)
  662. {
  663. if (pCurLine->cPair >= CVLINEMAX)
  664. {
  665. pCurLine->next = (CVLINE FAR *) GetMem(sizeof(CVLINE));
  666. pCurLine = pCurLine->next;
  667. pCurGsn->pLineLast = pCurLine;
  668. }
  669. pCurLine->rgOff[pCurLine->cPair] = ra;
  670. pCurLine->rgLn[pCurLine->cPair] = line;
  671. pCurLine->cPair++;
  672. pCurSrc->cLines++;
  673. pCurGsn->cLines++;
  674. }
  675. }
  676. // Remember last line LOGICAL offset
  677. pCurGsn->raEnd = ra;
  678. #if CVDEBUG
  679. fprintf(stdout, "New source lines for the 0x%x logical code segment; lines %d\r\n start offset %x:%lx end offset %x:%lx; physical address of logical segment %x:%lx\r\n",
  680. pCurGsn->seg, pCurGsn->cLines, pCurGsn->seg, pCurGsn->raStart, pCurGsn->seg, pCurGsn->raEnd, mpsegsa[pCurGsn->seg], mpsegraFirst[pCurGsn->seg]);
  681. #endif
  682. // If /LINENUMBERS and list file open, back up
  683. if (vfLineNos && fLstFileOpen)
  684. {
  685. #if ALIGN_REC
  686. pbRec += (cbRec - cbRecSav);
  687. #else
  688. fseek(bsInput, (long)cbRec - cbRecSav, 1);
  689. #endif
  690. cbRec = cbRecSav;
  691. }
  692. return(TRUE);
  693. }
  694. #pragma check_stack(off)
  695. /*** CheckTables - check space in table used by OutSrcModule
  696. *
  697. * Purpose:
  698. * While building the new source module subsection linker needs
  699. * to store a lot of information about given source file. Since
  700. * we can't predict how many source files were compiled to obtain
  701. * this object module or to how many logical segments this object
  702. * module contributes code we have to dynamically resize appropriate
  703. * tables.
  704. *
  705. * Input:
  706. * cFiles - number of source files compiled to produce
  707. * this object module
  708. * cSegs - number of logical segments this object module
  709. * contributes to.
  710. *
  711. * Output:
  712. * No explicit value is returned. As a side effect the following
  713. * tables are allocated or reallocated:
  714. *
  715. * fileBase - table of offsets to source file info
  716. * raSeg - table of physical starting and ending offsets
  717. * of the contribution to the logical segments
  718. * segNo - table of physical segment indicies
  719. *
  720. * Exceptions:
  721. * Memory allocation problems - fatal error and exit.
  722. *
  723. * Notes:
  724. * When we reallocated the tables we don't have to copy
  725. * their old content, because it was used in the previous
  726. * object module.
  727. *
  728. *************************************************************************/
  729. LOCAL void NEAR CheckTables(WORD cFiles, WORD cSegs)
  730. {
  731. WORD cCur;
  732. cCur = (WORD) (cFiles < cSegs ? cSegs : cFiles);
  733. if (cCur > cMac)
  734. {
  735. // We have to reallocate tables or allocate for the first time
  736. if (fileBase)
  737. FFREE(fileBase);
  738. if (raSeg)
  739. FFREE(raSeg);
  740. if (segNo)
  741. FFREE(segNo);
  742. fileBase = (DWORD FAR *) GetMem(cCur*sizeof(DWORD));
  743. raSeg = (RAPAIR FAR *) GetMem(cCur*sizeof(RAPAIR));
  744. segNo = (WORD FAR *) GetMem(cCur*sizeof(WORD));
  745. cMac = cCur;
  746. }
  747. }
  748. /*** OutSrcModule - write CV source module
  749. *
  750. * Purpose:
  751. * Create the CV 4.00 format source module descrbing the source line
  752. * number to addressing mapping information for one object file
  753. *
  754. * Input:
  755. * - pSrcLines - the list of source file information blocks
  756. *
  757. * Output:
  758. * Total size of the subsection in bytes.
  759. *
  760. * Exceptions:
  761. * None.
  762. *
  763. * Notes:
  764. * None.
  765. *
  766. *************************************************************************/
  767. LOCAL DWORD NEAR OutSrcModule(CVSRC FAR *pSrcLines)
  768. {
  769. CVSRC FAR *pCurSrc; // Pointer to current source file
  770. CVGSN FAR *pCurGsn; // Pointer to current code segment
  771. CVLINE FAR *pLine; // Pointer to source line bucket
  772. WORD cFiles; // Number of source files
  773. WORD cSegs; // Number of code segments
  774. WORD xFile;
  775. WORD xSeg;
  776. DWORD sizeTotal; // Size of source subsection
  777. DWORD srcLnBase;
  778. WORD counts[2];
  779. CVLINE FAR *pTmp;
  780. #if SRCDEBUG
  781. DumpSrcLines(vaLines);
  782. #endif
  783. // Count total number of source files, total number of code segments
  784. for (pCurSrc = pSrcLines, cFiles = 0, cSegs = 0; pCurSrc; cFiles++, pCurSrc = pCurSrc->next)
  785. cSegs += pCurSrc->cSegs;
  786. CheckTables(cFiles, cSegs);
  787. sizeTotal = (DWORD) (2*sizeof(WORD) + cFiles*sizeof(DWORD) +
  788. cSegs*(sizeof(raSeg[0]) + sizeof(WORD)));
  789. sizeTotal = Round2Dword(sizeTotal);
  790. // Make second pass througth the source files and fill in
  791. // source module header
  792. for (pCurSrc = pSrcLines, xFile = 0, xSeg = 0; xFile < cFiles && pCurSrc; xFile++, pCurSrc = pCurSrc->next)
  793. {
  794. fileBase[xFile] = sizeTotal;
  795. // Add the size of this source file information:
  796. //
  797. // Source file header:
  798. //
  799. // +------+------+------------+--------------+------+-------------+
  800. // | WORD | WORD | cSeg*DWORD | 2*cSeg*DWORD | BYTE | cbName*BYTE |
  801. // +------+------+------------+--------------+------+-------------+
  802. //
  803. sizeTotal += (2*sizeof(WORD) +
  804. pCurSrc->cSegs*(sizeof(DWORD) + sizeof(raSeg[0])) +
  805. sizeof(BYTE) + pCurSrc->fname[0]);
  806. // Pad to DWORD boundary
  807. sizeTotal = Round2Dword(sizeTotal);
  808. // Walk code segment list
  809. for (pCurGsn = pCurSrc->pGsnFirst; pCurGsn; pCurGsn = pCurGsn->next, xSeg++)
  810. {
  811. raSeg[xSeg].raStart = pCurGsn->raStart;
  812. raSeg[xSeg].raEnd = pCurGsn->raEnd;
  813. segNo[xSeg] = pCurGsn->seg;
  814. // Add size of the offset/line table
  815. //
  816. // +------+------+-------------+------------+
  817. // | WORD | WORD | cLine*DWORD | cLine*WORD |
  818. // +------+------+-------------+------------+
  819. sizeTotal += (2*sizeof(WORD) +
  820. pCurGsn->cLines*(sizeof(DWORD) + sizeof(WORD)));
  821. // Pad to DWORD boundary
  822. sizeTotal = Round2Dword(sizeTotal);
  823. }
  824. }
  825. // Write source module header
  826. counts[0] = cFiles;
  827. counts[1] = cSegs;
  828. WriteCopy(counts, sizeof(counts));
  829. WriteCopy(fileBase, cFiles*sizeof(DWORD));
  830. WriteCopy(raSeg, cSegs*sizeof(RAPAIR));
  831. WriteCopy(segNo, cSegs*sizeof(WORD));
  832. // Pad to DWORD boundary
  833. Pad2Dword();
  834. // Make third pass througth the source files and fill in
  835. // the source file header and write offset/line pairs
  836. for (pCurSrc = pSrcLines, srcLnBase = fileBase[0]; pCurSrc != NULL;
  837. pCurSrc = pCurSrc->next, xFile++)
  838. {
  839. // Add the size of source file header:
  840. //
  841. // +------+------+------------+--------------+------+-------------+
  842. // | WORD | WORD | cSeg*DWORD | 2*cSeg*DWORD | BYTE | cbName*BYTE |
  843. // +------+------+------------+--------------+------+-------------+
  844. //
  845. srcLnBase += (2*sizeof(WORD) +
  846. pCurSrc->cSegs*(sizeof(DWORD) + sizeof(raSeg[0])) +
  847. sizeof(BYTE) + pCurSrc->fname[0]);
  848. // Round to DWORD boundary
  849. srcLnBase = Round2Dword(srcLnBase);
  850. // Walk code segment list and store base offsets for source
  851. // line offset/line pairs and record start/stop offsets of
  852. // code segments
  853. for (xSeg = 0, pCurGsn = pCurSrc->pGsnFirst; pCurGsn != NULL;
  854. pCurGsn = pCurGsn->next, xSeg++)
  855. {
  856. fileBase[xSeg] = srcLnBase;
  857. srcLnBase += (2*sizeof(WORD) +
  858. pCurGsn->cLines*(sizeof(DWORD) + sizeof(WORD)));
  859. // Round to DWORD boundary
  860. srcLnBase = Round2Dword(srcLnBase);
  861. raSeg[xSeg].raStart = pCurGsn->raStart;
  862. raSeg[xSeg].raEnd = pCurGsn->raEnd;
  863. }
  864. // Write source file header
  865. counts[0] = (WORD) pCurSrc->cSegs;
  866. counts[1] = 0;
  867. WriteCopy(counts, sizeof(counts));
  868. WriteCopy(fileBase, pCurSrc->cSegs*sizeof(DWORD));
  869. WriteCopy(raSeg, pCurSrc->cSegs*sizeof(RAPAIR));
  870. WriteCopy(pCurSrc->fname, pCurSrc->fname[0] + 1);
  871. // Pad to DWORD boundary
  872. Pad2Dword();
  873. // Walk code segment list and write offsets/line pairs
  874. for (pCurGsn = pCurSrc->pGsnFirst; pCurGsn != NULL; pCurGsn = pCurGsn->next)
  875. {
  876. // Write segment index and number of offset/line pairs
  877. counts[0] = pCurGsn->seg;
  878. counts[1] = pCurGsn->cLines;
  879. WriteCopy(counts, sizeof(counts));
  880. // Write offsets
  881. for (pLine = pCurGsn->pLineFirst; pLine != NULL; pLine = pLine->next)
  882. WriteCopy(&(pLine->rgOff), pLine->cPair * sizeof(DWORD));
  883. // Write line numbers
  884. for (pLine = pCurGsn->pLineFirst; pLine != NULL; pLine = pLine->next)
  885. WriteCopy(&(pLine->rgLn), pLine->cPair * sizeof(WORD));
  886. // Pad to DWORD boundary
  887. Pad2Dword();
  888. // Free memory
  889. for (pLine = pCurGsn->pLineFirst; pLine != NULL;)
  890. {
  891. pTmp = pLine->next;
  892. FFREE(pLine);
  893. pLine = pTmp;
  894. }
  895. }
  896. }
  897. return(sizeTotal);
  898. }
  899. /*** SaveCode - save code segment information in MODULES entry
  900. *
  901. * Purpose:
  902. * For every module (.OBJ file) save the information about code segments
  903. * this module contributes to. COMDATs are threated as contibutions to
  904. * the logical segment, so each gets its entry in the CVCODE list attached
  905. * to the given .OBJ file (module).
  906. *
  907. * Input:
  908. * gsn - global segment index of logical segment to which this module
  909. * contributes
  910. * cb - size (in bytes) of contribution
  911. * raInit - offset of the contribution inside the logical segment; this
  912. * nonzero only for COMDATs.
  913. *
  914. * Output:
  915. * No explicit value is returned. The list of CVCODE attached to the
  916. * .OBJ file (module) is updated.
  917. *
  918. * Exceptions:
  919. * None.
  920. *
  921. * Notes:
  922. * None.
  923. *
  924. *************************************************************************/
  925. void SaveCode(SNTYPE gsn, DWORD cb, DWORD raInit)
  926. {
  927. CVCODE FAR *pSegCur; // Pointer to the current code segment
  928. APROPFILEPTR apropFile;
  929. apropFile = (APROPFILEPTR) vrpropFile;
  930. // Save code segment if module has CV info
  931. pSegCur = (CVCODE FAR *) GetMem(sizeof(CVCODE));
  932. // Store LOGICAL segment, offset and size of the contribution
  933. pSegCur->seg = mpgsnseg[gsn];
  934. if (raInit != 0xffffffffL)
  935. pSegCur->ra = raInit;
  936. else
  937. pSegCur->ra = mpgsndra[gsn] - mpsegraFirst[mpgsnseg[gsn]];
  938. pSegCur->cb = cb;
  939. // Add to the CV code list
  940. if (apropFile->af_Code == NULL)
  941. apropFile->af_Code = pSegCur;
  942. else
  943. apropFile->af_CodeLast->next = pSegCur;
  944. apropFile->af_CodeLast = pSegCur;
  945. apropFile->af_cCodeSeg++;
  946. }
  947. /****************************************************************
  948. * *
  949. * DO SYMBOLIC DEBUG STUFF FOR MODULE JUST PROCESSED. *
  950. * Pass 2. *
  951. * *
  952. ****************************************************************/
  953. void DebMd2(void)
  954. {
  955. APROPFILEPTR apropFile;
  956. sbLastModule[0] = 0; /* Force recognition of new THEADR */
  957. apropFile = (APROPFILEPTR) vrpropFile;
  958. if (apropFile->af_cvInfo)
  959. ++segDebLast;
  960. }
  961. /*** PutDnt - store subsection directory entry in the table
  962. *
  963. * Purpose:
  964. * Copy current subsection directory to the DNT table. If no more
  965. * room in the table reallocate table doubling its size.
  966. *
  967. * Input:
  968. * - pDnt - pointer to the current directory entry
  969. *
  970. * Output:
  971. * No explicit value is returned.
  972. *
  973. * Exceptions:
  974. * None.
  975. *
  976. * Notes:
  977. * None.
  978. *
  979. *************************************************************************/
  980. LOCAL void NEAR PutDnt(DNT *pDnt)
  981. {
  982. WORD newSize;
  983. if (dntMac >= dntMax)
  984. {
  985. if(dntMax)
  986. {
  987. newSize = dntMax << 1;
  988. #if defined(M_I386) || defined( _WIN32 )
  989. {
  990. BYTE *pb = REALLOC(rgDnt, newSize * sizeof(DNT));
  991. if (!pb)
  992. Fatal(ER_memovf);
  993. rgDnt = (DNT *)pb;
  994. }
  995. #else
  996. rgDnt = (DNT FAR *) _frealloc(rgDnt, newSize * sizeof(DNT));
  997. #endif
  998. }
  999. else
  1000. {
  1001. newSize = DNT_START;
  1002. rgDnt = (DNT*) GetMem ( newSize * sizeof(DNT) );
  1003. }
  1004. if (rgDnt == NULL)
  1005. Fatal(ER_memovf);
  1006. dntMax = newSize;
  1007. }
  1008. rgDnt[dntMac] = *pDnt;
  1009. dntMac++;
  1010. #if CVDEBUG
  1011. DumpDNT(pDnt);
  1012. #endif
  1013. }
  1014. #pragma check_stack(on)
  1015. /*** OutModule - write out module subsection
  1016. *
  1017. * Purpose:
  1018. * Write into the executable file the module subsections for all
  1019. * object files compiled with CV information. Only CV 4.0 format.
  1020. *
  1021. * Input:
  1022. * - apropFile - pointer to the current object file descriptor
  1023. *
  1024. * Output:
  1025. * No explicit value is retuned.
  1026. * Side effects:
  1027. * - module subsections in executable file
  1028. *
  1029. * Exceptions:
  1030. * None.
  1031. *
  1032. * Notes:
  1033. * None.
  1034. *
  1035. *************************************************************************/
  1036. LOCAL DWORD NEAR OutModule(APROPFILEPTR apropFile)
  1037. {
  1038. SBTYPE sbName;
  1039. SSTMOD4 module;
  1040. CVCODE FAR *pSegCur;
  1041. CODEINFO codeOnt;
  1042. WORD cOnt;
  1043. module.ovlNo = (WORD) apropFile->af_iov;
  1044. module.iLib = (WORD) (apropFile->af_ifh + 1);
  1045. module.cSeg = apropFile->af_cCodeSeg;
  1046. module.style[0] = 'C';
  1047. module.style[1] = 'V';
  1048. // Get file name or library module name
  1049. if (apropFile->af_ifh != FHNIL && apropFile->af_rMod != RHTENIL)
  1050. GetName((AHTEPTR) apropFile->af_rMod, sbName);
  1051. else
  1052. GetName((AHTEPTR) apropFile, sbName);
  1053. #if CVDEBUG
  1054. sbName[sbName[0]+1] = '\0';
  1055. fprintf(stdout, "\r\nCV info for %s\r\n", &sbName[1]);
  1056. #endif
  1057. // Write sstModule header followed by the list of code contributions
  1058. WriteCopy(&module, sizeof(SSTMOD4));
  1059. pSegCur = apropFile->af_Code;
  1060. codeOnt.pad = 0;
  1061. for (cOnt = 0; cOnt < module.cSeg && pSegCur; cOnt++, pSegCur = pSegCur->next)
  1062. {
  1063. codeOnt.seg = pSegCur->seg;
  1064. codeOnt.off = pSegCur->ra;
  1065. codeOnt.cbOnt = pSegCur->cb;
  1066. WriteCopy(&codeOnt, sizeof(CODEINFO));
  1067. #if CVDEBUG
  1068. fprintf(stdout, " Logical segment %d; offset 0x%lx; size 0x%lx\r\n",
  1069. codeOnt.seg, codeOnt.off, codeOnt.cbOnt);
  1070. #endif
  1071. }
  1072. // Write object file name
  1073. WriteCopy(sbName, B2W(sbName[0]) + 1);
  1074. return(sizeof(SSTMOD4) + B2W(sbName[0]) + 1 + module.cSeg * sizeof(CODEINFO));
  1075. }
  1076. /*** OutPublics - write sstPublics subsection
  1077. *
  1078. * Purpose:
  1079. * Write sstPublics subsection of the CV information. The subsection
  1080. * conforms to the new CV 4.0 format.
  1081. *
  1082. * Input:
  1083. * - firstPub - virtual pointer to the list of public symbols defined
  1084. * in a given object module
  1085. *
  1086. * Output:
  1087. * Total size of the subsection in bytes.
  1088. *
  1089. * Exceptions:
  1090. * None.
  1091. *
  1092. * Notes:
  1093. * None.
  1094. *
  1095. *************************************************************************/
  1096. LOCAL DWORD NEAR OutPublics(RBTYPE firstPub)
  1097. {
  1098. PUB16 pub16; // CV public descriptor - 16-bit
  1099. PUB32 pub32; // CV public descriptor - 32-bit
  1100. APROPNAMEPTR apropPub; // Real pointer to public descriptor
  1101. APROPSNPTR apropSn; // Real pointer to segment descriptor
  1102. RBTYPE curPub; // Virtual pointer to the current public symbol
  1103. WORD f32Bit; // TRUE if public defined in 32-bit segment
  1104. DWORD sizeTotal; // Total size of subsection
  1105. SNTYPE seg; // Symbol base
  1106. RATYPE ra; // Symbol offset
  1107. WORD CVtype; // CV info type index
  1108. SBTYPE sbName; // Public symbol
  1109. char *pPub;
  1110. WORD len;
  1111. // Initialize
  1112. curPub = firstPub;
  1113. pub16.idx = S_PUB16;
  1114. pub32.idx = S_PUB32;
  1115. sizeTotal = 1L;
  1116. WriteCopy(&sizeTotal, sizeof(DWORD));// sstPublicSym signature
  1117. sizeTotal = sizeof(DWORD);
  1118. while (curPub != 0L)
  1119. {
  1120. f32Bit = FALSE;
  1121. apropPub = (APROPNAMEPTR) FETCHSYM(curPub, FALSE);
  1122. curPub = apropPub->an_sameMod;
  1123. if (apropPub->an_attr == ATTRALIAS)
  1124. apropPub = (APROPNAMEPTR) FETCHSYM(((APROPALIASPTR) apropPub)->al_sym, FALSE);
  1125. if (apropPub->an_attr != ATTRPNM)
  1126. continue;
  1127. ra = apropPub->an_ra;
  1128. if (apropPub->an_gsn) // If not absolute symbol
  1129. {
  1130. seg = mpgsnseg[apropPub->an_gsn];
  1131. // If this is a .com program and the segment is the one
  1132. // moved by 0x100, adjust accordingly the SegMap entry
  1133. if(seg == segAdjCom)
  1134. {
  1135. #if FALSE
  1136. GetName((AHTEPTR) apropPub, sbName);
  1137. sbName[sbName[0]+1] = '\0';
  1138. fprintf(stdout, "\r\nCorrecting public %s : %lx -> %lx", sbName+1, ra, ra+0x100);
  1139. fflush(stdout);
  1140. #endif
  1141. ra += 0x100;
  1142. }
  1143. CVtype = 0; // Should be this apropPub->an_CVtype
  1144. // but cvpack can't handle it.
  1145. #if O68K
  1146. if (iMacType == MAC_NONE)
  1147. #endif
  1148. ra -= mpsegraFirst[seg];
  1149. #if CVDEBUG
  1150. GetName((AHTEPTR) apropPub, sbName);
  1151. sbName[sbName[0]+1] = '\0';
  1152. fprintf(stdout, "'%s' --> logical address %2x:%lx; physical address %2x:%lx\r\n",
  1153. &sbName[1], seg, ra, mpsegsa[seg], apropPub->an_ra);
  1154. #endif
  1155. apropSn = (APROPSNPTR) FETCHSYM(mpgsnrprop[apropPub->an_gsn], FALSE);
  1156. #if EXE386
  1157. f32Bit = TRUE;
  1158. #else
  1159. f32Bit = (WORD) Is32BIT(apropSn->as_flags);
  1160. #endif
  1161. }
  1162. else
  1163. {
  1164. seg = 0; // Else no base
  1165. CVtype = T_ABS; // CV absolute symbol type
  1166. f32Bit = (WORD) (ra > LXIVK);
  1167. }
  1168. GetName((AHTEPTR) apropPub, sbName);
  1169. if (f32Bit)
  1170. {
  1171. pub32.len = (WORD) (sizeof(PUB32) + B2W(sbName[0]) + 1 - sizeof(WORD));
  1172. pub32.off = ra;
  1173. pub32.seg = seg;
  1174. pub32.type = CVtype;
  1175. pPub = (char *) &pub32;
  1176. len = sizeof(PUB32);
  1177. }
  1178. else
  1179. {
  1180. pub16.len = (WORD) (sizeof(PUB16) + B2W(sbName[0]) + 1 - sizeof(WORD));
  1181. pub16.off = (WORD) ra;
  1182. pub16.seg = seg;
  1183. pub16.type = CVtype;
  1184. pPub = (char *) &pub16;
  1185. len = sizeof(PUB16);
  1186. }
  1187. WriteCopy(pPub, len);
  1188. // Output length-prefixed name
  1189. WriteCopy(sbName, sbName[0] + 1);
  1190. sizeTotal += (len + B2W(sbName[0]) + 1);
  1191. }
  1192. return(sizeTotal);
  1193. }
  1194. /*** OutSegMap - write segment map
  1195. *
  1196. * Purpose:
  1197. * This subsection was introduced in CV 4.0. This subsection
  1198. * maps the logical segments to physical segments. It also gives
  1199. * the names and sizes of each logical segment.
  1200. *
  1201. * Input:
  1202. * No explicit value is passed.
  1203. * Global variables:
  1204. * - mpsegsa - table mapping logical segment number to its physical
  1205. * segment number or address
  1206. * - mpsaflags - table mapping physicla segment index to its flags
  1207. * - mpseggsn - table mapping the logical segment index to its global
  1208. * segment index
  1209. * - mpgsnprop - table mapping global segment index to its symbol table
  1210. * descriptor
  1211. * - mpggrgsn - table mapping global group index to global segment index
  1212. * - mpggrrhte - table mapping global group index to group name
  1213. *
  1214. * Output:
  1215. * Function returns the size of segment map.
  1216. *
  1217. * Exceptions:
  1218. * None.
  1219. *
  1220. * Notes:
  1221. * None.
  1222. *
  1223. *************************************************************************/
  1224. LOCAL DWORD NEAR OutSegMap(void)
  1225. {
  1226. SEGTYPE seg; // Logical segment index
  1227. APROPSNPTR apropSn; // Real pointer to logical segment descriptor
  1228. SATYPE sa; // Physical segment index
  1229. WORD iName; // Index to free space in segment name table
  1230. DWORD sizeTotal; // Total size of the subsection
  1231. SEGINFO segInfo; // CV segment descriptor
  1232. SBTYPE segName; // Segment name
  1233. AHTEPTR ahte; // Real pointer to symbol table hash table
  1234. RBTYPE vpClass; // Virtual pointer to class descriptor
  1235. GRTYPE ggr; // Global group index
  1236. SATYPE saDGroup; // DGroup's sa
  1237. WORD counts[2];
  1238. iName = 0;
  1239. counts[0] = (WORD) (segLast + ggrMac - 1);
  1240. counts[1] = (WORD) segLast;
  1241. WriteCopy(counts, sizeof(counts));
  1242. sizeTotal = sizeof(counts);
  1243. saDGroup = mpsegsa[mpgsnseg[mpggrgsn[ggrDGroup]]];
  1244. // Write all logical segments
  1245. for (seg = 1; seg <= segLast; ++seg)// For all logical segments
  1246. {
  1247. memset(&segInfo, 0, sizeof(SEGINFO));
  1248. if (fNewExe)
  1249. segInfo.flags.fSel = TRUE;
  1250. sa = mpsegsa[seg];
  1251. if (fNewExe)
  1252. {
  1253. #if EXE386
  1254. segInfo.flags.f32Bit = TRUE;
  1255. #else
  1256. segInfo.flags.f32Bit = (WORD) (Is32BIT(mpsaflags[sa]));
  1257. #endif
  1258. if (IsDataFlg(mpsaflags[sa]))
  1259. {
  1260. segInfo.flags.fRead = TRUE;
  1261. #if EXE386
  1262. if (IsWRITEABLE(mpsaflags[sa]))
  1263. #else
  1264. if (!(mpsaflags[sa] & NSEXRD))
  1265. #endif
  1266. segInfo.flags.fWrite = TRUE;
  1267. }
  1268. else
  1269. {
  1270. segInfo.flags.fExecute = TRUE;
  1271. #if EXE386
  1272. if (IsREADABLE(mpsaflags[sa]))
  1273. #else
  1274. if (!(mpsaflags[sa] & NSEXRD))
  1275. #endif
  1276. segInfo.flags.fRead = TRUE;
  1277. }
  1278. }
  1279. else
  1280. {
  1281. if (mpsegFlags[seg] & FCODE)
  1282. {
  1283. segInfo.flags.fRead = TRUE;
  1284. segInfo.flags.fExecute = TRUE;
  1285. }
  1286. else
  1287. {
  1288. segInfo.flags.fRead = TRUE;
  1289. segInfo.flags.fWrite = TRUE;
  1290. }
  1291. }
  1292. // Look up segment definition
  1293. apropSn = (APROPSNPTR) FETCHSYM(mpgsnrprop[mpseggsn[seg]], FALSE);
  1294. vpClass = apropSn->as_rCla;
  1295. #if OVERLAYS
  1296. if (!fNewExe)
  1297. segInfo.ovlNbr = apropSn->as_iov;
  1298. #endif
  1299. // if segment doesn't belong to any group it's ggr is 0
  1300. if (apropSn->as_ggr != GRNIL)
  1301. segInfo.ggr = (WORD) (apropSn->as_ggr + segLast - 1);
  1302. // If segment is a DGROUP member, write DGROUP normalized address
  1303. if(apropSn->as_ggr == ggrDGroup)
  1304. {
  1305. segInfo.sa = saDGroup;
  1306. segInfo.phyOff = mpsegraFirst[seg] + ((sa - saDGroup) << 4);
  1307. }
  1308. else
  1309. {
  1310. segInfo.sa = sa;
  1311. segInfo.phyOff = mpsegraFirst[seg];
  1312. }
  1313. // If this is a .com program and the segment is the one moved by 0x100
  1314. // write all the publics at the original addresses, because the offset
  1315. // adjustment will be made in the SegMap table
  1316. if(seg == segAdjCom)
  1317. {
  1318. segInfo.phyOff -= 0x100;
  1319. }
  1320. segInfo.cbSeg = apropSn->as_cbMx;
  1321. GetName((AHTEPTR) apropSn, segName);
  1322. if (segName[0] != '\0')
  1323. {
  1324. segInfo.isegName = iName;
  1325. iName += (WORD) (B2W(segName[0]) + 1);
  1326. }
  1327. else
  1328. segInfo.isegName = 0xffff;
  1329. ahte = (AHTEPTR) FETCHSYM(vpClass, FALSE);
  1330. if (ahte->cch[0] != 0)
  1331. {
  1332. segInfo.iclassName = iName;
  1333. iName += (WORD) (B2W(ahte->cch[0]) + 1);
  1334. }
  1335. else
  1336. segInfo.iclassName = 0xffff;
  1337. WriteCopy(&segInfo, sizeof(SEGINFO));
  1338. sizeTotal += sizeof(SEGINFO);
  1339. }
  1340. // Write all groups
  1341. for (ggr = 1; ggr < ggrMac; ggr++)
  1342. {
  1343. memset(&segInfo, 0, sizeof(SEGINFO));
  1344. segInfo.flags.fGroup = TRUE;
  1345. if (fNewExe)
  1346. segInfo.flags.fSel = TRUE;
  1347. segInfo.sa = mpsegsa[mpgsnseg[mpggrgsn[ggr]]];
  1348. if (fNewExe)
  1349. segInfo.cbSeg = mpsacb[segInfo.sa];
  1350. else
  1351. {
  1352. segInfo.cbSeg = 0L;
  1353. if (mpggrgsn[ggr] != SNNIL)
  1354. {
  1355. // If group has members
  1356. for (seg = 1; seg <= segLast; seg++)
  1357. {
  1358. apropSn = (APROPSNPTR) FETCHSYM(mpgsnrprop[mpseggsn[seg]], FALSE);
  1359. if (apropSn->as_ggr == ggr)
  1360. {
  1361. segInfo.cbSeg += apropSn->as_cbMx;
  1362. #if OVERLAYS
  1363. segInfo.ovlNbr = apropSn->as_iov;
  1364. #endif
  1365. }
  1366. }
  1367. }
  1368. }
  1369. segInfo.isegName = iName;
  1370. ahte = (AHTEPTR) FETCHSYM(mpggrrhte[ggr], FALSE);
  1371. iName += (WORD) (B2W(ahte->cch[0]) + 1);
  1372. segInfo.iclassName = 0xffff;
  1373. WriteCopy(&segInfo, sizeof(SEGINFO));
  1374. sizeTotal += sizeof(SEGINFO);
  1375. }
  1376. return(sizeTotal);
  1377. }
  1378. /*** OutSegNames - write segment name table
  1379. *
  1380. * Purpose:
  1381. * This subsection was introduced in CV 4.0.
  1382. * The segment name subsection contains all of the logical segment,
  1383. * class and group names. Each name is a zero terminated ASCII string.
  1384. *
  1385. * Input:
  1386. * No explicit value is passed.
  1387. * Global variables:
  1388. * - mpseggsn - table mapping the logical segment index to its global
  1389. * segment index
  1390. * - mpgsnprop - table mapping global segment index to its symbol table
  1391. * descriptor
  1392. * - mpggrrhte - table mapping global group index to group name
  1393. *
  1394. * Output:
  1395. * Function returns the size of segment name table.
  1396. *
  1397. * Exceptions:
  1398. * None.
  1399. *
  1400. * Notes:
  1401. * None.
  1402. *
  1403. *************************************************************************/
  1404. LOCAL DWORD NEAR OutSegNames(void)
  1405. {
  1406. SEGTYPE seg; // Logical segment index
  1407. APROPSNPTR apropSn; // Real pointer to logical segment descriptor
  1408. DWORD sizeTotal; // Size of the segment name table
  1409. SBTYPE name; // A name
  1410. RBTYPE vpClass; // Virtual pointer to class descriptor
  1411. GRTYPE ggr; // Global group index
  1412. sizeTotal = 0L;
  1413. // Write names of all logical segments
  1414. for (seg = 1; seg <= segLast; ++seg)
  1415. {
  1416. // Look up segment definition
  1417. apropSn = (APROPSNPTR ) FETCHSYM(mpgsnrprop[mpseggsn[seg]], FALSE);
  1418. vpClass = apropSn->as_rCla;
  1419. GetName((AHTEPTR) apropSn, name);
  1420. WriteCopy(&name[1], B2W(name[0]) + 1);
  1421. sizeTotal += (B2W(name[0]) + 1);
  1422. GetName((AHTEPTR ) FETCHSYM(vpClass, FALSE), name);
  1423. WriteCopy(&name[1], B2W(name[0]) + 1);
  1424. sizeTotal += (B2W(name[0]) + 1);
  1425. }
  1426. // Write names of all groups
  1427. for (ggr = 1; ggr < ggrMac; ggr++)
  1428. {
  1429. GetName((AHTEPTR ) FETCHSYM(mpggrrhte[ggr], FALSE), name);
  1430. WriteCopy(&name[1], B2W(name[0]) + 1);
  1431. sizeTotal += (B2W(name[0]) + 1);
  1432. }
  1433. return(sizeTotal);
  1434. }
  1435. /*** OutSst - write subsections
  1436. *
  1437. * Purpose:
  1438. * For every object file with CV information write its sstModule,
  1439. * sstTypes, sstPublics, sstSymbols and sstSrcModule.
  1440. * Build subsection directory.
  1441. *
  1442. * Input:
  1443. * No explicit value is passed.
  1444. * Global variables used:
  1445. * - rprop1stFile - virtual pointer to the first object file descriptor
  1446. *
  1447. * Output:
  1448. * No explicit value is returned.
  1449. * Side effects:
  1450. * - subsections in the executable file
  1451. * - subsection directory in the VM
  1452. *
  1453. * Exceptions:
  1454. * I/O errors - display error message and quit
  1455. *
  1456. * Notes:
  1457. * None.
  1458. *
  1459. *************************************************************************/
  1460. LOCAL void NEAR OutSst(void)
  1461. {
  1462. APROPFILEPTR apropFile; // Real pointer to file entry
  1463. RBTYPE rbFileNext; // Virtual pointer the next file descriptor
  1464. struct dnt dntCur; // Current subsection directory entry
  1465. CVINFO FAR *pCvInfo; // Pointer to the CV info descriptor
  1466. #if CVPACK_SHARED
  1467. #if REVERSE_MODULE_ORDER_FOR_CVPACK
  1468. RBTYPE rbFileCur;
  1469. RBTYPE rbFileLast;
  1470. // reverse module list in place
  1471. // I've been waiting all my life to actually *need* this code... [rm]
  1472. // this will cause us to write the modules tables in REVERSE order
  1473. // (this gives better swapping behaviour in the cvpack phase
  1474. // because the modules cvpack will visit first will be the ones that
  1475. // are still resident...
  1476. rbFileCur = rprop1stFile;
  1477. rbFileLast = NULL;
  1478. while (rbFileCur != NULL)
  1479. {
  1480. apropFile = (APROPFILEPTR ) FETCHSYM(rbFileCur, TRUE);
  1481. rbFileNext = apropFile->af_FNxt;// Get pointer to next file
  1482. apropFile->af_FNxt = rbFileLast;
  1483. rbFileLast = rbFileCur;
  1484. rbFileCur = rbFileNext;
  1485. }
  1486. rprop1stFile = rbFileLast;
  1487. #endif
  1488. #endif
  1489. rbFileNext = rprop1stFile;
  1490. dntCur.iMod = 1;
  1491. while (rbFileNext != NULL) // For every module
  1492. {
  1493. apropFile = (APROPFILEPTR ) FETCHSYM(rbFileNext, TRUE);
  1494. rbFileNext = apropFile->af_FNxt;// Get pointer to next file
  1495. // Skip this module if no debug info for it
  1496. if (!apropFile->af_cvInfo && !apropFile->af_publics && !apropFile->af_Src)
  1497. continue;
  1498. pCvInfo = apropFile->af_cvInfo;
  1499. // sstModules
  1500. dntCur.sst = SSTMODULES4;
  1501. dntCur.lfo = FTELL_BSRUNFILE() - lfaBase;
  1502. dntCur.cb = OutModule(apropFile);
  1503. PutDnt(&dntCur);
  1504. // sstTypes
  1505. if (pCvInfo && pCvInfo->cv_cbTyp > 0L)
  1506. {
  1507. Pad2Dword();
  1508. if (apropFile->af_flags & FPRETYPES)
  1509. dntCur.sst = SSTPRETYPES;
  1510. else
  1511. dntCur.sst = SSTTYPES4;
  1512. dntCur.lfo = FTELL_BSRUNFILE() - lfaBase;
  1513. dntCur.cb = pCvInfo->cv_cbTyp;
  1514. WriteNocopy(pCvInfo->cv_typ, pCvInfo->cv_cbTyp);
  1515. IF_NOT_CVPACK_SHARED(FFREE(pCvInfo->cv_typ));
  1516. PutDnt(&dntCur);
  1517. }
  1518. // sstPublics
  1519. if (apropFile->af_publics && !fSkipPublics)
  1520. {
  1521. Pad2Dword();
  1522. dntCur.sst = SSTPUBLICSYM;
  1523. dntCur.lfo = FTELL_BSRUNFILE() - lfaBase;
  1524. dntCur.cb = OutPublics(apropFile->af_publics);
  1525. PutDnt(&dntCur);
  1526. }
  1527. // sstSymbols
  1528. if (pCvInfo && pCvInfo->cv_cbSym > 0L)
  1529. {
  1530. Pad2Dword();
  1531. dntCur.sst = SSTSYMBOLS4;
  1532. dntCur.lfo = FTELL_BSRUNFILE() - lfaBase;
  1533. dntCur.cb = pCvInfo->cv_cbSym;
  1534. WriteNocopy(pCvInfo->cv_sym, pCvInfo->cv_cbSym);
  1535. IF_NOT_CVPACK_SHARED(FFREE(pCvInfo->cv_sym));
  1536. PutDnt(&dntCur);
  1537. }
  1538. // sstSrcModule
  1539. if (apropFile->af_Src)
  1540. {
  1541. Pad2Dword();
  1542. dntCur.sst = SSTSRCMODULE;
  1543. dntCur.lfo = FTELL_BSRUNFILE() - lfaBase;
  1544. dntCur.cb = OutSrcModule(apropFile->af_Src);
  1545. PutDnt(&dntCur);
  1546. }
  1547. dntCur.iMod++;
  1548. }
  1549. // sstLibraries
  1550. Pad2Dword();
  1551. dntCur.sst = SSTLIBRARIES4;
  1552. dntCur.iMod = (short) 0xffff;
  1553. dntCur.lfo = FTELL_BSRUNFILE() - lfaBase;
  1554. dntCur.cb = OutLibSec();
  1555. PutDnt(&dntCur);
  1556. // sstSegMap
  1557. Pad2Dword();
  1558. dntCur.sst = SSTSEGMAP;
  1559. dntCur.lfo = FTELL_BSRUNFILE() - lfaBase;
  1560. dntCur.cb = OutSegMap();
  1561. PutDnt(&dntCur);
  1562. // sstSegNames
  1563. Pad2Dword();
  1564. dntCur.sst = SSTSEGNAME;
  1565. dntCur.lfo = FTELL_BSRUNFILE() - lfaBase;
  1566. dntCur.cb = OutSegNames();
  1567. PutDnt(&dntCur);
  1568. FFREE(fileBase);
  1569. FFREE(raSeg);
  1570. FFREE(segNo);
  1571. }
  1572. #pragma check_stack(off)
  1573. /*
  1574. * OutLibSec : Output sstLibraries subsection to bsRunfile
  1575. *
  1576. * Path prefix is stripped from library name.
  1577. * If no libraries, don't output anything.
  1578. *
  1579. * Parameters: none
  1580. * Returns: Number of bytes in Libraries subsection
  1581. */
  1582. LOCAL int NEAR OutLibSec ()
  1583. {
  1584. WORD ifh;
  1585. AHTEPTR ahte;
  1586. int cb = 0;
  1587. BYTE *pb;
  1588. if (ifhLibMac == 0)
  1589. return(0);
  1590. // Libraries subsection consists of a list of library
  1591. // names which will be indexed by library numbers in the
  1592. // sstModules. Those indexes are 1-based.
  1593. // cb == 0, use it to write a single byte
  1594. WriteCopy(&cb, 1); // 0th entry is null for now
  1595. cb++;
  1596. for (ifh = 0; ifh < ifhLibMac; ifh++)
  1597. {
  1598. if (mpifhrhte[ifh] != RHTENIL)
  1599. {
  1600. ahte = (AHTEPTR) FETCHSYM(mpifhrhte[ifh],FALSE);
  1601. #if OSXENIX
  1602. pb = GetFarSb(ahte->cch);
  1603. #else
  1604. pb = StripDrivePath(GetFarSb(ahte->cch));
  1605. #endif
  1606. }
  1607. else
  1608. pb = "";
  1609. WriteCopy(pb, pb[0] + 1);
  1610. cb += 1 + B2W(pb[0]);
  1611. }
  1612. return(cb);
  1613. }
  1614. /*** OutDntDir - write subsection directory
  1615. *
  1616. * Purpose:
  1617. * Write subsection directory
  1618. *
  1619. * Input:
  1620. * No explicit value is passed.
  1621. * Global variables:
  1622. * - dntPageMac - number of VM pages with DNTs
  1623. *
  1624. * Output:
  1625. * Function returns the size of the directory in bytes.
  1626. *
  1627. * Exceptions:
  1628. * I/O problems - display error message and quit
  1629. *
  1630. * Notes:
  1631. * None.
  1632. *
  1633. *************************************************************************/
  1634. LOCAL DWORD NEAR OutDntDir(void)
  1635. {
  1636. DNTHDR hdr; // Directory header
  1637. hdr.cbDirHeader = sizeof(DNTHDR);
  1638. hdr.cbDirEntry = sizeof(DNT);
  1639. hdr.cDir = dntMac;
  1640. hdr.lfoDirNext = 0L;
  1641. hdr.flags = 0L;
  1642. // Write header
  1643. WriteCopy(&hdr, sizeof(DNTHDR));
  1644. // Write directory
  1645. WriteCopy((char FAR *) rgDnt, dntMac * sizeof(DNT));
  1646. FFREE(rgDnt);
  1647. return(sizeof(DNTHDR) + dntMac * sizeof(DNT));
  1648. }
  1649. /*** OutDebSection - allow debugging
  1650. *
  1651. * Purpose:
  1652. * Append to the executable file the CV information. ONLY CV 4.00
  1653. * format supported.
  1654. *
  1655. * Input:
  1656. * No explicit value is passed.
  1657. * Global variables:
  1658. * - too many to list
  1659. *
  1660. * Output:
  1661. * No explicit value is returned.
  1662. * Side effects:
  1663. * - what do you think ??
  1664. *
  1665. * Exceptions:
  1666. * I/O problems - display error message and quit
  1667. *
  1668. * Notes:
  1669. * None.
  1670. *
  1671. *************************************************************************/
  1672. void OutDebSections(void)
  1673. {
  1674. long lfaDir; // File address of Directory
  1675. DWORD dirSize; // Directory size
  1676. long tmp;
  1677. #if CVPACK_SHARED
  1678. long * plfoDir; // pointer to directory data
  1679. fseek(bsRunfile, 0L, 2); // Go to end of file
  1680. lfaBase = ftell(bsRunfile); // Remember base address
  1681. lposCur = lfaBase; // set current position...
  1682. WriteCopy(szSignature, sizeof(szSignature)); // Signature dword
  1683. WriteCopy(&tmp, sizeof(tmp)); // Skip lfoDir field
  1684. plfoDir = (long *)rgbl[iblLim-1].pb;// remember address of lfoDir
  1685. OutSst(); // Output subsections
  1686. lfaDir = lposCur; // Remember where directory starts
  1687. *plfoDir = lfaDir - lfaBase; // fix up lfoDir field
  1688. dirSize = OutDntDir(); // Output subsection directory
  1689. WriteCopy(szSignature, sizeof(szSignature));
  1690. // Signature dword
  1691. tmp = (lfaDir + dirSize + 2*sizeof(DWORD)) - lfaBase;
  1692. WriteCopy(&tmp, sizeof(long)); // Distance from EOF to base
  1693. // write out the bits that cvpack won't overwrite...
  1694. if (fCVpack)
  1695. WriteFlushSignature();
  1696. else
  1697. WriteFlushAll();
  1698. cbRealBytes = ftell(bsRunfile); // # of real bytes actually written
  1699. lposMac = lposCur;
  1700. iblCur = iblNil;
  1701. #else
  1702. if (fseek(bsRunfile, 0L, 2)) // Go to end of file
  1703. Fatal(ER_ioerr, strerror(errno));
  1704. lfaBase = FTELL_BSRUNFILE(); // Remember base address
  1705. WriteExe(szSignature, sizeof(szSignature));
  1706. // Signature dword
  1707. if (fseek(bsRunfile,4L,1)) // Skip lfoDir field
  1708. Fatal(ER_ioerr, strerror(errno));
  1709. OutSst(); // Output subsections
  1710. lfaDir = FTELL_BSRUNFILE(); // Remember where directory starts
  1711. if (fseek(bsRunfile, lfaBase + 4, 0)) // Go to lfoDir field
  1712. Fatal(ER_ioerr, strerror(errno));
  1713. tmp = lfaDir - lfaBase;
  1714. WriteExe(&tmp, sizeof(long)); // Fix it up
  1715. if (fseek(bsRunfile, lfaDir, 0)) // Go back to directory
  1716. Fatal(ER_ioerr, strerror(errno));
  1717. dirSize = OutDntDir(); // Output subsection directory
  1718. WriteExe(szSignature, sizeof(szSignature));
  1719. // Signature dword
  1720. tmp = (lfaDir + dirSize + 2*sizeof(DWORD)) - lfaBase;
  1721. WriteExe(&tmp, sizeof(long)); // Distance from EOF to base
  1722. if (fseek(bsRunfile, 0L, 2)) // Seek to EOF just in case
  1723. Fatal(ER_ioerr, strerror(errno));
  1724. #endif
  1725. }
  1726. #if CVPACK_SHARED
  1727. //
  1728. // write data to cvpack memory cache area
  1729. //
  1730. void
  1731. WriteSave(FTYPE fCopy, void *pb, UINT cb)
  1732. {
  1733. if (!rgbl)
  1734. {
  1735. rgbl = (BL *)GetMem(sizeof(BL) * C_BL_INIT);
  1736. iblMac = C_BL_INIT;
  1737. iblLim = 0;
  1738. }
  1739. // if this memory isn't going to stay around, then copy it
  1740. if (fCopy)
  1741. {
  1742. void *pbT = (void *)GetMem(cb);
  1743. memcpy(pbT, pb, cb);
  1744. pb = pbT;
  1745. }
  1746. if (iblLim == iblMac)
  1747. {
  1748. BL *rgblT;
  1749. rgblT = (BL *)GetMem(sizeof(BL) * iblMac * 2);
  1750. memcpy(rgblT, rgbl, sizeof(BL) * iblMac);
  1751. iblMac *= 2;
  1752. FFREE(rgbl);
  1753. rgbl = rgblT;
  1754. }
  1755. rgbl[iblLim].lpos = lposCur;
  1756. rgbl[iblLim].pb = pb;
  1757. iblLim++;
  1758. lposCur += cb;
  1759. }
  1760. // we want to write a few of the blocks because cvpack won't rewrite the
  1761. // first bit... [rm]
  1762. void WriteFlushSignature()
  1763. {
  1764. int ibl, cb;
  1765. // we know that the signature and offset are written in two pieces...
  1766. // if this changes we need to change the magic '2' below [rm]
  1767. for (ibl = 0; ibl < 2; ibl++)
  1768. {
  1769. cb = rgbl[ibl+1].lpos - rgbl[ibl].lpos;
  1770. WriteExe(rgbl[ibl].pb, cb);
  1771. }
  1772. }
  1773. void WriteFlushAll()
  1774. {
  1775. int ibl, cb;
  1776. for (ibl = 0; ibl < iblLim - 1; ibl++)
  1777. {
  1778. cb = rgbl[ibl+1].lpos - rgbl[ibl].lpos;
  1779. WriteExe(rgbl[ibl].pb, cb);
  1780. }
  1781. cb = lposCur - rgbl[ibl].lpos;
  1782. WriteExe(rgbl[ibl].pb, cb);
  1783. }
  1784. // the following are the various callback functions needed to support
  1785. // the cvpack library when we are attempting to not write out the
  1786. // unpacked types and symbols
  1787. #include <io.h>
  1788. extern int printf(char *,...);
  1789. int __cdecl
  1790. link_chsize (int fh, long size)
  1791. {
  1792. LINK_TRACE(printf("chsize(%06d, %08ld)\n", fh, size));
  1793. // we must keep track of the new size so that we will correctly
  1794. // process lseeks that are relative to the end of the file
  1795. lposMac = size;
  1796. return(_chsize(fh,size));
  1797. }
  1798. int __cdecl
  1799. link_close (int x)
  1800. {
  1801. LINK_TRACE(printf("close (%06d)\n", x));
  1802. return(_close(x));
  1803. }
  1804. void __cdecl
  1805. link_exit (int x)
  1806. {
  1807. LINK_TRACE(printf("exit (%06d)\n", x));
  1808. #if USE_REAL
  1809. RealMemExit();
  1810. #endif
  1811. exit(x);
  1812. }
  1813. long __cdecl
  1814. link_lseek (int fh, long lpos, int mode)
  1815. {
  1816. int ibl;
  1817. LINK_TRACE(printf("lseek (%d, %08ld, %2d)\n", fh, lpos, mode));
  1818. // if we have no cache blocks, just forward the request...
  1819. // this will happen on a /CvpackOnly invocation
  1820. if (rgbl == NULL)
  1821. return _lseek(fh, lpos, mode);
  1822. // adjust lpos so that we are always doing an absolute seek
  1823. if (mode == 1)
  1824. lpos = lposCur + lpos;
  1825. else if (mode == 2)
  1826. lpos = lposMac + lpos;
  1827. // check for a bogus seek
  1828. if (lpos > lposMac || lpos < 0)
  1829. {
  1830. // this used to be an internal error... but cvpack sometimes does
  1831. // try to seek beyond the end of the file when it is trying to
  1832. // distinguish a PE exe from an unsegmented DOS exe
  1833. // instead of panicing, we just return failure
  1834. return(-1);
  1835. }
  1836. // if we are in the midst of reading a block, then free that block
  1837. // cvpack never reads the same data twice
  1838. if (iblCur != iblNil)
  1839. {
  1840. // first check if we're in the header -- we might come back to that...
  1841. if (rgbl[iblCur].lpos > cbRealBytes + CB_HEADER_SAVE)
  1842. {
  1843. long lposCurMin, lposCurMac;
  1844. // check for a seek that is within the current bucket
  1845. // in case we're skipping within the current block
  1846. lposCurMin = rgbl[iblCur].lpos;
  1847. if (iblCur < iblLim)
  1848. lposCurMac = rgbl[iblCur+1].lpos;
  1849. else
  1850. lposCurMac = lposMac;
  1851. if (lpos < lposCurMin || lpos >= lposCurMac)
  1852. {
  1853. FFREE(rgbl[iblCur].pb);
  1854. rgbl[iblCur].pb = NULL;
  1855. }
  1856. }
  1857. }
  1858. // if this seek is not in the debug area of the .exe use the real lseek
  1859. if (lpos < cbRealBytes)
  1860. {
  1861. iblCur = iblNil;
  1862. lposCur = lpos;
  1863. return(_lseek(fh,lpos,0));
  1864. }
  1865. // see if we are searching forward (the normal case)
  1866. // if we are, search from the current block, otherwise search from
  1867. // the start (linear search but OK because cvpack doesn't
  1868. // jump around much, it just uses lseek to skip a few bytes here and
  1869. // there)
  1870. if (lpos > lposCur && iblCur != iblNil)
  1871. ibl = iblCur;
  1872. else
  1873. ibl = 0;
  1874. // set the current position
  1875. lposCur = lpos;
  1876. // loop through the buffered writes looking for the requested position
  1877. for (; ibl < iblLim - 1; ibl++)
  1878. {
  1879. if (lpos >= rgbl[ibl].lpos && lpos < rgbl[ibl+1].lpos)
  1880. break; // found bucket
  1881. }
  1882. // set the bucket number, offset within the bucket, and number of bytes
  1883. // left in the bucket
  1884. iblCur = ibl;
  1885. ichCur = lpos - rgbl[ibl].lpos;
  1886. cbCur = CbIbl(ibl) - ichCur;
  1887. // check to make sure we haven't seeked back to a buffer that we already
  1888. // freed...
  1889. ASSERT(rgbl[iblCur].pb != NULL);
  1890. // make sure we get the boundary case... if cvpack is requesting to go to
  1891. // the end of the data that we have written then we MUST seek because
  1892. // cvpack might be about to write out the packed stuff...
  1893. if (lposCur == cbRealBytes)
  1894. _lseek(fh, lpos, 0);
  1895. // we set up the current position earlier... return it now
  1896. return(lposCur);
  1897. }
  1898. int __cdecl
  1899. link_open (const char * x, int y)
  1900. {
  1901. LINK_TRACE(printf("open (%s, %06d)\n", x, y));
  1902. // setup the static variables to a safe state
  1903. // the current position is the start of file and there is no buffer
  1904. // active (iblCur = iblNil)
  1905. iblCur = iblNil;
  1906. lposCur = 0;
  1907. return(_open(x,y));
  1908. }
  1909. int __cdecl
  1910. link_read (int fh, char *pch, unsigned int cb)
  1911. {
  1912. int cbRem;
  1913. LINK_TRACE(printf("read (%d, %06u)\n", fh, cb));
  1914. if (rgbl == NULL)
  1915. return _read(fh, pch, cb);
  1916. // special case zero byte read, not really necessary but
  1917. // avoids any potential problems with trying to setup empty
  1918. // buffers etc. -- it should just fall out anyways but
  1919. // just to be safe [rm]
  1920. if (cb == 0)
  1921. return 0;
  1922. // if there is no buffer active, then just forward the read
  1923. // note that if we are invoked with /CvpackOnly this test will
  1924. // always succeed
  1925. if (iblCur == iblNil)
  1926. {
  1927. if (lposCur + ((long)(unsigned long)cb) < cbRealBytes)
  1928. {
  1929. lposCur += cb;
  1930. return(_read(fh,pch,cb));
  1931. }
  1932. else
  1933. {
  1934. int cbReal = cbRealBytes - lposCur;
  1935. if (_read(fh, pch, cbReal) != cbReal)
  1936. return -1;
  1937. if (link_lseek(fh, cbRealBytes, 0) != cbRealBytes)
  1938. return -1;
  1939. // set the number of bytes remaining to be read in
  1940. cbRem = cb - cbReal;
  1941. pch += cb - cbReal;
  1942. }
  1943. }
  1944. else
  1945. {
  1946. // set the number of bytes remaining to be read in
  1947. cbRem = cb;
  1948. }
  1949. while (cbRem)
  1950. {
  1951. // check if the number of bytes we need to read is less than
  1952. // the number left in the current buffer
  1953. if (cbRem <= cbCur)
  1954. {
  1955. // we can read all the remaining bytes from the current buffer
  1956. // so do it. Copy bytes and adjust the number of bytes left
  1957. // in this buffer, the index into the buffer, and the current
  1958. // position in the file
  1959. memcpy(pch, rgbl[iblCur].pb+ichCur, cbRem);
  1960. cbCur -= cbRem;
  1961. ichCur += cbRem;
  1962. lposCur += cbRem;
  1963. #ifdef DUMP_CVPACK_BYTES
  1964. {
  1965. int i;
  1966. for (i=0;i<cb;i++)
  1967. {
  1968. if ((i&15) == 0)
  1969. printf("%04x: ", i);
  1970. printf("%02x ", pch[i]);
  1971. if ((i&15)==15)
  1972. printf("\n");
  1973. }
  1974. }
  1975. if ((i&15))
  1976. printf("\n");
  1977. #endif
  1978. return cb;
  1979. }
  1980. else
  1981. {
  1982. // in this case, the read is bigger than the current buffer
  1983. // we'll be reading the whole buffer and then moving to the
  1984. // next buffer
  1985. // first read in the rest of this buffer
  1986. memcpy(pch, rgbl[iblCur].pb+ichCur, cbCur);
  1987. // adjust the number of bytes remaining and the current file
  1988. // position...
  1989. pch += cbCur;
  1990. cbRem -= cbCur;
  1991. lposCur += cbCur;
  1992. // we won't be coming back to this buffer, so return it to the
  1993. // system and mark it as freed
  1994. // first check if we're in the header -- we might come back to that
  1995. if (rgbl[iblCur].lpos > cbRealBytes + CB_HEADER_SAVE)
  1996. {
  1997. FFREE(rgbl[iblCur].pb);
  1998. rgbl[iblCur].pb = NULL;
  1999. }
  2000. // move forward to the next bucket, if there are no more buckets
  2001. // then this is an ERROR -- we'll be returning the number of
  2002. // bytes that we managed to read
  2003. iblCur++;
  2004. if (iblCur == iblLim)
  2005. {
  2006. iblCur = iblNil;
  2007. break;
  2008. }
  2009. // check to make sure that we are not reading data that
  2010. // we've already freed (yipe!)
  2011. ASSERT(rgbl[iblCur].pb != NULL);
  2012. // check to make sure that the current position agrees with
  2013. // the position that this buffer is supposed to occur at
  2014. ASSERT(lposCur == rgbl[iblCur].lpos);
  2015. // ok, everything is safe now, set the index into the current
  2016. // buffer and the number of bytes left in the buffer, then
  2017. // run the loop again until we've read in all the bytes we need
  2018. ichCur = 0;
  2019. cbCur = CbIbl(iblCur);
  2020. }
  2021. }
  2022. // return the number of bytes we actually read
  2023. return cb - cbRem;
  2024. }
  2025. long __cdecl
  2026. link_tell (int x)
  2027. {
  2028. LINK_TRACE(printf("tell (%06d)\n", x));
  2029. if (iblCur != iblNil)
  2030. return(lposCur);
  2031. return(_tell(x));
  2032. }
  2033. int __cdecl
  2034. link_write (int x, const void * y, unsigned int z)
  2035. {
  2036. LINK_TRACE(printf("write (%06d,%08lx,%06u)\n", x, y, z));
  2037. return(_write(x,y,z));
  2038. }
  2039. #ifdef CVPACK_DEBUG_HELPER
  2040. void dumpstate()
  2041. {
  2042. printf("lposCur= %d\n", lposCur);
  2043. printf("iblCur = %d\n", iblCur);
  2044. printf("ichCur = %d\n", ichCur);
  2045. printf("cbReal = %d\n", cbRealBytes);
  2046. printf("lposMac= %d\n", lposMac);
  2047. }
  2048. #endif
  2049. #else
  2050. #ifdef CVPACK_MONDO
  2051. #include <io.h>
  2052. int __cdecl
  2053. link_chsize (int x, long y)
  2054. {
  2055. return(_chsize(x,y));
  2056. }
  2057. int __cdecl
  2058. link_close (int x)
  2059. {
  2060. return(_close(x));
  2061. }
  2062. void __cdecl
  2063. link_exit (int x)
  2064. {
  2065. #if USE_REAL
  2066. RealMemExit();
  2067. #endif
  2068. exit(x);
  2069. }
  2070. long __cdecl
  2071. link_lseek (int x, long y, int z)
  2072. {
  2073. return(_lseek(x,y,z));
  2074. }
  2075. int __cdecl
  2076. link_open (const char *x, int y)
  2077. {
  2078. return(_open(x,y));
  2079. }
  2080. int __cdecl
  2081. link_read (int x, void *y, unsigned int z)
  2082. {
  2083. return(_read(x,y,z));
  2084. }
  2085. long __cdecl
  2086. link_tell (int x)
  2087. {
  2088. return(_tell(x));
  2089. }
  2090. int __cdecl
  2091. link_write (int x, const void * y, unsigned int z)
  2092. {
  2093. return(_write(x,y,z));
  2094. }
  2095. #endif
  2096. #endif