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.

2507 lines
71 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; // 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. rgDnt = (DNT *) REALLOC(rgDnt, newSize * sizeof(DNT));
  990. #else
  991. rgDnt = (DNT FAR *) _frealloc(rgDnt, newSize * sizeof(DNT));
  992. #endif
  993. }
  994. else
  995. {
  996. newSize = DNT_START;
  997. rgDnt = (DNT*) GetMem ( newSize * sizeof(DNT) );
  998. }
  999. if (rgDnt == NULL)
  1000. Fatal(ER_memovf);
  1001. dntMax = newSize;
  1002. }
  1003. rgDnt[dntMac] = *pDnt;
  1004. dntMac++;
  1005. #if CVDEBUG
  1006. DumpDNT(pDnt);
  1007. #endif
  1008. }
  1009. #pragma check_stack(on)
  1010. /*** OutModule - write out module subsection
  1011. *
  1012. * Purpose:
  1013. * Write into the executable file the module subsections for all
  1014. * object files compiled with CV information. Only CV 4.0 format.
  1015. *
  1016. * Input:
  1017. * - apropFile - pointer to the current object file descriptor
  1018. *
  1019. * Output:
  1020. * No explicit value is retuned.
  1021. * Side effects:
  1022. * - module subsections in executable file
  1023. *
  1024. * Exceptions:
  1025. * None.
  1026. *
  1027. * Notes:
  1028. * None.
  1029. *
  1030. *************************************************************************/
  1031. LOCAL DWORD NEAR OutModule(APROPFILEPTR apropFile)
  1032. {
  1033. SBTYPE sbName;
  1034. SSTMOD4 module;
  1035. CVCODE FAR *pSegCur;
  1036. CODEINFO codeOnt;
  1037. WORD cOnt;
  1038. module.ovlNo = (WORD) apropFile->af_iov;
  1039. module.iLib = (WORD) (apropFile->af_ifh + 1);
  1040. module.cSeg = apropFile->af_cCodeSeg;
  1041. module.style[0] = 'C';
  1042. module.style[1] = 'V';
  1043. // Get file name or library module name
  1044. if (apropFile->af_ifh != FHNIL && apropFile->af_rMod != RHTENIL)
  1045. GetName((AHTEPTR) apropFile->af_rMod, sbName);
  1046. else
  1047. GetName((AHTEPTR) apropFile, sbName);
  1048. #if CVDEBUG
  1049. sbName[sbName[0]+1] = '\0';
  1050. fprintf(stdout, "\r\nCV info for %s\r\n", &sbName[1]);
  1051. #endif
  1052. // Write sstModule header followed by the list of code contributions
  1053. WriteCopy(&module, sizeof(SSTMOD4));
  1054. pSegCur = apropFile->af_Code;
  1055. codeOnt.pad = 0;
  1056. for (cOnt = 0; cOnt < module.cSeg && pSegCur; cOnt++, pSegCur = pSegCur->next)
  1057. {
  1058. codeOnt.seg = pSegCur->seg;
  1059. codeOnt.off = pSegCur->ra;
  1060. codeOnt.cbOnt = pSegCur->cb;
  1061. WriteCopy(&codeOnt, sizeof(CODEINFO));
  1062. #if CVDEBUG
  1063. fprintf(stdout, " Logical segment %d; offset 0x%lx; size 0x%lx\r\n",
  1064. codeOnt.seg, codeOnt.off, codeOnt.cbOnt);
  1065. #endif
  1066. }
  1067. // Write object file name
  1068. WriteCopy(sbName, B2W(sbName[0]) + 1);
  1069. return(sizeof(SSTMOD4) + B2W(sbName[0]) + 1 + module.cSeg * sizeof(CODEINFO));
  1070. }
  1071. /*** OutPublics - write sstPublics subsection
  1072. *
  1073. * Purpose:
  1074. * Write sstPublics subsection of the CV information. The subsection
  1075. * conforms to the new CV 4.0 format.
  1076. *
  1077. * Input:
  1078. * - firstPub - virtual pointer to the list of public symbols defined
  1079. * in a given object module
  1080. *
  1081. * Output:
  1082. * Total size of the subsection in bytes.
  1083. *
  1084. * Exceptions:
  1085. * None.
  1086. *
  1087. * Notes:
  1088. * None.
  1089. *
  1090. *************************************************************************/
  1091. LOCAL DWORD NEAR OutPublics(RBTYPE firstPub)
  1092. {
  1093. PUB16 pub16; // CV public descriptor - 16-bit
  1094. PUB32 pub32; // CV public descriptor - 32-bit
  1095. APROPNAMEPTR apropPub; // Real pointer to public descriptor
  1096. APROPSNPTR apropSn; // Real pointer to segment descriptor
  1097. RBTYPE curPub; // Virtual pointer to the current public symbol
  1098. WORD f32Bit; // TRUE if public defined in 32-bit segment
  1099. DWORD sizeTotal; // Total size of subsection
  1100. SNTYPE seg; // Symbol base
  1101. RATYPE ra; // Symbol offset
  1102. WORD CVtype; // CV info type index
  1103. SBTYPE sbName; // Public symbol
  1104. char *pPub;
  1105. WORD len;
  1106. // Initialize
  1107. curPub = firstPub;
  1108. pub16.idx = S_PUB16;
  1109. pub32.idx = S_PUB32;
  1110. sizeTotal = 1L;
  1111. WriteCopy(&sizeTotal, sizeof(DWORD));// sstPublicSym signature
  1112. sizeTotal = sizeof(DWORD);
  1113. while (curPub != 0L)
  1114. {
  1115. f32Bit = FALSE;
  1116. apropPub = (APROPNAMEPTR) FETCHSYM(curPub, FALSE);
  1117. curPub = apropPub->an_sameMod;
  1118. if (apropPub->an_attr == ATTRALIAS)
  1119. apropPub = (APROPNAMEPTR) FETCHSYM(((APROPALIASPTR) apropPub)->al_sym, FALSE);
  1120. if (apropPub->an_attr != ATTRPNM)
  1121. continue;
  1122. ra = apropPub->an_ra;
  1123. if (apropPub->an_gsn) // If not absolute symbol
  1124. {
  1125. seg = mpgsnseg[apropPub->an_gsn];
  1126. // If this is a .com program and the segment is the one
  1127. // moved by 0x100, adjust accordingly the SegMap entry
  1128. if(seg == segAdjCom)
  1129. {
  1130. #if FALSE
  1131. GetName((AHTEPTR) apropPub, sbName);
  1132. sbName[sbName[0]+1] = '\0';
  1133. fprintf(stdout, "\r\nCorrecting public %s : %lx -> %lx", sbName+1, ra, ra+0x100);
  1134. fflush(stdout);
  1135. #endif
  1136. ra += 0x100;
  1137. }
  1138. CVtype = 0; // Should be this apropPub->an_CVtype
  1139. // but cvpack can't handle it.
  1140. #if O68K
  1141. if (iMacType == MAC_NONE)
  1142. #endif
  1143. ra -= mpsegraFirst[seg];
  1144. #if CVDEBUG
  1145. GetName((AHTEPTR) apropPub, sbName);
  1146. sbName[sbName[0]+1] = '\0';
  1147. fprintf(stdout, "'%s' --> logical address %2x:%lx; physical address %2x:%lx\r\n",
  1148. &sbName[1], seg, ra, mpsegsa[seg], apropPub->an_ra);
  1149. #endif
  1150. apropSn = (APROPSNPTR) FETCHSYM(mpgsnrprop[apropPub->an_gsn], FALSE);
  1151. #if EXE386
  1152. f32Bit = TRUE;
  1153. #else
  1154. f32Bit = (WORD) Is32BIT(apropSn->as_flags);
  1155. #endif
  1156. }
  1157. else
  1158. {
  1159. seg = 0; // Else no base
  1160. CVtype = T_ABS; // CV absolute symbol type
  1161. f32Bit = (WORD) (ra > LXIVK);
  1162. }
  1163. GetName((AHTEPTR) apropPub, sbName);
  1164. if (f32Bit)
  1165. {
  1166. pub32.len = (WORD) (sizeof(PUB32) + B2W(sbName[0]) + 1 - sizeof(WORD));
  1167. pub32.off = ra;
  1168. pub32.seg = seg;
  1169. pub32.type = CVtype;
  1170. pPub = (char *) &pub32;
  1171. len = sizeof(PUB32);
  1172. }
  1173. else
  1174. {
  1175. pub16.len = (WORD) (sizeof(PUB16) + B2W(sbName[0]) + 1 - sizeof(WORD));
  1176. pub16.off = (WORD) ra;
  1177. pub16.seg = seg;
  1178. pub16.type = CVtype;
  1179. pPub = (char *) &pub16;
  1180. len = sizeof(PUB16);
  1181. }
  1182. WriteCopy(pPub, len);
  1183. // Output length-prefixed name
  1184. WriteCopy(sbName, sbName[0] + 1);
  1185. sizeTotal += (len + B2W(sbName[0]) + 1);
  1186. }
  1187. return(sizeTotal);
  1188. }
  1189. /*** OutSegMap - write segment map
  1190. *
  1191. * Purpose:
  1192. * This subsection was introduced in CV 4.0. This subsection
  1193. * maps the logical segments to physical segments. It also gives
  1194. * the names and sizes of each logical segment.
  1195. *
  1196. * Input:
  1197. * No explicit value is passed.
  1198. * Global variables:
  1199. * - mpsegsa - table mapping logical segment number to its physical
  1200. * segment number or address
  1201. * - mpsaflags - table mapping physicla segment index to its flags
  1202. * - mpseggsn - table mapping the logical segment index to its global
  1203. * segment index
  1204. * - mpgsnprop - table mapping global segment index to its symbol table
  1205. * descriptor
  1206. * - mpggrgsn - table mapping global group index to global segment index
  1207. * - mpggrrhte - table mapping global group index to group name
  1208. *
  1209. * Output:
  1210. * Function returns the size of segment map.
  1211. *
  1212. * Exceptions:
  1213. * None.
  1214. *
  1215. * Notes:
  1216. * None.
  1217. *
  1218. *************************************************************************/
  1219. LOCAL DWORD NEAR OutSegMap(void)
  1220. {
  1221. SEGTYPE seg; // Logical segment index
  1222. APROPSNPTR apropSn; // Real pointer to logical segment descriptor
  1223. SATYPE sa; // Physical segment index
  1224. WORD iName; // Index to free space in segment name table
  1225. DWORD sizeTotal; // Total size of the subsection
  1226. SEGINFO segInfo; // CV segment descriptor
  1227. SBTYPE segName; // Segment name
  1228. AHTEPTR ahte; // Real pointer to symbol table hash table
  1229. RBTYPE vpClass; // Virtual pointer to class descriptor
  1230. GRTYPE ggr; // Global group index
  1231. SATYPE saDGroup; // DGroup's sa
  1232. WORD counts[2];
  1233. iName = 0;
  1234. counts[0] = (WORD) (segLast + ggrMac - 1);
  1235. counts[1] = (WORD) segLast;
  1236. WriteCopy(counts, sizeof(counts));
  1237. sizeTotal = sizeof(counts);
  1238. saDGroup = mpsegsa[mpgsnseg[mpggrgsn[ggrDGroup]]];
  1239. // Write all logical segments
  1240. for (seg = 1; seg <= segLast; ++seg)// For all logical segments
  1241. {
  1242. memset(&segInfo, 0, sizeof(SEGINFO));
  1243. if (fNewExe)
  1244. segInfo.flags.fSel = TRUE;
  1245. sa = mpsegsa[seg];
  1246. if (fNewExe)
  1247. {
  1248. #if EXE386
  1249. segInfo.flags.f32Bit = TRUE;
  1250. #else
  1251. segInfo.flags.f32Bit = (WORD) (Is32BIT(mpsaflags[sa]));
  1252. #endif
  1253. if (IsDataFlg(mpsaflags[sa]))
  1254. {
  1255. segInfo.flags.fRead = TRUE;
  1256. #if EXE386
  1257. if (IsWRITEABLE(mpsaflags[sa]))
  1258. #else
  1259. if (!(mpsaflags[sa] & NSEXRD))
  1260. #endif
  1261. segInfo.flags.fWrite = TRUE;
  1262. }
  1263. else
  1264. {
  1265. segInfo.flags.fExecute = TRUE;
  1266. #if EXE386
  1267. if (IsREADABLE(mpsaflags[sa]))
  1268. #else
  1269. if (!(mpsaflags[sa] & NSEXRD))
  1270. #endif
  1271. segInfo.flags.fRead = TRUE;
  1272. }
  1273. }
  1274. else
  1275. {
  1276. if (mpsegFlags[seg] & FCODE)
  1277. {
  1278. segInfo.flags.fRead = TRUE;
  1279. segInfo.flags.fExecute = TRUE;
  1280. }
  1281. else
  1282. {
  1283. segInfo.flags.fRead = TRUE;
  1284. segInfo.flags.fWrite = TRUE;
  1285. }
  1286. }
  1287. // Look up segment definition
  1288. apropSn = (APROPSNPTR) FETCHSYM(mpgsnrprop[mpseggsn[seg]], FALSE);
  1289. vpClass = apropSn->as_rCla;
  1290. #if OVERLAYS
  1291. if (!fNewExe)
  1292. segInfo.ovlNbr = apropSn->as_iov;
  1293. #endif
  1294. // if segment doesn't belong to any group it's ggr is 0
  1295. if (apropSn->as_ggr != GRNIL)
  1296. segInfo.ggr = (WORD) (apropSn->as_ggr + segLast - 1);
  1297. // If segment is a DGROUP member, write DGROUP normalized address
  1298. if(apropSn->as_ggr == ggrDGroup)
  1299. {
  1300. segInfo.sa = saDGroup;
  1301. segInfo.phyOff = mpsegraFirst[seg] + ((sa - saDGroup) << 4);
  1302. }
  1303. else
  1304. {
  1305. segInfo.sa = sa;
  1306. segInfo.phyOff = mpsegraFirst[seg];
  1307. }
  1308. // If this is a .com program and the segment is the one moved by 0x100
  1309. // write all the publics at the original addresses, because the offset
  1310. // adjustment will be made in the SegMap table
  1311. if(seg == segAdjCom)
  1312. {
  1313. segInfo.phyOff -= 0x100;
  1314. }
  1315. segInfo.cbSeg = apropSn->as_cbMx;
  1316. GetName((AHTEPTR) apropSn, segName);
  1317. if (segName[0] != '\0')
  1318. {
  1319. segInfo.isegName = iName;
  1320. iName += (WORD) (B2W(segName[0]) + 1);
  1321. }
  1322. else
  1323. segInfo.isegName = 0xffff;
  1324. ahte = (AHTEPTR) FETCHSYM(vpClass, FALSE);
  1325. if (ahte->cch[0] != 0)
  1326. {
  1327. segInfo.iclassName = iName;
  1328. iName += (WORD) (B2W(ahte->cch[0]) + 1);
  1329. }
  1330. else
  1331. segInfo.iclassName = 0xffff;
  1332. WriteCopy(&segInfo, sizeof(SEGINFO));
  1333. sizeTotal += sizeof(SEGINFO);
  1334. }
  1335. // Write all groups
  1336. for (ggr = 1; ggr < ggrMac; ggr++)
  1337. {
  1338. memset(&segInfo, 0, sizeof(SEGINFO));
  1339. segInfo.flags.fGroup = TRUE;
  1340. if (fNewExe)
  1341. segInfo.flags.fSel = TRUE;
  1342. segInfo.sa = mpsegsa[mpgsnseg[mpggrgsn[ggr]]];
  1343. if (fNewExe)
  1344. segInfo.cbSeg = mpsacb[segInfo.sa];
  1345. else
  1346. {
  1347. segInfo.cbSeg = 0L;
  1348. if (mpggrgsn[ggr] != SNNIL)
  1349. {
  1350. // If group has members
  1351. for (seg = 1; seg <= segLast; seg++)
  1352. {
  1353. apropSn = (APROPSNPTR) FETCHSYM(mpgsnrprop[mpseggsn[seg]], FALSE);
  1354. if (apropSn->as_ggr == ggr)
  1355. {
  1356. segInfo.cbSeg += apropSn->as_cbMx;
  1357. #if OVERLAYS
  1358. segInfo.ovlNbr = apropSn->as_iov;
  1359. #endif
  1360. }
  1361. }
  1362. }
  1363. }
  1364. segInfo.isegName = iName;
  1365. ahte = (AHTEPTR) FETCHSYM(mpggrrhte[ggr], FALSE);
  1366. iName += (WORD) (B2W(ahte->cch[0]) + 1);
  1367. segInfo.iclassName = 0xffff;
  1368. WriteCopy(&segInfo, sizeof(SEGINFO));
  1369. sizeTotal += sizeof(SEGINFO);
  1370. }
  1371. return(sizeTotal);
  1372. }
  1373. /*** OutSegNames - write segment name table
  1374. *
  1375. * Purpose:
  1376. * This subsection was introduced in CV 4.0.
  1377. * The segment name subsection contains all of the logical segment,
  1378. * class and group names. Each name is a zero terminated ASCII string.
  1379. *
  1380. * Input:
  1381. * No explicit value is passed.
  1382. * Global variables:
  1383. * - mpseggsn - table mapping the logical segment index to its global
  1384. * segment index
  1385. * - mpgsnprop - table mapping global segment index to its symbol table
  1386. * descriptor
  1387. * - mpggrrhte - table mapping global group index to group name
  1388. *
  1389. * Output:
  1390. * Function returns the size of segment name table.
  1391. *
  1392. * Exceptions:
  1393. * None.
  1394. *
  1395. * Notes:
  1396. * None.
  1397. *
  1398. *************************************************************************/
  1399. LOCAL DWORD NEAR OutSegNames(void)
  1400. {
  1401. SEGTYPE seg; // Logical segment index
  1402. APROPSNPTR apropSn; // Real pointer to logical segment descriptor
  1403. DWORD sizeTotal; // Size of the segment name table
  1404. SBTYPE name; // A name
  1405. RBTYPE vpClass; // Virtual pointer to class descriptor
  1406. GRTYPE ggr; // Global group index
  1407. sizeTotal = 0L;
  1408. // Write names of all logical segments
  1409. for (seg = 1; seg <= segLast; ++seg)
  1410. {
  1411. // Look up segment definition
  1412. apropSn = (APROPSNPTR ) FETCHSYM(mpgsnrprop[mpseggsn[seg]], FALSE);
  1413. vpClass = apropSn->as_rCla;
  1414. GetName((AHTEPTR) apropSn, name);
  1415. WriteCopy(&name[1], B2W(name[0]) + 1);
  1416. sizeTotal += (B2W(name[0]) + 1);
  1417. GetName((AHTEPTR ) FETCHSYM(vpClass, FALSE), name);
  1418. WriteCopy(&name[1], B2W(name[0]) + 1);
  1419. sizeTotal += (B2W(name[0]) + 1);
  1420. }
  1421. // Write names of all groups
  1422. for (ggr = 1; ggr < ggrMac; ggr++)
  1423. {
  1424. GetName((AHTEPTR ) FETCHSYM(mpggrrhte[ggr], FALSE), name);
  1425. WriteCopy(&name[1], B2W(name[0]) + 1);
  1426. sizeTotal += (B2W(name[0]) + 1);
  1427. }
  1428. return(sizeTotal);
  1429. }
  1430. /*** OutSst - write subsections
  1431. *
  1432. * Purpose:
  1433. * For every object file with CV information write its sstModule,
  1434. * sstTypes, sstPublics, sstSymbols and sstSrcModule.
  1435. * Build subsection directory.
  1436. *
  1437. * Input:
  1438. * No explicit value is passed.
  1439. * Global variables used:
  1440. * - rprop1stFile - virtual pointer to the first object file descriptor
  1441. *
  1442. * Output:
  1443. * No explicit value is returned.
  1444. * Side effects:
  1445. * - subsections in the executable file
  1446. * - subsection directory in the VM
  1447. *
  1448. * Exceptions:
  1449. * I/O errors - display error message and quit
  1450. *
  1451. * Notes:
  1452. * None.
  1453. *
  1454. *************************************************************************/
  1455. LOCAL void NEAR OutSst(void)
  1456. {
  1457. APROPFILEPTR apropFile; // Real pointer to file entry
  1458. RBTYPE rbFileNext; // Virtual pointer the next file descriptor
  1459. struct dnt dntCur; // Current subsection directory entry
  1460. CVINFO FAR *pCvInfo; // Pointer to the CV info descriptor
  1461. #if CVPACK_SHARED
  1462. #if REVERSE_MODULE_ORDER_FOR_CVPACK
  1463. RBTYPE rbFileCur;
  1464. RBTYPE rbFileLast;
  1465. // reverse module list in place
  1466. // I've been waiting all my life to actually *need* this code... [rm]
  1467. // this will cause us to write the modules tables in REVERSE order
  1468. // (this gives better swapping behaviour in the cvpack phase
  1469. // because the modules cvpack will visit first will be the ones that
  1470. // are still resident...
  1471. rbFileCur = rprop1stFile;
  1472. rbFileLast = NULL;
  1473. while (rbFileCur != NULL)
  1474. {
  1475. apropFile = (APROPFILEPTR ) FETCHSYM(rbFileCur, TRUE);
  1476. rbFileNext = apropFile->af_FNxt;// Get pointer to next file
  1477. apropFile->af_FNxt = rbFileLast;
  1478. rbFileLast = rbFileCur;
  1479. rbFileCur = rbFileNext;
  1480. }
  1481. rprop1stFile = rbFileLast;
  1482. #endif
  1483. #endif
  1484. rbFileNext = rprop1stFile;
  1485. dntCur.iMod = 1;
  1486. while (rbFileNext != NULL) // For every module
  1487. {
  1488. apropFile = (APROPFILEPTR ) FETCHSYM(rbFileNext, TRUE);
  1489. rbFileNext = apropFile->af_FNxt;// Get pointer to next file
  1490. // Skip this module if no debug info for it
  1491. if (!apropFile->af_cvInfo && !apropFile->af_publics && !apropFile->af_Src)
  1492. continue;
  1493. pCvInfo = apropFile->af_cvInfo;
  1494. // sstModules
  1495. dntCur.sst = SSTMODULES4;
  1496. dntCur.lfo = FTELL_BSRUNFILE() - lfaBase;
  1497. dntCur.cb = OutModule(apropFile);
  1498. PutDnt(&dntCur);
  1499. // sstTypes
  1500. if (pCvInfo && pCvInfo->cv_cbTyp > 0L)
  1501. {
  1502. Pad2Dword();
  1503. if (apropFile->af_flags & FPRETYPES)
  1504. dntCur.sst = SSTPRETYPES;
  1505. else
  1506. dntCur.sst = SSTTYPES4;
  1507. dntCur.lfo = FTELL_BSRUNFILE() - lfaBase;
  1508. dntCur.cb = pCvInfo->cv_cbTyp;
  1509. WriteNocopy(pCvInfo->cv_typ, pCvInfo->cv_cbTyp);
  1510. IF_NOT_CVPACK_SHARED(FFREE(pCvInfo->cv_typ));
  1511. PutDnt(&dntCur);
  1512. }
  1513. // sstPublics
  1514. if (apropFile->af_publics && !fSkipPublics)
  1515. {
  1516. Pad2Dword();
  1517. dntCur.sst = SSTPUBLICSYM;
  1518. dntCur.lfo = FTELL_BSRUNFILE() - lfaBase;
  1519. dntCur.cb = OutPublics(apropFile->af_publics);
  1520. PutDnt(&dntCur);
  1521. }
  1522. // sstSymbols
  1523. if (pCvInfo && pCvInfo->cv_cbSym > 0L)
  1524. {
  1525. Pad2Dword();
  1526. dntCur.sst = SSTSYMBOLS4;
  1527. dntCur.lfo = FTELL_BSRUNFILE() - lfaBase;
  1528. dntCur.cb = pCvInfo->cv_cbSym;
  1529. WriteNocopy(pCvInfo->cv_sym, pCvInfo->cv_cbSym);
  1530. IF_NOT_CVPACK_SHARED(FFREE(pCvInfo->cv_sym));
  1531. PutDnt(&dntCur);
  1532. }
  1533. // sstSrcModule
  1534. if (apropFile->af_Src)
  1535. {
  1536. Pad2Dword();
  1537. dntCur.sst = SSTSRCMODULE;
  1538. dntCur.lfo = FTELL_BSRUNFILE() - lfaBase;
  1539. dntCur.cb = OutSrcModule(apropFile->af_Src);
  1540. PutDnt(&dntCur);
  1541. }
  1542. dntCur.iMod++;
  1543. }
  1544. // sstLibraries
  1545. Pad2Dword();
  1546. dntCur.sst = SSTLIBRARIES4;
  1547. dntCur.iMod = (short) 0xffff;
  1548. dntCur.lfo = FTELL_BSRUNFILE() - lfaBase;
  1549. dntCur.cb = OutLibSec();
  1550. PutDnt(&dntCur);
  1551. // sstSegMap
  1552. Pad2Dword();
  1553. dntCur.sst = SSTSEGMAP;
  1554. dntCur.lfo = FTELL_BSRUNFILE() - lfaBase;
  1555. dntCur.cb = OutSegMap();
  1556. PutDnt(&dntCur);
  1557. // sstSegNames
  1558. Pad2Dword();
  1559. dntCur.sst = SSTSEGNAME;
  1560. dntCur.lfo = FTELL_BSRUNFILE() - lfaBase;
  1561. dntCur.cb = OutSegNames();
  1562. PutDnt(&dntCur);
  1563. FFREE(fileBase);
  1564. FFREE(raSeg);
  1565. FFREE(segNo);
  1566. }
  1567. #pragma check_stack(off)
  1568. /*
  1569. * OutLibSec : Output sstLibraries subsection to bsRunfile
  1570. *
  1571. * Path prefix is stripped from library name.
  1572. * If no libraries, don't output anything.
  1573. *
  1574. * Parameters: none
  1575. * Returns: Number of bytes in Libraries subsection
  1576. */
  1577. LOCAL int NEAR OutLibSec ()
  1578. {
  1579. WORD ifh;
  1580. AHTEPTR ahte;
  1581. int cb = 0;
  1582. BYTE *pb;
  1583. if (ifhLibMac == 0)
  1584. return(0);
  1585. // Libraries subsection consists of a list of library
  1586. // names which will be indexed by library numbers in the
  1587. // sstModules. Those indexes are 1-based.
  1588. // cb == 0, use it to write a single byte
  1589. WriteCopy(&cb, 1); // 0th entry is null for now
  1590. cb++;
  1591. for (ifh = 0; ifh < ifhLibMac; ifh++)
  1592. {
  1593. if (mpifhrhte[ifh] != RHTENIL)
  1594. {
  1595. ahte = (AHTEPTR) FETCHSYM(mpifhrhte[ifh],FALSE);
  1596. #if OSXENIX
  1597. pb = GetFarSb(ahte->cch);
  1598. #else
  1599. pb = StripDrivePath(GetFarSb(ahte->cch));
  1600. #endif
  1601. }
  1602. else
  1603. pb = "";
  1604. WriteCopy(pb, pb[0] + 1);
  1605. cb += 1 + B2W(pb[0]);
  1606. }
  1607. return(cb);
  1608. }
  1609. /*** OutDntDir - write subsection directory
  1610. *
  1611. * Purpose:
  1612. * Write subsection directory
  1613. *
  1614. * Input:
  1615. * No explicit value is passed.
  1616. * Global variables:
  1617. * - dntPageMac - number of VM pages with DNTs
  1618. *
  1619. * Output:
  1620. * Function returns the size of the directory in bytes.
  1621. *
  1622. * Exceptions:
  1623. * I/O problems - display error message and quit
  1624. *
  1625. * Notes:
  1626. * None.
  1627. *
  1628. *************************************************************************/
  1629. LOCAL DWORD NEAR OutDntDir(void)
  1630. {
  1631. DNTHDR hdr; // Directory header
  1632. hdr.cbDirHeader = sizeof(DNTHDR);
  1633. hdr.cbDirEntry = sizeof(DNT);
  1634. hdr.cDir = dntMac;
  1635. hdr.lfoDirNext = 0L;
  1636. hdr.flags = 0L;
  1637. // Write header
  1638. WriteCopy(&hdr, sizeof(DNTHDR));
  1639. // Write directory
  1640. WriteCopy((char FAR *) rgDnt, dntMac * sizeof(DNT));
  1641. FFREE(rgDnt);
  1642. return(sizeof(DNTHDR) + dntMac * sizeof(DNT));
  1643. }
  1644. /*** OutDebSection - allow debugging
  1645. *
  1646. * Purpose:
  1647. * Append to the executable file the CV information. ONLY CV 4.00
  1648. * format supported.
  1649. *
  1650. * Input:
  1651. * No explicit value is passed.
  1652. * Global variables:
  1653. * - too many to list
  1654. *
  1655. * Output:
  1656. * No explicit value is returned.
  1657. * Side effects:
  1658. * - what do you think ??
  1659. *
  1660. * Exceptions:
  1661. * I/O problems - display error message and quit
  1662. *
  1663. * Notes:
  1664. * None.
  1665. *
  1666. *************************************************************************/
  1667. void OutDebSections(void)
  1668. {
  1669. long lfaDir; // File address of Directory
  1670. DWORD dirSize; // Directory size
  1671. long tmp;
  1672. #if CVPACK_SHARED
  1673. long * plfoDir; // pointer to directory data
  1674. fseek(bsRunfile, 0L, 2); // Go to end of file
  1675. lfaBase = ftell(bsRunfile); // Remember base address
  1676. lposCur = lfaBase; // set current position...
  1677. WriteCopy(szSignature, sizeof(szSignature)); // Signature dword
  1678. WriteCopy(&tmp, sizeof(tmp)); // Skip lfoDir field
  1679. plfoDir = (long *)rgbl[iblLim-1].pb;// remember address of lfoDir
  1680. OutSst(); // Output subsections
  1681. lfaDir = lposCur; // Remember where directory starts
  1682. *plfoDir = lfaDir - lfaBase; // fix up lfoDir field
  1683. dirSize = OutDntDir(); // Output subsection directory
  1684. WriteCopy(szSignature, sizeof(szSignature));
  1685. // Signature dword
  1686. tmp = (lfaDir + dirSize + 2*sizeof(DWORD)) - lfaBase;
  1687. WriteCopy(&tmp, sizeof(long)); // Distance from EOF to base
  1688. // write out the bits that cvpack won't overwrite...
  1689. if (fCVpack)
  1690. WriteFlushSignature();
  1691. else
  1692. WriteFlushAll();
  1693. cbRealBytes = ftell(bsRunfile); // # of real bytes actually written
  1694. lposMac = lposCur;
  1695. iblCur = iblNil;
  1696. #else
  1697. fseek(bsRunfile, 0L, 2); // Go to end of file
  1698. lfaBase = FTELL_BSRUNFILE(); // Remember base address
  1699. WriteExe(szSignature, sizeof(szSignature));
  1700. // Signature dword
  1701. fseek(bsRunfile,4L,1); // Skip lfoDir field
  1702. OutSst(); // Output subsections
  1703. lfaDir = FTELL_BSRUNFILE(); // Remember where directory starts
  1704. fseek(bsRunfile, lfaBase + 4, 0); // Go to lfoDir field
  1705. tmp = lfaDir - lfaBase;
  1706. WriteExe(&tmp, sizeof(long)); // Fix it up
  1707. fseek(bsRunfile, lfaDir, 0); // Go back to directory
  1708. dirSize = OutDntDir(); // Output subsection directory
  1709. WriteExe(szSignature, sizeof(szSignature));
  1710. // Signature dword
  1711. tmp = (lfaDir + dirSize + 2*sizeof(DWORD)) - lfaBase;
  1712. WriteExe(&tmp, sizeof(long)); // Distance from EOF to base
  1713. fseek(bsRunfile, 0L, 2); // Seek to EOF just in case
  1714. #endif
  1715. }
  1716. #if CVPACK_SHARED
  1717. //
  1718. // write data to cvpack memory cache area
  1719. //
  1720. void
  1721. WriteSave(FTYPE fCopy, void *pb, UINT cb)
  1722. {
  1723. if (!rgbl)
  1724. {
  1725. rgbl = (BL *)GetMem(sizeof(BL) * C_BL_INIT);
  1726. iblMac = C_BL_INIT;
  1727. iblLim = 0;
  1728. }
  1729. // if this memory isn't going to stay around, then copy it
  1730. if (fCopy)
  1731. {
  1732. void *pbT = (void *)GetMem(cb);
  1733. memcpy(pbT, pb, cb);
  1734. pb = pbT;
  1735. }
  1736. if (iblLim == iblMac)
  1737. {
  1738. BL *rgblT;
  1739. rgblT = (BL *)GetMem(sizeof(BL) * iblMac * 2);
  1740. memcpy(rgblT, rgbl, sizeof(BL) * iblMac);
  1741. iblMac *= 2;
  1742. FFREE(rgbl);
  1743. rgbl = rgblT;
  1744. }
  1745. rgbl[iblLim].lpos = lposCur;
  1746. rgbl[iblLim].pb = pb;
  1747. iblLim++;
  1748. lposCur += cb;
  1749. }
  1750. // we want to write a few of the blocks because cvpack won't rewrite the
  1751. // first bit... [rm]
  1752. void WriteFlushSignature()
  1753. {
  1754. int ibl, cb;
  1755. // we know that the signature and offset are written in two pieces...
  1756. // if this changes we need to change the magic '2' below [rm]
  1757. for (ibl = 0; ibl < 2; ibl++)
  1758. {
  1759. cb = rgbl[ibl+1].lpos - rgbl[ibl].lpos;
  1760. WriteExe(rgbl[ibl].pb, cb);
  1761. }
  1762. }
  1763. void WriteFlushAll()
  1764. {
  1765. int ibl, cb;
  1766. for (ibl = 0; ibl < iblLim - 1; ibl++)
  1767. {
  1768. cb = rgbl[ibl+1].lpos - rgbl[ibl].lpos;
  1769. WriteExe(rgbl[ibl].pb, cb);
  1770. }
  1771. cb = lposCur - rgbl[ibl].lpos;
  1772. WriteExe(rgbl[ibl].pb, cb);
  1773. }
  1774. // the following are the various callback functions needed to support
  1775. // the cvpack library when we are attempting to not write out the
  1776. // unpacked types and symbols
  1777. #include <io.h>
  1778. extern int printf(char *,...);
  1779. int __cdecl
  1780. link_chsize (int fh, long size)
  1781. {
  1782. LINK_TRACE(printf("chsize(%06d, %08ld)\n", fh, size));
  1783. // we must keep track of the new size so that we will correctly
  1784. // process lseeks that are relative to the end of the file
  1785. lposMac = size;
  1786. return(_chsize(fh,size));
  1787. }
  1788. int __cdecl
  1789. link_close (int x)
  1790. {
  1791. LINK_TRACE(printf("close (%06d)\n", x));
  1792. return(_close(x));
  1793. }
  1794. void __cdecl
  1795. link_exit (int x)
  1796. {
  1797. LINK_TRACE(printf("exit (%06d)\n", x));
  1798. #if USE_REAL
  1799. RealMemExit();
  1800. #endif
  1801. exit(x);
  1802. }
  1803. long __cdecl
  1804. link_lseek (int fh, long lpos, int mode)
  1805. {
  1806. int ibl;
  1807. LINK_TRACE(printf("lseek (%d, %08ld, %2d)\n", fh, lpos, mode));
  1808. // if we have no cache blocks, just forward the request...
  1809. // this will happen on a /CvpackOnly invocation
  1810. if (rgbl == NULL)
  1811. return _lseek(fh, lpos, mode);
  1812. // adjust lpos so that we are always doing an absolute seek
  1813. if (mode == 1)
  1814. lpos = lposCur + lpos;
  1815. else if (mode == 2)
  1816. lpos = lposMac + lpos;
  1817. // check for a bogus seek
  1818. if (lpos > lposMac || lpos < 0)
  1819. {
  1820. // this used to be an internal error... but cvpack sometimes does
  1821. // try to seek beyond the end of the file when it is trying to
  1822. // distinguish a PE exe from an unsegmented DOS exe
  1823. // instead of panicing, we just return failure
  1824. return(-1);
  1825. }
  1826. // if we are in the midst of reading a block, then free that block
  1827. // cvpack never reads the same data twice
  1828. if (iblCur != iblNil)
  1829. {
  1830. // first check if we're in the header -- we might come back to that...
  1831. if (rgbl[iblCur].lpos > cbRealBytes + CB_HEADER_SAVE)
  1832. {
  1833. long lposCurMin, lposCurMac;
  1834. // check for a seek that is within the current bucket
  1835. // in case we're skipping within the current block
  1836. lposCurMin = rgbl[iblCur].lpos;
  1837. if (iblCur < iblLim)
  1838. lposCurMac = rgbl[iblCur+1].lpos;
  1839. else
  1840. lposCurMac = lposMac;
  1841. if (lpos < lposCurMin || lpos >= lposCurMac)
  1842. {
  1843. FFREE(rgbl[iblCur].pb);
  1844. rgbl[iblCur].pb = NULL;
  1845. }
  1846. }
  1847. }
  1848. // if this seek is not in the debug area of the .exe use the real lseek
  1849. if (lpos < cbRealBytes)
  1850. {
  1851. iblCur = iblNil;
  1852. lposCur = lpos;
  1853. return(_lseek(fh,lpos,0));
  1854. }
  1855. // see if we are searching forward (the normal case)
  1856. // if we are, search from the current block, otherwise search from
  1857. // the start (linear search but OK because cvpack doesn't
  1858. // jump around much, it just uses lseek to skip a few bytes here and
  1859. // there)
  1860. if (lpos > lposCur && iblCur != iblNil)
  1861. ibl = iblCur;
  1862. else
  1863. ibl = 0;
  1864. // set the current position
  1865. lposCur = lpos;
  1866. // loop through the buffered writes looking for the requested position
  1867. for (; ibl < iblLim - 1; ibl++)
  1868. {
  1869. if (lpos >= rgbl[ibl].lpos && lpos < rgbl[ibl+1].lpos)
  1870. break; // found bucket
  1871. }
  1872. // set the bucket number, offset within the bucket, and number of bytes
  1873. // left in the bucket
  1874. iblCur = ibl;
  1875. ichCur = lpos - rgbl[ibl].lpos;
  1876. cbCur = CbIbl(ibl) - ichCur;
  1877. // check to make sure we haven't seeked back to a buffer that we already
  1878. // freed...
  1879. ASSERT(rgbl[iblCur].pb != NULL);
  1880. // make sure we get the boundary case... if cvpack is requesting to go to
  1881. // the end of the data that we have written then we MUST seek because
  1882. // cvpack might be about to write out the packed stuff...
  1883. if (lposCur == cbRealBytes)
  1884. _lseek(fh, lpos, 0);
  1885. // we set up the current position earlier... return it now
  1886. return(lposCur);
  1887. }
  1888. int __cdecl
  1889. link_open (const char * x, int y)
  1890. {
  1891. LINK_TRACE(printf("open (%s, %06d)\n", x, y));
  1892. // setup the static variables to a safe state
  1893. // the current position is the start of file and there is no buffer
  1894. // active (iblCur = iblNil)
  1895. iblCur = iblNil;
  1896. lposCur = 0;
  1897. return(_open(x,y));
  1898. }
  1899. int __cdecl
  1900. link_read (int fh, char *pch, unsigned int cb)
  1901. {
  1902. int cbRem;
  1903. LINK_TRACE(printf("read (%d, %06u)\n", fh, cb));
  1904. if (rgbl == NULL)
  1905. return _read(fh, pch, cb);
  1906. // special case zero byte read, not really necessary but
  1907. // avoids any potential problems with trying to setup empty
  1908. // buffers etc. -- it should just fall out anyways but
  1909. // just to be safe [rm]
  1910. if (cb == 0)
  1911. return 0;
  1912. // if there is no buffer active, then just forward the read
  1913. // note that if we are invoked with /CvpackOnly this test will
  1914. // always succeed
  1915. if (iblCur == iblNil)
  1916. {
  1917. if (lposCur + ((long)(unsigned long)cb) < cbRealBytes)
  1918. {
  1919. lposCur += cb;
  1920. return(_read(fh,pch,cb));
  1921. }
  1922. else
  1923. {
  1924. int cbReal = cbRealBytes - lposCur;
  1925. if (_read(fh, pch, cbReal) != cbReal)
  1926. return -1;
  1927. if (link_lseek(fh, cbRealBytes, 0) != cbRealBytes)
  1928. return -1;
  1929. // set the number of bytes remaining to be read in
  1930. cbRem = cb - cbReal;
  1931. pch += cb - cbReal;
  1932. }
  1933. }
  1934. else
  1935. {
  1936. // set the number of bytes remaining to be read in
  1937. cbRem = cb;
  1938. }
  1939. while (cbRem)
  1940. {
  1941. // check if the number of bytes we need to read is less than
  1942. // the number left in the current buffer
  1943. if (cbRem <= cbCur)
  1944. {
  1945. // we can read all the remaining bytes from the current buffer
  1946. // so do it. Copy bytes and adjust the number of bytes left
  1947. // in this buffer, the index into the buffer, and the current
  1948. // position in the file
  1949. memcpy(pch, rgbl[iblCur].pb+ichCur, cbRem);
  1950. cbCur -= cbRem;
  1951. ichCur += cbRem;
  1952. lposCur += cbRem;
  1953. #ifdef DUMP_CVPACK_BYTES
  1954. {
  1955. int i;
  1956. for (i=0;i<cb;i++)
  1957. {
  1958. if ((i&15) == 0)
  1959. printf("%04x: ", i);
  1960. printf("%02x ", pch[i]);
  1961. if ((i&15)==15)
  1962. printf("\n");
  1963. }
  1964. }
  1965. if ((i&15))
  1966. printf("\n");
  1967. #endif
  1968. return cb;
  1969. }
  1970. else
  1971. {
  1972. // in this case, the read is bigger than the current buffer
  1973. // we'll be reading the whole buffer and then moving to the
  1974. // next buffer
  1975. // first read in the rest of this buffer
  1976. memcpy(pch, rgbl[iblCur].pb+ichCur, cbCur);
  1977. // adjust the number of bytes remaining and the current file
  1978. // position...
  1979. pch += cbCur;
  1980. cbRem -= cbCur;
  1981. lposCur += cbCur;
  1982. // we won't be coming back to this buffer, so return it to the
  1983. // system and mark it as freed
  1984. // first check if we're in the header -- we might come back to that
  1985. if (rgbl[iblCur].lpos > cbRealBytes + CB_HEADER_SAVE)
  1986. {
  1987. FFREE(rgbl[iblCur].pb);
  1988. rgbl[iblCur].pb = NULL;
  1989. }
  1990. // move forward to the next bucket, if there are no more buckets
  1991. // then this is an ERROR -- we'll be returning the number of
  1992. // bytes that we managed to read
  1993. iblCur++;
  1994. if (iblCur == iblLim)
  1995. {
  1996. iblCur = iblNil;
  1997. break;
  1998. }
  1999. // check to make sure that we are not reading data that
  2000. // we've already freed (yipe!)
  2001. ASSERT(rgbl[iblCur].pb != NULL);
  2002. // check to make sure that the current position agrees with
  2003. // the position that this buffer is supposed to occur at
  2004. ASSERT(lposCur == rgbl[iblCur].lpos);
  2005. // ok, everything is safe now, set the index into the current
  2006. // buffer and the number of bytes left in the buffer, then
  2007. // run the loop again until we've read in all the bytes we need
  2008. ichCur = 0;
  2009. cbCur = CbIbl(iblCur);
  2010. }
  2011. }
  2012. // return the number of bytes we actually read
  2013. return cb - cbRem;
  2014. }
  2015. long __cdecl
  2016. link_tell (int x)
  2017. {
  2018. LINK_TRACE(printf("tell (%06d)\n", x));
  2019. if (iblCur != iblNil)
  2020. return(lposCur);
  2021. return(_tell(x));
  2022. }
  2023. int __cdecl
  2024. link_write (int x, const void * y, unsigned int z)
  2025. {
  2026. LINK_TRACE(printf("write (%06d,%08lx,%06u)\n", x, y, z));
  2027. return(_write(x,y,z));
  2028. }
  2029. #ifdef CVPACK_DEBUG_HELPER
  2030. void dumpstate()
  2031. {
  2032. printf("lposCur= %d\n", lposCur);
  2033. printf("iblCur = %d\n", iblCur);
  2034. printf("ichCur = %d\n", ichCur);
  2035. printf("cbReal = %d\n", cbRealBytes);
  2036. printf("lposMac= %d\n", lposMac);
  2037. }
  2038. #endif
  2039. #else
  2040. #ifdef CVPACK_MONDO
  2041. #include <io.h>
  2042. int __cdecl
  2043. link_chsize (int x, long y)
  2044. {
  2045. return(_chsize(x,y));
  2046. }
  2047. int __cdecl
  2048. link_close (int x)
  2049. {
  2050. return(_close(x));
  2051. }
  2052. void __cdecl
  2053. link_exit (int x)
  2054. {
  2055. #if USE_REAL
  2056. RealMemExit();
  2057. #endif
  2058. exit(x);
  2059. }
  2060. long __cdecl
  2061. link_lseek (int x, long y, int z)
  2062. {
  2063. return(_lseek(x,y,z));
  2064. }
  2065. int __cdecl
  2066. link_open (const char *x, int y)
  2067. {
  2068. return(_open(x,y));
  2069. }
  2070. int __cdecl
  2071. link_read (int x, void *y, unsigned int z)
  2072. {
  2073. return(_read(x,y,z));
  2074. }
  2075. long __cdecl
  2076. link_tell (int x)
  2077. {
  2078. return(_tell(x));
  2079. }
  2080. int __cdecl
  2081. link_write (int x, const void * y, unsigned int z)
  2082. {
  2083. return(_write(x,y,z));
  2084. }
  2085. #endif
  2086. #endif