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.

2229 lines
61 KiB

  1. // MAPSYM.C
  2. //
  3. // where "filename" is .MAP file produced by MSlink.
  4. //
  5. //
  6. // Modifications
  7. // 21 Jun 84 Reuben Borman
  8. // - Declared a static buffer for mapfh for use by the runtime I/O.
  9. // Previously, mapfh was being read unbuffered because all the heap
  10. // was being grabbed beforehand.
  11. // 30 Nov 88 Thomas Fenwick
  12. // - added detection and support for LINK32 map files.
  13. // 14 Mar 95 Jon Thomason
  14. // - Made into a console app (mapsym32), removed coff support, 'modernized'
  15. // 17 Apr 96 Greg Jones
  16. // - Added -t option to include static symbols
  17. // 13 May 96 Raymond Chen
  18. // - Version 6.01: Fix underflow bug if group consists entirely of
  19. // unused line numbers.
  20. // - Version 6.02: Fix overflow bug if symbol exceeds 127 chars.
  21. // (The limit is theoretically 255, but hdr.exe barfs
  22. // if more than 127)
  23. //
  24. #include <ctype.h>
  25. #include <malloc.h>
  26. #include <memory.h>
  27. #include <process.h>
  28. #include <stdarg.h>
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <string.h>
  32. #include <stddef.h>
  33. #include "mapsym.h"
  34. #include <common.ver>
  35. #define ZEROLINEHACK // suppress N386 generated 0 line numbers
  36. // Globals
  37. int cbOffsets = CBOFFSET;
  38. int cbMapOffset = 4;
  39. FILE *mapfh;
  40. char MapfhBuf[OURBUFSIZ];
  41. char achMapfn[512];
  42. char *pszMapfn; /* MAP input file */
  43. FILE *exefh;
  44. char ExefhBuf[OURBUFSIZ];
  45. char *pszExefn; /* PE EXE input file */
  46. FILE *outfh;
  47. char OutfhBuf[OURBUFSIZ];
  48. char achOutfn[512];
  49. char *pszOutfn; /* sym or PE EXE output file */
  50. char Buf[MAPBUFLEN];
  51. char achZeroFill[128];
  52. char fLogo = 1; /* set if want logo */
  53. char f32BitMap; /* set if map created by link32.exe */
  54. char fMZMap; /* set if map created from old exe map */
  55. char fList; /* set if want to see stuff */
  56. char fLine = 1; /* set if want line number info */
  57. char fAlpha; /* set if want alpha symbol sort */
  58. char fDebug; /* debug flag */
  59. char fEdit; /* NTSD hack flag */
  60. char fModname; /* set if force module name override */
  61. char fQuiet; /* suppress module name warning */
  62. char fStatic; /* set if want static symbols */
  63. int fByChar; /* getc()/fgetl() flag */
  64. int cLine; /* map file line counter */
  65. int cSeg; /* number of Segments in map */
  66. int iSegLast;
  67. unsigned SegVal;
  68. unsigned uVal;
  69. unsigned long ulCost; /* Count of stricmp()'s for sorting */
  70. unsigned long ulVal;
  71. unsigned long cbSymFile;
  72. extern struct seg_s *SegTab[];
  73. struct sym_s *pAbs; /* pointer to constant chain */
  74. struct sym_s *pAbsLast; /* pointer to last constant */
  75. struct map_s *pMap;
  76. struct endmap_s *pMapEnd;
  77. union linerec_u LineRec[MAXLINENUMBER];
  78. struct seg_s *SegTab[MAXSEG];
  79. /* Indices into a MAP file line for various fields of interest. */
  80. /* The first list doesn't change with maps produced by LINK vs. LINK32 */
  81. #define IB_SEG 1
  82. #define IB_SYMOFF 6
  83. #define IB_SEGSIZE 15 // size position for 16 bit MZ and 32 bit PE/NE
  84. #define IB_SEGSIZE_NE16 11
  85. #define IB_GROUPNAME 10
  86. #define IB_ENTRYSEG 23
  87. #define IB_ENTRYOFF 28
  88. /*
  89. * The next list changes based upon the type of map produced. Values
  90. * for 16-bit maps are given, IB_ADJUST32 must be added for 32-bit maps.
  91. */
  92. #define IB_SYMTYPE 12
  93. #define IB_SYMNAME 17
  94. #define IB_SEGNAME 22
  95. char *pBufSegSize = &Buf[IB_SEGSIZE];
  96. #define IB_ADJUST32 4 /* adjustment to above indices for 32-bit maps */
  97. char *pBufSymType = &Buf[IB_SYMTYPE];
  98. char *pBufSymName = &Buf[IB_SYMNAME];
  99. char *pBufSegName = &Buf[IB_SEGNAME];
  100. /* Tag strings */
  101. char achEntry[] = "entry point at";
  102. char achLength[] = "Length";
  103. char achLineNos[] = "Line numbers for";
  104. char achOrigin[] = "Origin";
  105. char achPublics[] = "Publics by Valu";
  106. char achStart[] = " Start "; /* blanks avoid matching module name */
  107. char achStatic[] = " Static symbols";
  108. char achFixups[] = "FIXUPS:";
  109. char achStartMZ[] = " Start Stop Length"; /* 16-bit "MZ" old exe */
  110. char achStartNE[] = " Start Length"; /* 16-bit "NE" new exe */
  111. char achStartPE[] = " Start Length"; /* 32-bit "PE" */
  112. int alignment = 16; /* global alignment value for map */
  113. /* function prototypes */
  114. int parsefilename(char *pfilename, char *pbuf);
  115. struct map_s* BuildMapDef(char *mapname, char *buf);
  116. void BuildSegDef(void);
  117. void BuildGroupDef(void);
  118. void BuildLineDef(void);
  119. int getlineno(void);
  120. unsigned long getoffset(void);
  121. void FixLineDef(void);
  122. void TruncateLineDef(struct line_s *pli, unsigned long ulnext);
  123. void BuildStaticSyms(void);
  124. void BuildSymDef(void);
  125. void WriteSym(void);
  126. int WriteMapRec(void);
  127. void WriteSegRec(int i);
  128. void WriteLineRec(int i);
  129. void ReadMapLine(void);
  130. void RedefineSegDefName(unsigned segno, char *segname);
  131. void WriteOutFile(void *src, int len);
  132. void WriteSyms(struct sym_s *psy, unsigned csym,
  133. unsigned char symtype, unsigned long symbase, char *segname);
  134. struct sym_s* sysort(struct sym_s *psylist,unsigned csy);
  135. struct sym_s* sysplit(struct sym_s *psyhead, register unsigned csy);
  136. struct sym_s* symerge(struct sym_s *psy1, struct sym_s *psy2);
  137. struct sym_s* sysorted(struct sym_s **ppsyhead);
  138. int fgetl(char *pbuf, int len, struct _iobuf *fh);
  139. int NameLen(char *p);
  140. int HexTouVal(char *p);
  141. int HexToulVal(char *p);
  142. int CharToHex(int c);
  143. int rem_align(unsigned long foo);
  144. int align(int foo);
  145. void logo(void);
  146. void usage(void);
  147. void xexit(int rc);
  148. int BuildLineRec1or2(struct line_s* pli, int (*pfngetlineno)(void),
  149. unsigned long (*pfngetoffset)(void));
  150. char* Zalloc(unsigned int cb);
  151. void AddSegDef(unsigned int segno, unsigned long segsize,
  152. char *segname);
  153. void AddAbsDef(char *symname);
  154. void AddSymDef(struct seg_s *pse, char *symname, int fSort);
  155. int NameSqueeze(char *p);
  156. struct line_s* AllocLineDef(char *filename, unsigned cbname);
  157. void AddLineDef(struct line_s *pli, unsigned long lcb);
  158. unsigned long salign(unsigned long foo);
  159. void __cdecl error(char *fmt, ...);
  160. void __cdecl errorline(char *fmt, ...);
  161. int __cdecl cmpoffset(union linerec_u* plr1, union linerec_u* plr2);
  162. // main
  163. void
  164. _cdecl
  165. main(
  166. int argc,
  167. char** argv
  168. )
  169. {
  170. char* p;
  171. int i, rc, chswitch;
  172. char fentry; /* true if entry point was found */
  173. unsigned long entryp;
  174. /* process options */
  175. while (argc > 1 && ((chswitch = *(p = argv[1])) == '-' || *p == '/')) {
  176. argc--, argv++;
  177. if (strcmp(&p[1], "nologo") == 0) {
  178. if (chswitch == '/') {
  179. usage(); // only allow '/' on old switches
  180. }
  181. fLogo = 0;
  182. continue;
  183. }
  184. while (*++p) {
  185. if (chswitch == '/' && strchr("adlLnNsS", *p) == NULL) {
  186. usage(); // only allow '/' on old switches
  187. }
  188. switch (*p) {
  189. case 'o':
  190. if (pszOutfn || p[1] || argc < 3) {
  191. usage();
  192. }
  193. pszOutfn = argv[1];
  194. argc--, argv++;
  195. break;
  196. case 'a':
  197. fAlpha = MSF_ALPHASYMS;
  198. break;
  199. case 'd': fList++; fDebug++; break;
  200. case 'e': fEdit++; break;
  201. case 'l':
  202. case 'L': fList++; break;
  203. case 'm': fModname++; break;
  204. case 'q': fQuiet++; break;
  205. case 'n':
  206. case 'N': fLine = 0; break;
  207. case 's':
  208. case 'S': break; // Default
  209. case 't':
  210. case 'T': fStatic++; break;
  211. default: usage(); break;
  212. }
  213. }
  214. }
  215. logo();
  216. if (argc < 2) { /* must have at least one argument */
  217. usage();
  218. } else if (argc > 2) { /* If extra arguments */
  219. fprintf(stderr, "Warning: ignoring \"%s", argv[2]);
  220. for (i = 3; i < argc; i++) {
  221. fprintf(stderr, " %s", argv[i]); /* Print ignored arguments */
  222. }
  223. fprintf(stderr, "\"\n");
  224. }
  225. argv++; /* point to filename arg */
  226. /* create .sym file name */
  227. if (pszOutfn == NULL) {
  228. parsefilename(*argv, achOutfn);
  229. strcat(pszOutfn = achOutfn, ".sym");
  230. }
  231. /* create .map file name */
  232. strcpy(pszMapfn = achMapfn, *argv);
  233. if (!parsefilename(pszMapfn, NULL)) { /* if no extension */
  234. strcat(pszMapfn, ".Map");
  235. }
  236. if (fList) {
  237. printf("Building %s from %s\n", pszOutfn, pszMapfn);
  238. }
  239. if (fLine)
  240. printf("Line number support enabled\n");
  241. else
  242. printf("Line number support disabled\n");
  243. if (fAlpha) {
  244. printf("Alphabetic sort arrays included in SYM file\n");
  245. cbOffsets = 2 * CBOFFSET;
  246. }
  247. /* initialize MAP */
  248. pMapEnd = (struct endmap_s *) Zalloc(sizeof(struct endmap_s));
  249. pMapEnd->em_ver = MAPSYM_VERSION; /* version */
  250. pMapEnd->em_rel = MAPSYM_RELEASE; /* release */
  251. // see if input file is a map or coff debug info
  252. if ((exefh = fopen(pszMapfn, "rb")) == NULL) {
  253. error("can't open input file: %s", pszMapfn);
  254. xexit(1);
  255. }
  256. setvbuf(exefh, ExefhBuf, _IOFBF, OURBUFSIZ);
  257. if ((outfh = fopen(pszOutfn, "wb")) == NULL) {
  258. error("can't create: %s", pszOutfn);
  259. xexit(1);
  260. }
  261. setvbuf(outfh, OutfhBuf, _IOFBF, OURBUFSIZ);
  262. fclose(exefh);
  263. if ((mapfh = fopen(pszMapfn, "r")) == NULL) {
  264. error("can't open input file: %s", pszMapfn);
  265. xexit(1);
  266. }
  267. setvbuf(mapfh, MapfhBuf, _IOFBF, OURBUFSIZ);
  268. // Skip possible extraneous text at the start of the map file
  269. // Map file module names have a space in the first column,
  270. // extraneous text does not. The module name may not exist,
  271. // so stop at achStart.
  272. // "Stack Allocation = 8192 bytes" ; extraneous
  273. // " modname" ; module name
  274. // " Start ..." ; begin segment list
  275. do {
  276. ReadMapLine(); /* read possible module name */
  277. } while (Buf[0] != ' ');
  278. // If at achStart, no module name was found.
  279. // Don't call ReadMapLine() again; BuildSegDef needs achStart
  280. if (strstr(Buf, achStart) == Buf) {
  281. pMap = BuildMapDef(pszMapfn, "");
  282. } else {
  283. pMap = BuildMapDef(pszMapfn, Buf);
  284. ReadMapLine(); /* read next line of map file */
  285. }
  286. BuildSegDef(); /* build segment definitions */
  287. BuildGroupDef(); /* build group definitions */
  288. BuildSymDef(); /* build symbol definitions */
  289. fentry = 0;
  290. do {
  291. if (strstr(Buf, achLineNos)) {
  292. if (fLine) {
  293. BuildLineDef();
  294. }
  295. } else if (strstr(Buf, achEntry)) {
  296. if (HexToulVal(&Buf[IB_ENTRYOFF]) < 4) {
  297. errorline("invalid entry offset");
  298. xexit(4);
  299. }
  300. entryp = ulVal;
  301. if (!HexTouVal(&Buf[IB_ENTRYSEG])) {
  302. errorline("invalid entry segment");
  303. xexit(4);
  304. }
  305. pMap->mp_mapdef.md_segentry = (unsigned short)uVal;
  306. fentry++;
  307. } else if (strstr(Buf, achStatic) && fStatic) {
  308. BuildStaticSyms();
  309. }
  310. } while (fgetl(Buf, MAPBUFLEN, mapfh));
  311. if (fentry) {
  312. printf("Program entry point at %04x:%04lx\n",
  313. pMap->mp_mapdef.md_segentry,
  314. entryp);
  315. } else {
  316. printf("No entry point, assume 0000:0100\n");
  317. }
  318. fclose(mapfh);
  319. rc = 0;
  320. WriteSym(); /* write out .SYM file */
  321. fflush(outfh);
  322. if (ferror(outfh)) {
  323. error("%s: write error", pszOutfn);
  324. rc++;
  325. }
  326. fclose(outfh);
  327. exit(rc);
  328. }
  329. /*
  330. * parsefilename - Copy pfilename without path or extension
  331. * into pbuf (if pbuf != NULL)
  332. *
  333. * returns non-zero value if extension existed.
  334. */
  335. int
  336. parsefilename(
  337. char *pfilename,
  338. char *pbuf
  339. )
  340. {
  341. char *p1, *p2;
  342. p1 = pfilename;
  343. if (isalpha(*p1) && p1[1] == ':') {
  344. p1 += 2; /* skip drive letter if specified */
  345. }
  346. while (p2 = strpbrk(p1, "/\\")) {
  347. p1 = p2 + 1; /* skip pathname if specified */
  348. }
  349. if (pbuf) {
  350. strcpy(pbuf, p1);
  351. if (p2 = strrchr(pbuf, '.')) {
  352. *p2 = '\0'; /* eliminate rightmost . and any extension */
  353. }
  354. }
  355. return(strchr(p1, '.') != NULL);
  356. }
  357. struct map_s*
  358. BuildMapDef(
  359. char* mapname,
  360. char* buf
  361. ) {
  362. unsigned cbname;
  363. struct map_s *pmp;
  364. char *pszname;
  365. char namebuf1[MAPBUFLEN]; // module name from map/exe file name
  366. char namebuf2[MAPBUFLEN]; // module name from map/exe file contents
  367. pszname = namebuf1;
  368. parsefilename(mapname, pszname);
  369. while (*buf == ' ' || *buf == '\t') {
  370. buf++;
  371. }
  372. if (cbname = strcspn(buf, " \t")) {
  373. buf[cbname] = '\0';
  374. }
  375. if (*buf) {
  376. parsefilename(buf, namebuf2);
  377. if (_stricmp(pszname, namebuf2)) {
  378. if (fModname) {
  379. pszname = namebuf2; // use module name from file contents
  380. if (fList) {
  381. printf("using \"%s\" for module name\n", pszname);
  382. }
  383. } else if (!fQuiet) {
  384. errorline("Warning: input file uses \"%s\" for module name, not \"%s\"",
  385. namebuf2,
  386. pszname);
  387. }
  388. }
  389. } else if (fModname) {
  390. errorline("Warning: No module name found; using \"%s\" for module name", pszname);
  391. }
  392. _strupr(pszname);
  393. cbname = NameLen(pszname);
  394. pmp = (struct map_s *) Zalloc(sizeof(struct map_s) + cbname);
  395. pmp->mp_mapdef.md_abstype = fAlpha;
  396. pmp->mp_mapdef.md_cbname = (char) cbname;
  397. strcpy((char *) pmp->mp_mapdef.md_achname, pszname);
  398. return(pmp);
  399. }
  400. void
  401. BuildSegDef(void)
  402. {
  403. int i;
  404. int fDup;
  405. fDup = 0;
  406. while (strstr(Buf, achStart) != Buf) {
  407. ReadMapLine();
  408. }
  409. if (strstr(Buf, achStartPE) == Buf) {
  410. f32BitMap++;
  411. pBufSymType += IB_ADJUST32;
  412. pBufSymName += IB_ADJUST32;
  413. pBufSegName += IB_ADJUST32;
  414. cbMapOffset += IB_ADJUST32;
  415. if (fList) {
  416. printf("32-bit PE map\n");
  417. }
  418. } else if (strstr(Buf, achStartMZ) == Buf) {
  419. fMZMap++;
  420. if (fList) {
  421. printf("16-bit MZ map\n");
  422. }
  423. } else if (strstr(Buf, achStartNE) == Buf) {
  424. pBufSegSize = &Buf[IB_SEGSIZE_NE16];
  425. if (fList) {
  426. printf("16-bit NE map\n");
  427. }
  428. } else {
  429. errorline("unrecognized map type");
  430. xexit(4);
  431. }
  432. ReadMapLine();
  433. /* here comes the correction for a small change in PE map files.
  434. This program's map file parser expects a certain
  435. map-file layout. Especially it assumes that token start at
  436. fixed, predefined columns. Well, the "segment name column"
  437. has changed (one column to the left) and now we try to find out
  438. if the current mapfile is such a beast.
  439. !!!!! We make here the assumption that the segment definition
  440. !!!!! immediately starts behind the "Start Len" line.
  441. */
  442. if (f32BitMap && (*(pBufSegName-1) != ' '))
  443. pBufSegName--;
  444. do {
  445. if (HexToulVal(pBufSegSize) < 4) {
  446. ulVal = 0; // ulVal is the segment size
  447. }
  448. if (HexTouVal(&Buf[IB_SEG])) {
  449. if (cSeg > 0) {
  450. for (i = 0; i < cSeg; i++) {
  451. if ((fDup = (SegTab[i]->se_segdef.gd_lsa == uVal))) {
  452. if (SegTab[i]->se_cbseg == 0 && ulVal != 0) {
  453. RedefineSegDefName(i, pBufSegName);
  454. SegTab[i]->se_cbseg = ulVal;
  455. }
  456. break;
  457. }
  458. }
  459. }
  460. if (!fDup) {
  461. AddSegDef(uVal, ulVal, pBufSegName);
  462. }
  463. }
  464. ReadMapLine();
  465. } while (strstr(Buf, achOrigin) != &Buf[1] &&
  466. strstr(Buf, achPublics) == NULL &&
  467. strstr(Buf, achEntry) == NULL);
  468. }
  469. void
  470. BuildGroupDef(void)
  471. {
  472. int i;
  473. int fRedefine;
  474. int fDup;
  475. /* find "origin-group" label in map file which precedes the group list */
  476. while (strstr(Buf, achOrigin) != &Buf[1]) {
  477. if (strstr(Buf, achPublics) || strstr(Buf, achEntry)) {
  478. return;
  479. }
  480. ReadMapLine();
  481. }
  482. ReadMapLine();
  483. /* read in group definitions while they exist */
  484. while (HexTouVal(&Buf[IB_SEG])) {
  485. /* if not the FLAT group in a link32 map */
  486. if (fMZMap || uVal || _stricmp(&Buf[IB_GROUPNAME], "FLAT")) {
  487. fRedefine = 0;
  488. /* search through segment table for group address */
  489. for (i = 0; i < cSeg; i++) {
  490. if (SegTab[i]->se_segdef.gd_lsa == uVal &&
  491. SegTab[i]->se_redefined == 0) {
  492. RedefineSegDefName(i, &Buf[IB_GROUPNAME]);
  493. SegTab[i]->se_redefined = 1;
  494. fRedefine++;
  495. break;
  496. }
  497. }
  498. if (!fRedefine) {
  499. for (i = 0; i < cSeg; i++) {
  500. fDup = (SegTab[i]->se_segdef.gd_lsa == uVal);
  501. if (fDup) {
  502. break;
  503. }
  504. }
  505. if (!fDup) {
  506. AddSegDef(uVal, 0L, &Buf[IB_GROUPNAME]);
  507. }
  508. }
  509. }
  510. ReadMapLine();
  511. }
  512. }
  513. void
  514. BuildLineDef(void)
  515. {
  516. struct line_s *pli;
  517. int cbname;
  518. int cblr;
  519. int i;
  520. char *p;
  521. /* make sure that there is a source file in parentheses */
  522. p = pBufSymName;
  523. while (*p && *p != LPAREN) {
  524. p++;
  525. }
  526. if (*p == LPAREN) {
  527. i = (int)(p - pBufSymName + 1); // index start of source file name
  528. } else { /* else no source file, return .obj name */
  529. if (p = strrchr(pBufSymName, '.')) {
  530. *p = '\0'; /* throw away ".obj" */
  531. }
  532. i = 0; /* point to .obj name */
  533. }
  534. cbname = NameSqueeze(&pBufSymName[i]);// Squeeze \\, convert /'s to \'s
  535. pli = AllocLineDef(&pBufSymName[i], cbname); // pass source name
  536. // clear line record array; any entry with a line number of zero is empty
  537. memset(LineRec, 0, sizeof(LineRec));
  538. /* process line numbers */
  539. cblr = BuildLineRec1or2(pli, getlineno, getoffset);
  540. if (cblr) {
  541. /* size is size of linedef_s + name size + size of line recs */
  542. AddLineDef(pli, sizeof(struct linedef_s) + cbname + cblr);
  543. }
  544. }
  545. struct line_s*
  546. AllocLineDef(
  547. char* filename,
  548. unsigned cbname
  549. ) {
  550. struct line_s* pli;
  551. if (pMap->mp_mapdef.md_cbnamemax < (char) cbname) {
  552. pMap->mp_mapdef.md_cbnamemax = (char) cbname;
  553. }
  554. pli = (struct line_s *) Zalloc(sizeof(struct line_s) + cbname);
  555. pli->li_linedef.ld_cbname = (char) cbname;
  556. strcpy((char *) pli->li_linedef.ld_achname, filename);
  557. return(pli);
  558. }
  559. void
  560. AddLineDef(
  561. struct line_s *pli,
  562. unsigned long lcb
  563. )
  564. {
  565. int i;
  566. struct seg_s *pse;
  567. struct seg_s *pselast = 0;
  568. struct line_s **ppli;
  569. struct linerec0_s *plr0;
  570. struct linerec1_s *plr1;
  571. struct linerec2_s *plr2;
  572. unsigned long ulfixup;
  573. /*
  574. * The linker puts out all the line number information logical segment
  575. * relative instead of group or physical segment relative unlike the
  576. * symbol information. The map file doesn't contain any group member
  577. * information on the segment so we assume that segments that don't
  578. * have any symbols belong to last segment that contains symbols.
  579. * Note that it's possible that *no* segments contain symbols, so
  580. * care must be taken to ensure that we don't use something that
  581. * doesn't exist.
  582. */
  583. for (i = 0; i < cSeg; i++) {
  584. /*
  585. * Save away the last segment table entry that has symbols
  586. * we are assuming this is the group the segment belongs to.
  587. */
  588. if (SegTab[i]->se_psy) {
  589. pselast = SegTab[i];
  590. }
  591. /*
  592. * Check if the segment table entry matches the segment value
  593. * gotten from the line number information. The segment value
  594. * is segment relative instead of group relative so we may use
  595. * the last segment with symbols.
  596. */
  597. if (SegTab[i]->se_segdef.gd_lsa == SegVal) {
  598. pse = SegTab[i];
  599. /*
  600. * If the segment we just found doesn't have any symbols,
  601. * we will add the line number info to the last segment
  602. * saved away that did have symbols (pselast).
  603. */
  604. if (pse->se_psy || !pselast) {
  605. /*
  606. * No fixup when the segment has symbols since it is the
  607. * "group" and all the code offsets in the line recs are
  608. * relative to it. This is also the case if we haven't found
  609. * a segment yet that has symbols.
  610. */
  611. ulfixup = 0;
  612. } else {
  613. /*
  614. * Calculate the amount each line record will have to be
  615. * fixed up by since these linerecs' code offsets are
  616. * segment relative instead of group relative like the
  617. * symbol info.
  618. */
  619. ulfixup = ((unsigned long)
  620. (pse->se_segdef.gd_lsa - pselast->se_segdef.gd_lsa)) << 4;
  621. pse = pselast;
  622. }
  623. break;
  624. }
  625. }
  626. if (i >= cSeg) {
  627. error("AddLineDef: segment table search failed");
  628. xexit(4);
  629. }
  630. /* if there is a fixup, add it to each line record's code offset */
  631. if (ulfixup) {
  632. i = pli->li_linedef.ld_cline;
  633. switch (pli->li_linedef.ld_itype) {
  634. case 0:
  635. plr0 = &pli->li_plru->lr0;
  636. while (i) {
  637. plr0->lr0_codeoffset += (unsigned short)ulfixup;
  638. plr0++, i--;
  639. }
  640. break;
  641. case 1:
  642. plr1 = &pli->li_plru->lr1;
  643. while (i) {
  644. plr1->lr1_codeoffset += (unsigned short)ulfixup;
  645. plr1++, i--;
  646. }
  647. break;
  648. case 2:
  649. plr2 = &pli->li_plru->lr2;
  650. while (i) {
  651. plr2->lr2_codeoffset += ulfixup;
  652. plr2++, i--;
  653. }
  654. break;
  655. }
  656. }
  657. /*
  658. * if there was a last segment,
  659. * add the linedef_s to the segment linedef_s chain
  660. */
  661. if (pse) {
  662. ppli = &pse->se_pli;
  663. while (*ppli && (*ppli)->li_offmin < pli->li_offmin) {
  664. ppli = &(*ppli)->li_plinext;
  665. }
  666. pli->li_plinext = *ppli;
  667. *ppli = pli;
  668. /* adjust table sizes for linedef_s record and line numbers */
  669. pli->li_cblines = lcb;
  670. }
  671. }
  672. int
  673. __cdecl
  674. cmpoffset(
  675. union linerec_u* plr1,
  676. union linerec_u* plr2
  677. )
  678. {
  679. if (fDebug > 1) {
  680. printf("comparing %08lx line %u with %08lx line %u",
  681. plr1->lr2.lr2_codeoffset,
  682. plr1->lr2.lr2_linenumber,
  683. plr2->lr2.lr2_codeoffset,
  684. plr2->lr2.lr2_linenumber);
  685. }
  686. if (plr1->lr2.lr2_codeoffset < plr2->lr2.lr2_codeoffset) {
  687. if (fDebug > 1) {
  688. printf(": -1\n");
  689. }
  690. return(-1);
  691. }
  692. if (plr1->lr2.lr2_codeoffset > plr2->lr2.lr2_codeoffset) {
  693. if (fDebug > 1) {
  694. printf(": 1\n");
  695. }
  696. return(1);
  697. }
  698. if (fDebug > 1) {
  699. printf(": 0\n");
  700. }
  701. return(0);
  702. }
  703. int
  704. BuildLineRec1or2(
  705. struct line_s* pli,
  706. int (*pfngetlineno)(void),
  707. unsigned long (*pfngetoffset)(void)
  708. )
  709. {
  710. register union linerec_u *plru;
  711. register unsigned short lineno;
  712. unsigned long offval, offmin, offmax;
  713. int clr;
  714. int ilr, ilrmax;
  715. int cblr;
  716. char f32 = 0;
  717. /* read line numbers */
  718. ilrmax = clr = 0; /* count of line records */
  719. fByChar = 1; /* compensate for unread new-line */
  720. while (lineno = (unsigned short)(*pfngetlineno)()) {
  721. offval = (*pfngetoffset)();
  722. #ifdef ZEROLINEHACK
  723. if (lineno == (unsigned short) -1) {
  724. continue;
  725. }
  726. #endif
  727. /*
  728. * Check for too many line numbers. Caller will skip
  729. * the rest (so we don't have to waste time parsing them).
  730. */
  731. if (lineno >= MAXLINENUMBER) {
  732. errorline("too many line numbers in %s, truncated to %d",
  733. pli->li_linedef.ld_achname, MAXLINENUMBER);
  734. break;
  735. }
  736. if (fDebug > 1) {
  737. printf( "%s: line %hu @%lx\n",
  738. pli->li_linedef.ld_achname,
  739. lineno,
  740. offval);
  741. }
  742. /*
  743. * If any of the offsets are 32 bits, clear the 16 bit flag so
  744. * 32 bit line recs will be generated.
  745. */
  746. if (offval & 0xffff0000L) {
  747. f32 = 1;
  748. }
  749. if (ilrmax < lineno) {
  750. ilrmax = lineno;
  751. }
  752. /*
  753. * Only update the count if the line number has not already been read.
  754. */
  755. if (LineRec[lineno].lr2.lr2_linenumber == 0) {
  756. clr++;
  757. }
  758. /*
  759. * Put the line info away in 32 bit format, but we will copy it
  760. * to 16 bit format if none of the offsets are 32 bit.
  761. */
  762. LineRec[lineno].lr2.lr2_codeoffset = offval;
  763. LineRec[lineno].lr2.lr2_linenumber = lineno;
  764. }
  765. /*
  766. * If a segment consists only of unused line numbers, then
  767. * there is nothing to do. Stop now, or we will barf big time
  768. * trying to allocate memory for nothing (and even worse, trying
  769. * to sort 0 - 1 = 4 billion elements).
  770. */
  771. if (clr == 0) {
  772. return 0;
  773. }
  774. /* get size of line record */
  775. if (f32) {
  776. cblr = clr * sizeof(struct linerec2_s);
  777. pli->li_linedef.ld_itype = 2;
  778. } else {
  779. cblr = clr * sizeof(struct linerec1_s);
  780. pli->li_linedef.ld_itype = 1;
  781. }
  782. pli->li_linedef.ld_cline = (unsigned short) clr;
  783. /* allocate space for line numbers */
  784. pli->li_plru = (union linerec_u *) Zalloc(cblr);
  785. // compress out unused line numbers, then sort by offset
  786. ilr = 0;
  787. offmin = 0xffffffff;
  788. offmax = 0;
  789. for (lineno = 0; lineno <= ilrmax; lineno++) {
  790. if (LineRec[lineno].lr2.lr2_linenumber) {
  791. offval = LineRec[lineno].lr2.lr2_codeoffset;
  792. if (offmin > offval) {
  793. offmin = offval;
  794. }
  795. if (offmax < offval) {
  796. offmax = offval;
  797. }
  798. if (fDebug > 1) {
  799. printf("copying %08lx line %u\n",
  800. offval,
  801. LineRec[lineno].lr2.lr2_linenumber);
  802. }
  803. LineRec[ilr++] = LineRec[lineno];
  804. }
  805. }
  806. pli->li_offmin = offmin;
  807. pli->li_offmax = offmax;
  808. ilrmax = ilr - 1;
  809. if (ilrmax != clr - 1) {
  810. error("line count mismatch: %u/%u", ilrmax, clr - 1);
  811. }
  812. // Sort the line numbers
  813. qsort((void *)LineRec, (size_t)ilrmax, sizeof(LineRec[0]),
  814. (int (__cdecl *)(const void *, const void *))cmpoffset);
  815. /* convert and copy line number information */
  816. for (lineno = 0, plru = pli->li_plru; lineno <= ilrmax; lineno++) {
  817. if (f32) {
  818. memcpy(plru, &LineRec[lineno], sizeof(struct linerec2_s));
  819. (unsigned char *) plru += sizeof(struct linerec2_s);
  820. } else {
  821. plru->lr1.lr1_codeoffset =
  822. (unsigned short) LineRec[lineno].lr2.lr2_codeoffset;
  823. plru->lr1.lr1_linenumber = LineRec[lineno].lr2.lr2_linenumber;
  824. (unsigned char *) plru += sizeof(struct linerec1_s);
  825. }
  826. }
  827. fByChar = 0;
  828. return(cblr);
  829. }
  830. /*
  831. * getlineno - get a decimal source file line number,
  832. * ignoring leading tabs, blanks and new-lines.
  833. */
  834. int
  835. getlineno(void)
  836. {
  837. register int num = 0;
  838. register int c;
  839. do {
  840. if ((c = getc(mapfh)) == '\n') {
  841. cLine++;
  842. }
  843. } while (isspace(c));
  844. if (isdigit(c)) {
  845. do {
  846. num = num * 10 + c - '0';
  847. c = getc(mapfh);
  848. } while (isdigit(c));
  849. #ifdef ZEROLINEHACK
  850. if (num == 0) {
  851. num = -1;
  852. }
  853. #endif
  854. } else {
  855. ungetc(c, mapfh);
  856. }
  857. return(num);
  858. }
  859. unsigned long
  860. getoffset(void)
  861. {
  862. register int i;
  863. register int num;
  864. unsigned long lnum;
  865. num = 0;
  866. for (i = 4; i > 0; i--) {
  867. num = (num << 4) + CharToHex(getc(mapfh));
  868. }
  869. SegVal = num;
  870. if (getc(mapfh) != ':') { /* skip colon */
  871. errorline("expected colon");
  872. xexit(4);
  873. }
  874. lnum = 0;
  875. for (i = cbMapOffset; i > 0; i--) {
  876. lnum = (lnum << 4) + (unsigned long) CharToHex(getc(mapfh));
  877. }
  878. return(lnum);
  879. }
  880. unsigned long ulmind;
  881. unsigned long ulmaxd;
  882. void
  883. FixLineDef(void)
  884. {
  885. int i;
  886. struct line_s *pli;
  887. for (i = 0; i < cSeg; i++) {
  888. ulmind = (unsigned long) -1;
  889. ulmaxd = 0;
  890. if (pli = SegTab[i]->se_pli) {
  891. while (pli) {
  892. if (fDebug) {
  893. printf("%s: (%d: %lx - %lx)",
  894. pli->li_linedef.ld_achname,
  895. pli->li_linedef.ld_cline,
  896. pli->li_offmin,
  897. pli->li_offmax);
  898. }
  899. TruncateLineDef(pli,
  900. pli->li_plinext == NULL?
  901. pli->li_offmax + 1 :
  902. pli->li_plinext->li_offmin);
  903. if (fDebug) {
  904. printf(" (%d: %lx - %lx)\n",
  905. pli->li_linedef.ld_cline,
  906. pli->li_offmin,
  907. pli->li_offmax);
  908. }
  909. pli = pli->li_plinext;
  910. }
  911. }
  912. if (fList && (ulmaxd || ulmind != (unsigned long) -1)) {
  913. printf("Ignoring extraneous line records for Seg %d, offsets %lx - %lx\n",
  914. i + 1,
  915. ulmind,
  916. ulmaxd);
  917. }
  918. }
  919. }
  920. void
  921. TruncateLineDef(
  922. struct line_s *pli,
  923. unsigned long ulnext
  924. )
  925. {
  926. int i, clines;
  927. union linerec_u *plru, *plrudst;
  928. unsigned long ulmindel, ulmaxdel, ulmax;
  929. ulmindel = (unsigned long) -1;
  930. ulmax = ulmaxdel = 0;
  931. clines = i = pli->li_linedef.ld_cline;
  932. plru = plrudst = pli->li_plru;
  933. if (fDebug > 1) {
  934. printf("\n");
  935. }
  936. switch (pli->li_linedef.ld_itype) {
  937. case 1:
  938. while (i-- > 0) {
  939. if (ulnext <= plru->lr1.lr1_codeoffset) {
  940. if (fDebug > 1) {
  941. printf("delete1: %04lx %03d\n",
  942. plru->lr1.lr1_codeoffset,
  943. plru->lr1.lr1_linenumber);
  944. }
  945. if (ulmindel > plru->lr1.lr1_codeoffset) {
  946. ulmindel = plru->lr1.lr1_codeoffset;
  947. }
  948. if (ulmaxdel < plru->lr1.lr1_codeoffset) {
  949. ulmaxdel = plru->lr1.lr1_codeoffset;
  950. }
  951. clines--;
  952. } else {
  953. if (fDebug > 1) {
  954. printf("keep1: %04lx %03d\n",
  955. plru->lr1.lr1_codeoffset,
  956. plru->lr1.lr1_linenumber);
  957. }
  958. if (ulmax < plru->lr1.lr1_codeoffset) {
  959. ulmax = plru->lr1.lr1_codeoffset;
  960. }
  961. plrudst->lr1.lr1_codeoffset = plru->lr1.lr1_codeoffset;
  962. plrudst->lr1.lr1_linenumber = plru->lr1.lr1_linenumber;
  963. (unsigned char *) plrudst += sizeof(struct linerec1_s);
  964. }
  965. (unsigned char *) plru += sizeof(struct linerec1_s);
  966. }
  967. break;
  968. case 2:
  969. while (i-- > 0) {
  970. if (ulnext <= plru->lr2.lr2_codeoffset) {
  971. if (fDebug > 1) {
  972. printf("delete2: %04x %03d\n",
  973. plru->lr2.lr2_codeoffset,
  974. plru->lr2.lr2_linenumber);
  975. }
  976. if (ulmindel > plru->lr2.lr2_codeoffset) {
  977. ulmindel = plru->lr2.lr2_codeoffset;
  978. }
  979. if (ulmaxdel < plru->lr2.lr2_codeoffset) {
  980. ulmaxdel = plru->lr2.lr2_codeoffset;
  981. }
  982. clines--;
  983. } else {
  984. if (fDebug > 1) {
  985. printf("keep2: %04x %03d\n",
  986. plru->lr2.lr2_codeoffset,
  987. plru->lr2.lr2_linenumber);
  988. }
  989. if (ulmax < plru->lr2.lr2_codeoffset) {
  990. ulmax = plru->lr2.lr2_codeoffset;
  991. }
  992. plrudst->lr2.lr2_codeoffset = plru->lr2.lr2_codeoffset;
  993. plrudst->lr2.lr2_linenumber = plru->lr2.lr2_linenumber;
  994. (unsigned char *) plrudst += sizeof(struct linerec2_s);
  995. }
  996. (unsigned char *) plru += sizeof(struct linerec2_s);
  997. }
  998. break;
  999. default:
  1000. error("bad line record type");
  1001. xexit(1);
  1002. }
  1003. pli->li_linedef.ld_cline = (unsigned short) clines;
  1004. pli->li_offmax = ulmax;
  1005. if (fDebug) {
  1006. printf(" ==> (%lx - %lx)", ulmindel, ulmaxdel);
  1007. }
  1008. if (ulmind > ulmindel) {
  1009. ulmind = ulmindel;
  1010. }
  1011. if (ulmaxd < ulmaxdel) {
  1012. ulmaxd = ulmaxdel;
  1013. }
  1014. }
  1015. void
  1016. BuildStaticSyms(void)
  1017. {
  1018. int i;
  1019. struct seg_s *pse;
  1020. /* search for publics or entry point */
  1021. for (;;) {
  1022. if (strstr(Buf, achStatic)) {
  1023. ReadMapLine();
  1024. break;
  1025. } else if (strstr(Buf, achFixups)) {
  1026. return; // no static symbols
  1027. } else {
  1028. ReadMapLine();
  1029. }
  1030. }
  1031. do {
  1032. if (Buf[0] == '\0') {
  1033. fgetl(Buf, MAPBUFLEN, mapfh);
  1034. }
  1035. if (strstr(Buf, achFixups) || strstr(Buf, achLineNos)) {
  1036. break;
  1037. }
  1038. if (Buf[0] != ' ') {
  1039. errorline("unexpected input ignored");
  1040. break;
  1041. }
  1042. if (*pBufSymType == ' ' || *pBufSymType == 'R') {
  1043. if ( !HexTouVal( &Buf[ IB_SEG])) {
  1044. errorline("invalid segment");
  1045. xexit(4);
  1046. }
  1047. pse = NULL;
  1048. for (i = 0; i < cSeg; i++) {
  1049. if (SegTab[i]->se_segdef.gd_lsa == uVal) {
  1050. pse = SegTab[i];
  1051. break;
  1052. }
  1053. }
  1054. if (i >= cSeg) {
  1055. /*
  1056. * For some reason, a new C compiler puts information about
  1057. * imported modules in the symbol section of the map file.
  1058. * He puts those in segment "0", so ignore any lines that
  1059. * say they are for segment 0.
  1060. */
  1061. if (uVal == 0) {
  1062. continue; /* this will execute the "while" condition */
  1063. }
  1064. errorline("BuildSymDef: segment table search failed");
  1065. xexit(4);
  1066. }
  1067. if (HexToulVal(&Buf[IB_SYMOFF]) != cbMapOffset) {
  1068. errorline("invalid offset");
  1069. xexit(4);
  1070. }
  1071. AddSymDef(pse, pBufSymName, TRUE);
  1072. }
  1073. } while (fgetl(Buf, MAPBUFLEN, mapfh));
  1074. }
  1075. void
  1076. BuildSymDef(void)
  1077. {
  1078. int i;
  1079. struct seg_s *pse;
  1080. /* search for publics or entry point */
  1081. for (;;) {
  1082. if (strstr(Buf, achPublics)) {
  1083. ReadMapLine();
  1084. break;
  1085. } else if (strstr(Buf, achEntry)) {
  1086. error("no public symbols. - Re-link file with /map switch!");
  1087. xexit(4);
  1088. } else {
  1089. ReadMapLine();
  1090. }
  1091. }
  1092. do {
  1093. if (Buf[0] == '\0') {
  1094. fgetl(Buf, MAPBUFLEN, mapfh);
  1095. }
  1096. if (strstr(Buf, achEntry) || strstr(Buf, achLineNos)) {
  1097. break;
  1098. }
  1099. if (Buf[0] != ' ') {
  1100. errorline("unexpected input ignored");
  1101. break;
  1102. }
  1103. if (*pBufSymType == ' ' || *pBufSymType == 'R') {
  1104. if (!HexTouVal(&Buf[IB_SEG])) {
  1105. errorline("invalid segment");
  1106. xexit(4);
  1107. }
  1108. pse = NULL;
  1109. for (i = 0; i < cSeg; i++) {
  1110. if (SegTab[i]->se_segdef.gd_lsa == uVal) {
  1111. pse = SegTab[i];
  1112. break;
  1113. }
  1114. }
  1115. if (i >= cSeg) {
  1116. /*
  1117. * For some reason, a new C compiler puts information about
  1118. * imported modules in the symbol section of the map file.
  1119. * He puts those in segment "0", so ignore any lines that
  1120. * say they are for segment 0.
  1121. */
  1122. if (uVal == 0) {
  1123. continue; /* this will execute the "while" condition */
  1124. }
  1125. errorline("BuildSymDef: segment table search failed");
  1126. xexit(4);
  1127. }
  1128. if (HexToulVal(&Buf[IB_SYMOFF]) != cbMapOffset) {
  1129. errorline("invalid offset");
  1130. xexit(4);
  1131. }
  1132. AddSymDef(pse, pBufSymName, FALSE);
  1133. } else if (*pBufSymType != 'I') { /* else if not an import */
  1134. if (HexToulVal(&Buf[IB_SYMOFF]) != cbMapOffset) {
  1135. errorline("invalid offset");
  1136. xexit(4);
  1137. }
  1138. AddAbsDef(pBufSymName);
  1139. }
  1140. } while (fgetl(Buf, MAPBUFLEN, mapfh));
  1141. }
  1142. void
  1143. AddSegDef(
  1144. unsigned segno,
  1145. unsigned long segsize,
  1146. char *segname
  1147. )
  1148. {
  1149. unsigned cbname;
  1150. unsigned cballoc;
  1151. struct seg_s *pse;
  1152. cbname = NameLen(segname);
  1153. /*
  1154. * We allocate at least MAXNAMELEN so group name replacement
  1155. * won't step on whoever is next in the heap.
  1156. */
  1157. cballoc = MAXNAMELEN;
  1158. if (cbname > MAXNAMELEN) {
  1159. cballoc = cbname;
  1160. }
  1161. pse = (struct seg_s *) Zalloc(sizeof(struct seg_s) + cballoc);
  1162. pse->se_cbseg = segsize;
  1163. pse->se_segdef.gd_lsa = (unsigned short) segno;
  1164. pse->se_segdef.gd_curin = 0xff;
  1165. pse->se_segdef.gd_type = fAlpha;
  1166. pse->se_segdef.gd_cbname = (char) cbname;
  1167. strcpy((char *) pse->se_segdef.gd_achname, segname);
  1168. if (cSeg >= MAXSEG) {
  1169. errorline("segment table limit (%u) exceeded", MAXSEG);
  1170. xexit(4);
  1171. }
  1172. SegTab[cSeg++] = pse;
  1173. }
  1174. void
  1175. RedefineSegDefName(
  1176. unsigned segno,
  1177. char *segname
  1178. )
  1179. {
  1180. register unsigned cbname;
  1181. cbname = NameLen(segname);
  1182. segname[cbname] = '\0'; // make sure it's null terminated
  1183. if (fList) {
  1184. printf("%s (segment/group) redefines %s (segment)\n", segname,
  1185. SegTab[segno]->se_segdef.gd_achname);
  1186. }
  1187. if (cbname > MAXNAMELEN && cbname > SegTab[segno]->se_segdef.gd_cbname) {
  1188. errorline("segment/group name too long: %s", segname);
  1189. xexit(4);
  1190. }
  1191. SegTab[segno]->se_segdef.gd_cbname = (char) cbname;
  1192. strcpy((char *) SegTab[segno]->se_segdef.gd_achname, segname);
  1193. }
  1194. void
  1195. AddAbsDef(
  1196. char *symname
  1197. )
  1198. {
  1199. unsigned cbname;
  1200. struct sym_s *psy;
  1201. cbname = NameLen(symname);
  1202. if (pMap->mp_mapdef.md_cbnamemax < (char) cbname) {
  1203. pMap->mp_mapdef.md_cbnamemax = (char) cbname;
  1204. }
  1205. psy = (struct sym_s *) Zalloc(sizeof(struct sym_s) + cbname);
  1206. psy->sy_symdef.sd_lval = ulVal;
  1207. psy->sy_symdef.sd_cbname = (char) cbname;
  1208. strcpy((char *) psy->sy_symdef.sd_achname, symname);
  1209. if (pAbs == NULL) {
  1210. pAbs = psy;
  1211. } else {
  1212. pAbsLast->sy_psynext = psy;
  1213. }
  1214. pAbsLast = psy;
  1215. if (cbname > 8) {
  1216. pMap->mp_cbsymlong += cbname + 1;
  1217. }
  1218. pMap->mp_mapdef.md_cabs++;
  1219. pMap->mp_cbsyms += (unsigned short) cbname;
  1220. if (pMap->mp_mapdef.md_abstype & MSF_32BITSYMS) {
  1221. pMap->mp_cbsyms += CBSYMDEF;
  1222. } else {
  1223. pMap->mp_cbsyms += CBSYMDEF16;
  1224. if ((unsigned long) (unsigned short) ulVal != ulVal) {
  1225. pMap->mp_mapdef.md_abstype |= MSF_32BITSYMS;
  1226. // correct the size of the abs symdefs
  1227. pMap->mp_cbsyms += ((CBSYMDEF-CBSYMDEF16) * pMap->mp_mapdef.md_cabs);
  1228. }
  1229. }
  1230. if (pMap->mp_cbsyms + (pMap->mp_mapdef.md_cabs * cbOffsets) >= _64K) {
  1231. error("absolute symbols too large");
  1232. xexit(4);
  1233. }
  1234. }
  1235. void
  1236. AddSymDef(
  1237. struct seg_s *pse,
  1238. char *symname,
  1239. int fSort
  1240. )
  1241. {
  1242. unsigned cbname;
  1243. struct sym_s *psy;
  1244. struct sym_s* psyT;
  1245. struct sym_s* psyPrev;
  1246. int cbsegdef;
  1247. cbname = NameLen(symname);
  1248. if (pMap->mp_mapdef.md_cbnamemax < (char) cbname) {
  1249. pMap->mp_mapdef.md_cbnamemax = (char) cbname;
  1250. }
  1251. psy = (struct sym_s *) Zalloc(sizeof(struct sym_s) + cbname);
  1252. psy->sy_symdef.sd_lval = ulVal;
  1253. psy->sy_symdef.sd_cbname = (char) cbname;
  1254. strcpy((char *) psy->sy_symdef.sd_achname, symname);
  1255. if (fSort) {
  1256. /* Find the symbol just greater (or equal) to this new one */
  1257. psyPrev = NULL;
  1258. for (psyT = pse->se_psy ; psyT ; psyT = psyT->sy_psynext) {
  1259. if (ulVal <= psyT->sy_symdef.sd_lval) {
  1260. break;
  1261. }
  1262. psyPrev = psyT;
  1263. }
  1264. // Now that we've found this spot, link it in. If the previous item
  1265. // is NULL, we're linking it at the start of the list. If the current
  1266. // item is NULL, this is the end of the list.
  1267. if (!psyPrev) {
  1268. psy->sy_psynext = pse->se_psy;
  1269. pse->se_psy = psy;
  1270. } else {
  1271. psy->sy_psynext = psyT;
  1272. psyPrev->sy_psynext = psy;
  1273. }
  1274. if (!psyT) {
  1275. pse->se_psylast = psy;
  1276. }
  1277. } else {
  1278. /* insert at end of symbol chain */
  1279. if (pse->se_psy == NULL) {
  1280. pse->se_psy = psy;
  1281. } else {
  1282. pse->se_psylast->sy_psynext = psy;
  1283. }
  1284. pse->se_psylast = psy;
  1285. }
  1286. if (cbname > 8) {
  1287. pse->se_cbsymlong += cbname + 1;
  1288. }
  1289. pse->se_segdef.gd_csym++;
  1290. pse->se_cbsyms += cbname;
  1291. if (pse->se_segdef.gd_type & MSF_32BITSYMS) {
  1292. pse->se_cbsyms += CBSYMDEF;
  1293. } else {
  1294. pse->se_cbsyms += CBSYMDEF16;
  1295. if ((unsigned long) (unsigned short) ulVal != ulVal) {
  1296. pse->se_segdef.gd_type |= MSF_32BITSYMS;
  1297. // correct the size of the symdefs
  1298. pse->se_cbsyms += (CBSYMDEF - CBSYMDEF16) * pse->se_segdef.gd_csym;
  1299. }
  1300. }
  1301. cbsegdef = CBSEGDEF + pse->se_segdef.gd_cbname;
  1302. if (cbsegdef + pse->se_cbsyms >= _64K) {
  1303. pse->se_segdef.gd_type |= MSF_BIGSYMDEF;
  1304. }
  1305. }
  1306. void
  1307. WriteSym(void)
  1308. {
  1309. int i;
  1310. while (!WriteMapRec()) {
  1311. if ((pMap->mp_mapdef.md_abstype & MSF_ALIGN_MASK) == MSF_ALIGN_MASK) {
  1312. error("map file too large\n");
  1313. xexit(4);
  1314. }
  1315. pMap->mp_mapdef.md_abstype += MSF_ALIGN32;
  1316. alignment *= 2;
  1317. if (fList) {
  1318. printf("Using alignment: %d\n", alignment);
  1319. }
  1320. }
  1321. for (i = 0; i < cSeg; i++) {
  1322. if (SegTab[i]->se_psy) {
  1323. WriteSegRec(i);
  1324. WriteLineRec(i);
  1325. }
  1326. }
  1327. WriteOutFile(pMapEnd, sizeof(*pMapEnd)); /* terminate MAPDEF chain */
  1328. }
  1329. int
  1330. WriteMapRec(void)
  1331. {
  1332. int i;
  1333. int cbmapdef;
  1334. long lcbTotal;
  1335. long lcbOff;
  1336. register struct line_s *pli;
  1337. struct seg_s *pse;
  1338. cbSymFile = 0;
  1339. pMap->mp_mapdef.md_cseg = 0;
  1340. cbmapdef = CBMAPDEF + pMap->mp_mapdef.md_cbname;
  1341. pMap->mp_mapdef.md_pabsoff = cbmapdef + pMap->mp_cbsyms;
  1342. lcbTotal = align(cbmapdef + pMap->mp_cbsyms +
  1343. (pMap->mp_mapdef.md_cabs * cbOffsets));
  1344. // make sure the map file isn't too large
  1345. if (lcbTotal >= (_64K * alignment)) {
  1346. return(FALSE);
  1347. }
  1348. pMap->mp_mapdef.md_spseg = (unsigned short)(lcbTotal / alignment);
  1349. for (i = 0; i < cSeg; i++) {
  1350. if ((pse = SegTab[i])->se_psy) {
  1351. // calculate the symdef offset array size
  1352. if (pse->se_segdef.gd_type & MSF_BIGSYMDEF) {
  1353. lcbOff = align(pse->se_segdef.gd_csym *
  1354. (cbOffsets + CBOFFSET_BIG - CBOFFSET));
  1355. } else {
  1356. lcbOff = pse->se_segdef.gd_csym * cbOffsets;
  1357. }
  1358. // calculate the size of the linedefs and linerecs
  1359. pli = pse->se_pli;
  1360. pse->se_cblines = 0;
  1361. while (pli) {
  1362. pse->se_cblines += align(pli->li_cblines);
  1363. pli = pli->li_plinext;
  1364. }
  1365. lcbTotal += align(pse->se_cbsyms + pse->se_cblines +
  1366. lcbOff + CBSEGDEF + pse->se_segdef.gd_cbname);
  1367. // make sure the map file isn't too large
  1368. if (align(lcbTotal) >= (_64K * alignment)) {
  1369. return(FALSE);
  1370. }
  1371. // One more segment in map file
  1372. pMap->mp_mapdef.md_cseg++;
  1373. // Save away the last segment number
  1374. iSegLast = i;
  1375. }
  1376. }
  1377. // make sure the map file isn't too large
  1378. if (align(lcbTotal) >= (_64K * alignment)) {
  1379. return(FALSE);
  1380. }
  1381. pMap->mp_mapdef.md_spmap = (unsigned short)(align(lcbTotal) / alignment);
  1382. WriteOutFile(&pMap->mp_mapdef, cbmapdef);
  1383. if (fList) {
  1384. printf("%s - %d segment%s\n",
  1385. pMap->mp_mapdef.md_achname,
  1386. pMap->mp_mapdef.md_cseg,
  1387. (pMap->mp_mapdef.md_cseg == 1)? "" : "s");
  1388. }
  1389. // output abs symbols and values, followed by their offsets
  1390. WriteSyms(pAbs,
  1391. pMap->mp_mapdef.md_cabs,
  1392. pMap->mp_mapdef.md_abstype,
  1393. 0,
  1394. "<Constants>");
  1395. // return that everything is ok
  1396. return(TRUE);
  1397. }
  1398. void
  1399. WriteSyms(
  1400. struct sym_s *psylist,
  1401. unsigned csym,
  1402. unsigned char symtype,
  1403. unsigned long symbase,
  1404. char *segname
  1405. )
  1406. {
  1407. register unsigned cb;
  1408. struct sym_s *psy;
  1409. unsigned short svalue;
  1410. for (psy = psylist; psy; psy = psy->sy_psynext) {
  1411. cb = CBSYMDEF + psy->sy_symdef.sd_cbname;
  1412. if ((symtype & MSF_32BITSYMS) == 0) {
  1413. cb -= CBSYMDEF - CBSYMDEF16;
  1414. svalue = (unsigned short) psy->sy_symdef.sd_lval;
  1415. WriteOutFile(&svalue, sizeof(svalue));
  1416. WriteOutFile(&psy->sy_symdef.sd_cbname, cb - CBSYMDEF16 + 1);
  1417. } else {
  1418. WriteOutFile(&psy->sy_symdef.sd_lval, cb);
  1419. }
  1420. /* save offset to symbol */
  1421. psy->sy_symdef.sd_lval = (cbSymFile - cb) - symbase;
  1422. if ((int)psy->sy_symdef.sd_lval >=
  1423. (symtype & MSF_BIGSYMDEF ? _16MEG : _64K)) {
  1424. error("symbol offset array entry too large");
  1425. xexit(4);
  1426. }
  1427. }
  1428. /* if big group, align end of symbols on segment boundary */
  1429. if (symtype & MSF_BIGSYMDEF) {
  1430. WriteOutFile(achZeroFill, rem_align(cbSymFile));
  1431. cb = CBOFFSET_BIG;
  1432. } else {
  1433. cb = CBOFFSET;
  1434. }
  1435. /* write out the symbol offsets, after the symbols */
  1436. for (psy = psylist; psy; psy = psy->sy_psynext) {
  1437. WriteOutFile(&psy->sy_symdef.sd_lval, cb);
  1438. }
  1439. /* sort alphabetically, and write out the sorted symbol offsets */
  1440. if (fAlpha) {
  1441. psylist = sysort(psylist,csym);
  1442. for (psy = psylist; psy; psy = psy->sy_psynext) {
  1443. WriteOutFile(&psy->sy_symdef.sd_lval, cb);
  1444. }
  1445. }
  1446. if (fList && csym) {
  1447. printf("%-16s %4d %d-bit %ssymbol%s\n",
  1448. segname,
  1449. csym,
  1450. (symtype & MSF_32BITSYMS)? 32 : 16,
  1451. (symtype & MSF_BIGSYMDEF)? "big " : "",
  1452. (csym == 1)? "" : "s");
  1453. }
  1454. /* align end of symbol offsets */
  1455. WriteOutFile(achZeroFill, rem_align(cbSymFile));
  1456. }
  1457. /*
  1458. * Merge two symbol lists that are sorted alphabetically.
  1459. */
  1460. struct sym_s*
  1461. symerge(
  1462. struct sym_s *psy1, /* First list */
  1463. struct sym_s *psy2 /* Second list */
  1464. ) {
  1465. struct sym_s **ppsytail; /* Pointer to tail link */
  1466. struct sym_s *psy;
  1467. struct sym_s *psyhead; /* Pointer to head of result */
  1468. psyhead = NULL; /* List is empty */
  1469. ppsytail = &psyhead; /* Tail link starts at head */
  1470. while (psy1 != NULL && psy2 != NULL) {
  1471. /* While both lists are not empty */
  1472. ulCost++;
  1473. /*
  1474. * Select the lesser of the two head records
  1475. * and remove it from its list.
  1476. */
  1477. if (_stricmp((char *) psy1->sy_symdef.sd_achname,
  1478. (char *) psy2->sy_symdef.sd_achname) <= 0) {
  1479. psy = psy1;
  1480. psy1 = psy1->sy_psynext;
  1481. } else {
  1482. psy = psy2;
  1483. psy2 = psy2->sy_psynext;
  1484. }
  1485. *ppsytail = psy; /* Insert at tail of new list */
  1486. ppsytail = &psy->sy_psynext; /* Update tail link */
  1487. }
  1488. *ppsytail = psy1; /* Attach rest of 1st list to tail */
  1489. if (psy1 == NULL)
  1490. *ppsytail = psy2; /* Attach rest of 2nd if 1st empty */
  1491. return(psyhead); /* Return pointer to merged list */
  1492. }
  1493. /*
  1494. * Find as many records at the head of the list as
  1495. * are already in sorted order.
  1496. */
  1497. struct sym_s*
  1498. sysorted(
  1499. struct sym_s **ppsyhead /* Pointer to head-of-list pointer */
  1500. ) {
  1501. struct sym_s *psy;
  1502. struct sym_s *psyhead; /* Head of list */
  1503. /*
  1504. * Find as many records at the head of the list as
  1505. * are already in sorted order.
  1506. */
  1507. for (psy = psyhead = *ppsyhead; psy->sy_psynext != NULL; psy = psy->sy_psynext) {
  1508. ulCost++;
  1509. if (_stricmp((char *) psy->sy_symdef.sd_achname,
  1510. (char *) psy->sy_psynext->sy_symdef.sd_achname) > 0)
  1511. break;
  1512. }
  1513. *ppsyhead = psy->sy_psynext; /* Set head to point to unsorted */
  1514. psy->sy_psynext = NULL; /* Break the link */
  1515. return(psyhead); /* Return head of sorted sublist */
  1516. }
  1517. /*
  1518. * Split a list in two after skipping the specified number
  1519. * of symbols.
  1520. */
  1521. struct sym_s *
  1522. sysplit(
  1523. struct sym_s *psyhead, /* Head of list */
  1524. unsigned csy /* # to skip before splitting (>=1) */
  1525. ) {
  1526. struct sym_s *psy;
  1527. struct sym_s *psyprev;
  1528. /*
  1529. * Skip the requested number of symbols.
  1530. */
  1531. for (psy = psyhead; csy-- != 0; psy = psy->sy_psynext) {
  1532. psyprev = psy;
  1533. }
  1534. psyprev->sy_psynext = NULL; /* Break the list */
  1535. return(psy); /* Return pointer to second half */
  1536. }
  1537. /*
  1538. * Sort a symbol list of the specified length alphabetically.
  1539. */
  1540. struct sym_s*
  1541. sysort(
  1542. struct sym_s *psylist, /* List to sort */
  1543. unsigned csy /* Length of list */
  1544. ) {
  1545. struct sym_s *psy;
  1546. struct sym_s *psyalpha; /* Sorted list */
  1547. if (csy >= 32) { /* If list smaller than 32 */
  1548. psy = sysplit(psylist,csy >> 1);/* Split it in half */
  1549. return(symerge(sysort(psylist,csy >> 1),sysort(psy,csy - (csy >> 1))));
  1550. /* Sort halves and merge */
  1551. }
  1552. psyalpha = NULL; /* Sorted list is empty */
  1553. while (psylist != NULL) { /* While list is not empty */
  1554. psy = sysorted(&psylist); /* Get sorted head */
  1555. psyalpha = symerge(psyalpha,psy);
  1556. /* Merge with sorted list */
  1557. }
  1558. return(psyalpha); /* Return the sorted list */
  1559. }
  1560. void
  1561. WriteSegRec(
  1562. int i
  1563. )
  1564. {
  1565. int cbsegdef;
  1566. int cboff;
  1567. unsigned long segdefbase, ulsymoff, uloff;
  1568. struct seg_s *pse = SegTab[i];
  1569. /* compute length of symbols and segment record */
  1570. cbsegdef = CBSEGDEF + pse->se_segdef.gd_cbname;
  1571. /* set the offset array size */
  1572. cboff = pse->se_segdef.gd_csym * cbOffsets;
  1573. /* set segdef-relative pointer to array of symbol offsets */
  1574. ulsymoff = uloff = cbsegdef + pse->se_cbsyms;
  1575. if (pse->se_segdef.gd_type & MSF_BIGSYMDEF) {
  1576. /* alignment symdef offset pointer */
  1577. ulsymoff = align(ulsymoff);
  1578. uloff = ulsymoff / alignment;
  1579. /* set the array offset size to the big group size */
  1580. cboff = pse->se_segdef.gd_csym * (cbOffsets + CBOFFSET_BIG - CBOFFSET);
  1581. }
  1582. if (uloff >= _64K) {
  1583. error("segdef's array offset too large: %08lx", uloff);
  1584. xexit(4);
  1585. }
  1586. pse->se_segdef.gd_psymoff = (unsigned short)uloff;
  1587. /* set pointer to linedef_s(s) attached to this segment def */
  1588. if (pse->se_pli) {
  1589. uloff = align(cbSymFile + ulsymoff + cboff) / alignment;
  1590. if (uloff >= _64K) {
  1591. error("segdef's linedef pointer too large: %08lx\n", uloff);
  1592. xexit(4);
  1593. }
  1594. pse->se_segdef.gd_spline = (unsigned short)uloff;
  1595. }
  1596. /* set relative address for symbol offset calculations */
  1597. segdefbase = cbSymFile;
  1598. /* set pointer to next segdef */
  1599. uloff = align(cbSymFile + ulsymoff + cboff + pse->se_cblines) / alignment;
  1600. if (i == iSegLast) {
  1601. pse->se_segdef.gd_spsegnext = 0;
  1602. } else {
  1603. if (uloff >= _64K) {
  1604. error("segdef next pointer too large: %08lx", uloff);
  1605. xexit(4);
  1606. }
  1607. pse->se_segdef.gd_spsegnext = (unsigned short)uloff;
  1608. }
  1609. WriteOutFile(&pse->se_segdef, cbsegdef);
  1610. /* output symbols and values, followed by their offsets */
  1611. WriteSyms(pse->se_psy,
  1612. pse->se_segdef.gd_csym,
  1613. pse->se_segdef.gd_type,
  1614. segdefbase,
  1615. (char *) pse->se_segdef.gd_achname);
  1616. }
  1617. void
  1618. WriteLineRec(
  1619. int i
  1620. )
  1621. {
  1622. register struct line_s *pli = SegTab[i]->se_pli;
  1623. register unsigned cb;
  1624. unsigned short cblr;
  1625. while (pli) {
  1626. cb = sizeof(struct linedef_s) + pli->li_linedef.ld_cbname;
  1627. pli->li_linedef.ld_plinerec = (unsigned short)cb;
  1628. /* compute length of line numbers */
  1629. switch (pli->li_linedef.ld_itype) {
  1630. case 0:
  1631. cblr = pli->li_linedef.ld_cline * sizeof(struct linerec0_s);
  1632. break;
  1633. case 1:
  1634. cblr = pli->li_linedef.ld_cline * sizeof(struct linerec1_s);
  1635. break;
  1636. case 2:
  1637. cblr = pli->li_linedef.ld_cline * sizeof(struct linerec2_s);
  1638. break;
  1639. }
  1640. if (pli->li_plinext) {
  1641. pli->li_linedef.ld_splinenext =
  1642. (unsigned short)(align(cbSymFile + pli->li_cblines) / alignment);
  1643. }
  1644. /* write out linedef_s */
  1645. WriteOutFile(&pli->li_linedef, cb);
  1646. /* write out line number offsets */
  1647. WriteOutFile(pli->li_plru, cblr);
  1648. /* align end of linerecs */
  1649. WriteOutFile(achZeroFill, rem_align(cbSymFile));
  1650. pli = pli->li_plinext;
  1651. }
  1652. }
  1653. void
  1654. ReadMapLine(void)
  1655. {
  1656. do {
  1657. if (!fgetl(Buf, MAPBUFLEN, mapfh)) {
  1658. errorline("Unexpected eof");
  1659. xexit(4);
  1660. }
  1661. } while (Buf[0] == '\0');
  1662. }
  1663. void
  1664. WriteOutFile(src, len)
  1665. char *src;
  1666. int len;
  1667. {
  1668. if (len && fwrite(src, len, 1, outfh) != 1) {
  1669. error("write fail on: %s", pszOutfn);
  1670. xexit(1);
  1671. }
  1672. cbSymFile += len;
  1673. }
  1674. /*
  1675. * fgetl - return a line from file (no CRLFs); returns 0 if EOF
  1676. */
  1677. int
  1678. fgetl(
  1679. char *pbuf,
  1680. int len,
  1681. FILE *fh
  1682. )
  1683. {
  1684. int c;
  1685. char *p;
  1686. p = pbuf;
  1687. len--; /* leave room for nul terminator */
  1688. while (len > 0 && (c = getc(fh)) != EOF && c != '\n') {
  1689. if (c != '\r') {
  1690. *p++ = (char) c;
  1691. len--;
  1692. }
  1693. }
  1694. if (c == '\n') {
  1695. cLine++;
  1696. }
  1697. *p = '\0';
  1698. return(c != EOF || p != pbuf);
  1699. }
  1700. int
  1701. NameLen(
  1702. char* p
  1703. )
  1704. {
  1705. char* p1;
  1706. char* plimit;
  1707. int len;
  1708. p1 = p;
  1709. plimit = p + MAXSYMNAMELEN;
  1710. while (*p) {
  1711. if (*p == ' ' || *p == LPAREN || *p == RPAREN || p == plimit) {
  1712. *p = '\0';
  1713. break;
  1714. }
  1715. if ( fEdit && strchr( "@?", *p)) {
  1716. *p = '_';
  1717. }
  1718. p++;
  1719. }
  1720. return (int)(p - p1);
  1721. }
  1722. int
  1723. NameSqueeze(
  1724. char* ps
  1725. )
  1726. {
  1727. char* pd;
  1728. char* porg;
  1729. char* plimit;
  1730. NameLen(ps);
  1731. porg = pd = ps;
  1732. plimit = porg + MAXLINERECNAMELEN;
  1733. while (pd < plimit && *ps) {
  1734. switch (*pd++ = *ps++) {
  1735. case '/':
  1736. pd[-1] = '\\';
  1737. // FALLTHROUGH
  1738. // remove \\ in middle of path, & .\ at start or middle of path
  1739. case '\\':
  1740. if (pd > &porg[2] && pd[-2] == '\\') {
  1741. pd--;
  1742. } else if (pd > &porg[1] && pd[-2] == '.' &&
  1743. (pd == &porg[2] || pd[-3] == '\\')) {
  1744. pd -= 2;
  1745. }
  1746. break;
  1747. }
  1748. }
  1749. *pd = '\0';
  1750. return (int)(pd - porg);
  1751. }
  1752. int
  1753. HexTouVal(
  1754. char* p
  1755. )
  1756. {
  1757. int i;
  1758. for (uVal = 0, i = 0; i < 4; i++) {
  1759. if (!isxdigit(*p)) {
  1760. break;
  1761. }
  1762. if (*p <= '9') {
  1763. uVal = 0x10 * uVal + *p++ - '0';
  1764. } else {
  1765. uVal = 0x10 * uVal + (*p++ & 0xf) + 9;
  1766. }
  1767. }
  1768. return(i > 3);
  1769. }
  1770. int
  1771. HexToulVal(
  1772. char* p
  1773. )
  1774. {
  1775. int i;
  1776. for (ulVal = 0, i = 0; i < 8; i++) {
  1777. if (!isxdigit(*p)) {
  1778. break;
  1779. }
  1780. if (isdigit(*p)) {
  1781. ulVal = 0x10 * ulVal + *p++ - '0';
  1782. } else {
  1783. ulVal = 0x10 * ulVal + (*p++ & 0xf) + 9;
  1784. }
  1785. }
  1786. return(i);
  1787. }
  1788. int
  1789. CharToHex(
  1790. int c
  1791. )
  1792. {
  1793. if (!isxdigit(c)) {
  1794. errorline("Bad hex digit (0x%02x)", c);
  1795. xexit(1);
  1796. }
  1797. if ((c -= '0') > 9) {
  1798. if ((c += '0' - 'A' + 10) > 0xf) {
  1799. c += 'A' - 'a';
  1800. }
  1801. }
  1802. return(c);
  1803. }
  1804. int
  1805. rem_align(
  1806. unsigned long foo
  1807. )
  1808. {
  1809. return((int) ((alignment - (foo % alignment)) % alignment));
  1810. }
  1811. int
  1812. align(
  1813. int foo
  1814. )
  1815. {
  1816. int bar;
  1817. bar = foo % alignment;
  1818. if (bar == 0) {
  1819. return(foo);
  1820. }
  1821. return(foo + alignment - bar);
  1822. }
  1823. char *
  1824. Zalloc(
  1825. unsigned cb
  1826. )
  1827. {
  1828. char *p;
  1829. if ((p = malloc(cb)) == NULL) {
  1830. error("out of memory");
  1831. xexit(4);
  1832. }
  1833. memset(p, 0, cb);
  1834. return(p);
  1835. }
  1836. void
  1837. logo(void) /* sign on */
  1838. {
  1839. if (fLogo) {
  1840. fLogo = 0;
  1841. printf("Microsoft (R) Symbol File Generator Version %d.%02d\n",
  1842. MAPSYM_VERSION,
  1843. MAPSYM_RELEASE);
  1844. printf(VER_LEGALCOPYRIGHT_STR ". All rights reserved.\n");
  1845. }
  1846. }
  1847. void
  1848. usage(void)
  1849. {
  1850. logo();
  1851. fprintf(stderr, "\nusage: mapsym [-nologo] [-almnst] [[-c pefile] -o outfile] infile\n");
  1852. fprintf(stderr, " -a include alphabetic sort arrays\n");
  1853. fprintf(stderr, " -l list map file information\n");
  1854. fprintf(stderr, " -e edit symbols for NTSD parser\n");
  1855. fprintf(stderr, " -m use module name from infile\n");
  1856. fprintf(stderr, " -n omit line number information\n");
  1857. fprintf(stderr, " -nologo omit signon logo\n");
  1858. fprintf(stderr, " -o outfile symbol output file\n");
  1859. fprintf(stderr, " -s enable line number support [default]\n");
  1860. fprintf(stderr, " -t include static symbols\n");
  1861. fprintf(stderr, "infile is a map file \n");
  1862. fprintf(stderr, "outfile is a sym file.\n");
  1863. xexit(1);
  1864. }
  1865. /*VARARGS1*/
  1866. void
  1867. __cdecl
  1868. error(
  1869. char* fmt,
  1870. ...
  1871. )
  1872. {
  1873. va_list argptr;
  1874. va_start(argptr, fmt);
  1875. fprintf(stderr, "mapsym: ");
  1876. vfprintf(stderr, fmt, argptr);
  1877. fprintf(stderr, "\n");
  1878. }
  1879. /*VARARGS1*/
  1880. void
  1881. __cdecl
  1882. errorline(
  1883. char* fmt,
  1884. ...
  1885. )
  1886. {
  1887. va_list argptr;
  1888. va_start(argptr, fmt);
  1889. fprintf(stderr, "mapsym: ");
  1890. fprintf(stderr, "%s", pszMapfn);
  1891. if (cLine) {
  1892. fprintf(stderr, "(%u)", cLine + fByChar);
  1893. }
  1894. fprintf(stderr, ": ");
  1895. vfprintf(stderr, fmt, argptr);
  1896. fprintf(stderr, "\n");
  1897. }
  1898. void
  1899. xexit(
  1900. int rc
  1901. )
  1902. {
  1903. if (outfh) {
  1904. fclose(outfh);
  1905. _unlink(pszOutfn);
  1906. }
  1907. exit(rc);
  1908. }