home *** CD-ROM | disk | FTP | other *** search
/ World of Shareware - Software Farm 2 / wosw_2.zip / wosw_2 / CPROG / CGAZV5N3.ZIP / OX.C < prev    next >
C/C++ Source or Header  |  1991-02-25  |  57KB  |  1,525 lines

  1. /********  Listing 3  *************************  OX.C  ********
  2. *  ox.c -- Object Explorer,
  3. *  Author:   Thomas E. Siering, 1991. See Lisitng 1 for 
  4. *                      copyright notice.
  5. *  Compiler: Microsoft C 6.0, Turbo C++ 1.0
  6. *  Compile time switches: none
  7. *  Links with: svc.c and apps.c
  8. **************************************************************/
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <io.h>
  13. #include "ox.h"
  14.  
  15.  
  16. #define NEAR   0x62
  17. #define FAR    0x61
  18.  
  19. #define THREADMAX         4
  20. #define MAXLINELENGTH    16
  21.  
  22. extern FILE *AnalysisFH;
  23.  
  24. PRIVATE char *ObjBase;
  25. PRIVATE FILE *ObjFH;
  26. PRIVATE FIXUPTHREAD ThreadTable[THREADMAX * 2];  /* for Target AND Frame */
  27.  
  28.  
  29. PRIVATE LNODE ListLNAMES;
  30. PRIVATE LNODE ListSEGDEF;
  31. PRIVATE LNODE ListGRPDEF;
  32. PRIVATE LNODE ListEXTDEF;
  33.  
  34.  
  35. PRIVATE int GetExplicitFixupp(unsigned char *RecordP);
  36. PRIVATE int GetFixupThread(unsigned char *RecordP);
  37. PRIVATE LNODE *GetThreadFixupMethod(unsigned int method, unsigned int d,
  38.         char *RecordP);
  39. PRIVATE void GetFixupLocation(unsigned int loc, char *RecordP);
  40. PRIVATE int IteratedDataBlock(unsigned char *RecordP);
  41. PRIVATE void InstThreadTable(void);
  42. PRIVATE void PutThread(FIXUPTHREAD NewThread);
  43. PRIVATE FIXUPTHREAD *GetThread(unsigned char ThreadID, char ThreadType,
  44.         char *RecordP);
  45. PRIVATE int GetFixDatField(unsigned char *RecordP);
  46. PRIVATE char GetVarLengthIdx(char *RecordP, int *Index);
  47.  
  48.  
  49. /*------------------------------------------------------------
  50. *   InstObjExp  --  Instantiate the Object Explorer
  51. *-----------------------------------------------------------*/
  52. PUBLIC void InstObjExp(char ObjFN[], char **ws, long *ObjSize)
  53. {
  54.     if ((ObjFH = fopen(ObjFN, "rb")) == NULL) {
  55.         fprintf(stderr, "Could Not Open File %s\n", ObjFN);
  56.         exit(-1);
  57.     }
  58.  
  59.     if ((*ObjSize = filelength(fileno(ObjFH))) == -1) {
  60.         fprintf(stderr, "Error in File Size Determination\n");
  61.         exit(-1);
  62.     }
  63.  
  64.     if ((ObjBase = *ws = malloc((int) *ObjSize)) == NULL) {
  65.         fprintf(stderr, "Work Space Allocation Failed.  Aborting\n");
  66.         exit(-1);
  67.     }
  68.  
  69.     if (fread(*ws, sizeof(char), (int) *ObjSize, ObjFH) !=
  70.             (unsigned int) *ObjSize) {
  71.         fprintf(stderr, "Read of OBJ Failed.  Aborting\n");
  72.         exit(-1);
  73.     }
  74.     fclose(ObjFH);
  75.  
  76.     if ((char) **ws != (char) THEADR && (char) **ws != (char) LHEADR) {
  77.         fprintf(stderr, "Invalid OBJ file.  Aborting\n");
  78.         exit(-1);
  79.     }
  80.  
  81.     InstList(&ListLNAMES);    /* initialize symbol lists */
  82.     InstList(&ListSEGDEF);
  83.     InstList(&ListGRPDEF);
  84.     InstList(&ListEXTDEF);
  85.     InstThreadTable();
  86. }
  87.  
  88.  
  89. /*===============================================
  90. *  1. OMF comment records:
  91. *   THEADR      0x80
  92. *   COMENT      0x88
  93. *   MODEND      0x8A
  94. *===============================================*/
  95.  
  96. /*--------------------------------------------------------
  97. *  DoTHEADR --  Translator Header record (T-module)
  98. *  NOTE: MUST always appear as the first record in OBJ module
  99. *--------------------------------------------------------*/
  100. PUBLIC void DoTHEADR(unsigned char *RecordP)
  101. {
  102.     char *ModuleName;
  103.  
  104.     ModuleName = MakeASCIIZ(RecordP);
  105.  
  106.     Output(Message, AnalysisFH, "Module Name:\n     %s\n", ModuleName);
  107.     free(ModuleName);
  108. }
  109. /*--------------------------------------------------------
  110. *   DoCOMENT -- Comment record
  111. *   Within the given Comment Classes anything can be put here.             
  112. *   As a result, COMENT records are popular for OMF extensions.                                                                      
  113. *-------------------------------------------------------*/                
  114. PUBLIC void DoCOMENT(unsigned char *RecordP, int RecordLength)
  115. {
  116.     bool NoPurge, NoList;
  117.     unsigned char CommentClass;
  118.     char *Comment;
  119.     char Processor[6];
  120.     int PrintLength;
  121.     int Offset;
  122.  
  123.     NoPurge = *RecordP & (char) 0x80;
  124.     NoList =  *RecordP++ & (char) 0x40;
  125.     Output(Message, AnalysisFH, "     No Purge           :  %s\n",
  126.             NoPurge ? "ON" : "OFF");
  127.     Output(Message, AnalysisFH, "     No List            :  %s\n",
  128.             NoList ? "ON" : "OFF");
  129.     CommentClass = *RecordP++;
  130.     RecordLength -= 2;        /* past NoPurge/NoList and CommentClass */
  131.  
  132.     /* Note: This string is NOT preceded by "length" byte */
  133.     Comment = malloc(RecordLength + 1);
  134.     Comment[RecordLength] = '\0';
  135.     strncpy(Comment, RecordP, RecordLength);
  136.  
  137.     /* Comment Class */
  138.     Output(Message, AnalysisFH, "     Comment Class      :  %02X\n",
  139.             CommentClass & 0x00FF);
  140.  
  141.     switch(CommentClass) {
  142.         case 0x00 :
  143.             Output(Message, AnalysisFH,
  144.                     "     Language Translator:  %s\n", Comment);
  145.             break;
  146.         case 0x01 :
  147.             Output(Message, AnalysisFH,
  148.                     "     Copyright          :  %s\n", Comment);
  149.             break;
  150.         case 0x81 :      /* obsolete: 9F comment class should be used */
  151.             Output(Message, AnalysisFH,
  152.                     "     Library Specifier  :  %s\n", Comment);
  153.             break;
  154.         case 0x9C :
  155.             Output(Message, AnalysisFH,
  156.                     "     DOS Version        :  %d\n", *(int *) RecordP);
  157.             break;
  158.         case 0x9D :
  159.             if (Comment[0] == '0')
  160.                 strcpy(Processor, "8086");
  161.             else {
  162.                 strcpy(Processor, "80086");
  163.                 Processor[2] = Comment[0];
  164.             }
  165.             Output(Message, AnalysisFH, "     Target Processor   :  %s\n",
  166.                     Processor);
  167.             Output(Message, AnalysisFH, "     Memory Model       :  %c\n",
  168.                     Comment[1]);
  169.             break;
  170.         case 0x9E :             /* Sets LINK's DOSSEG */
  171.             Output(Message, AnalysisFH, "     Force Segment Order:  %s\n",
  172.                     Comment);
  173.             break;
  174.         case 0x9F :
  175.             Output(Message, AnalysisFH, "     Library Specifier  :  %s\n",
  176.                     Comment);
  177.             break;
  178.         case 0xA0 :             /* used for IMPDEF with Windows, OS/2 */
  179.             Output(Message, AnalysisFH, "     MS-Reserved Field  :  ");
  180.             switch (*RecordP) {
  181.                 case 1 :
  182.                     Output(Message, AnalysisFH, "IMPDEF\n");
  183.                     break;
  184.                 case 2:
  185.                     Output(Message, AnalysisFH, "EXPDEF\n");
  186.                     break;
  187.                 case 3:
  188.                     Output(Message, AnalysisFH, "INCDEF\n");
  189.                     break;
  190.                 case 4:
  191.                     Output(Message, AnalysisFH,
  192.                             "Protected Memory Lib. (386)\n");
  193.                     break;
  194.                 default:
  195.                     Output(Warning, AnalysisFH, "Unknown Comment Record\n");
  196.                     break;
  197.             }
  198.             break;
  199.         case 0xA1 :      /* meaning that obsolete TYPDEF/EXTDEF pairs */
  200.                          /* not used but COMDEF instead */
  201.             Output(Message, AnalysisFH, "     Microsoft Extension:  %s\n",
  202.                     Comment);
  203.             break;
  204.         case 0xA2 :
  205.             Output(Message, AnalysisFH, "     Start of Link Pass 2\n");
  206.             break;
  207.         case 0xA3 :
  208.             Output(Message, AnalysisFH, "     LIBMOD record\n");
  209.             break;
  210.         case 0xA4 :
  211.             Output(Message, AnalysisFH, "     EXESTR record\n");
  212.             break;
  213.         case 0xA5 :
  214.             Output(Message, AnalysisFH, "     QC # 1 record\n");
  215.             break;
  216.         case 0xA6 :
  217.             Output(Message, AnalysisFH, "     INCERR record\n");
  218.             break;
  219.         case 0xA7 :
  220.             Output(Message, AnalysisFH, "     NOPAD record\n");
  221.             break;
  222.         case 0xA8 :
  223.             Output(Message, AnalysisFH, "     WKEXT record\n");
  224.             break;
  225.         default:
  226.             if (CommentClass >= 0xC0)
  227.                 Output(Message, AnalysisFH, "     User-Defined Comm. :\n");
  228.             else
  229.              /* This is foul play, or some future non-compliant extension */
  230.                 Output(Message, AnalysisFH, "     Proprietary Comm.  :\n");
  231.  
  232.             /* Hex dump the comment (string printing it isn't safe!) */
  233.             Offset = GetRecordRelPos(RecordP);
  234.             while (RecordLength > 0) {
  235.                 PrintLength = (RecordLength > MAXLINELENGTH) ?
  236.                         MAXLINELENGTH : RecordLength;
  237.                 PrintObjDumpLine(RecordP, AnalysisFH, Offset, PrintLength);
  238.                 RecordLength -= PrintLength;
  239.                 Offset += PrintLength;
  240.                 RecordP    += PrintLength;
  241.             }
  242.             break;
  243.     }
  244.     free(Comment);
  245. }
  246.  
  247. /*--------------------------------------------------------------
  248. *  DoMODEND --  Module End record
  249. *  Indicates end of module, whether it's the main routine in a
  250. *  program, and, optionally, program entry point.
  251. *  NOTE: MUST always appear as the last record in OBJ module
  252. *-------------------------------------------------------------*/
  253. PUBLIC void DoMODEND(unsigned char *RecordP)
  254. {
  255.     bool IsMain;
  256.     bool HasEntryPoint;
  257.     bool IsRelocatableEP;
  258.  
  259.     /* The top two bytes are relevant:  byte 7 - is it main module, */
  260.     /*                        byte 6 - is starting address supplied */
  261.  
  262.     /* The following check will fail on Quick C generated OBJ modules.
  263.         This non-standard behavior is undocumented (but harmless).  */
  264.     #ifdef QUICKC_MYSTERY
  265.     if ((*RecordP & (char) 0x3E) != 0)
  266.         Output(Warning, AnalysisFH,
  267.                 "Unrecognizable Module End Attribute Record\n");
  268.     #endif
  269.  
  270.     IsMain = *RecordP & (char) 0x80;
  271.     HasEntryPoint = *RecordP & (char) 0x40;
  272.     IsRelocatableEP = *RecordP++ & (char) 0x01;
  273.  
  274.     Output(Message, AnalysisFH, "     %s / %s\n",
  275.             (IsMain) ? "Main module" : "Non-Main Module",
  276.             (HasEntryPoint) ? "Entry Point" : "No Entry Point");
  277.     if (HasEntryPoint)
  278.         Output(Message, AnalysisFH, "     %s\n",
  279.                 (IsRelocatableEP) ?
  280.                 "Relocatable Entry Point" : "Absolute Entry Point");
  281.  
  282.     if (HasEntryPoint)  /* Specified starting address */
  283.         GetFixDatField(RecordP);
  284. }
  285.  
  286. /*===============================================
  287. *  2. Symbol lists:
  288. *   LNAMES      0x96
  289. *   EXTDEF      0x8C
  290. *   PUBDEF      0x90
  291. *===============================================*/
  292.  
  293. /*-------------------------------------------------------------
  294. *   DoLNAMES -- Names List record
  295. *   List of names which will be referenced by subsequent SEGDEF
  296. *   and GRPDEF records in this module, using 1-based index.
  297. *   MS LINK limit is 255 logical names/module.
  298. *-------------------------------------------------------------*/
  299. PUBLIC void DoLNAMES(unsigned char *RecordP, int RecordLength)
  300. {
  301.     char *LName;
  302.  
  303.     while (RecordLength > 0) {
  304.         LName = MakeASCIIZ(RecordP);
  305.         Output(Message, AnalysisFH, "     %s\n",
  306.                 *RecordP != '\0' ? LName : "(NULLNAME)");
  307.  
  308.         ListLNAMES = AddListNode(ListLNAMES, LName);
  309.  
  310.         RecordLength -= ((int) *RecordP + 1);
  311.         RecordP += ((int) *RecordP + 1);
  312.     }
  313.  
  314.     if (RecordLength)
  315.         Output(Error, AnalysisFH,
  316.                 "LNAMES record not recognized.  Terminating\n");
  317. }
  318.  
  319.  
  320. /*---------------------------------------------------------------
  321. *   DoEXTDEF -- External Name Definitions record
  322. *   List of symbolic external references (symbols defined in other
  323. *   OBJ modules).  MS LINK limit is 1023 external names.
  324. *---------------------------------------------------------------*/
  325. PUBLIC void DoEXTDEF(unsigned char *RecordP, int RecordLength)
  326. {
  327.     char *ExtName;
  328.     int TypeIndex;
  329.     char IndexSize;
  330.  
  331.     while (RecordLength > 0) {
  332.         ExtName = MakeASCIIZ(RecordP);
  333.         ListEXTDEF = AddListNode(ListEXTDEF, ExtName); /*EXTDEF name list*/
  334.         Output(Message, AnalysisFH, "\n     External Symbol    :  %s \n",
  335.                 ExtName);
  336.         RecordLength -= ((int) *RecordP + 1);
  337.         RecordP += ((int) *RecordP + 1);
  338.  
  339.         /* Type index is reference to a TYPDEF record (if > 0)
  340.            EXTDEF/TYPDEF method is mostly obsolete, except for 
  341.            communal variables. It is replaced by COMDEF records. */
  342.  
  343.         IndexSize = GetVarLengthIdx(RecordP, &TypeIndex);
  344.         Output(Message, AnalysisFH, "     Type Index         :  %u\n",
  345.                 TypeIndex);
  346.         RecordLength -= IndexSize;
  347.         RecordP += IndexSize;
  348.     }
  349.     if (RecordLength)
  350.         Output(Error, AnalysisFH,
  351.                 "EXTDEF record not recognized.  Terminating\n");
  352. }
  353.  
  354. /*------------------------------------------------------------
  355. *   DoPUBDEF -- Public Name Definitions record
  356. *   This record contains the public names used to resolve the
  357. *   externals at link time.
  358. *-------------------------------------------------------------*/
  359. PUBLIC void DoPUBDEF(unsigned char *RecordP, int  RecordLength)
  360. {
  361.     char *PubName;
  362.     int  GroupIndex;
  363.     int  SegmentIndex;
  364.     LNODE *ListNodeP = NULL;
  365.     int TypeIndex;
  366.     char IndexSize;
  367.  
  368.     /* If a group is associated with this PUBDEF record, Group Index
  369.        indexes to the appropriate GRPDEF, otherwise it's 0 */
  370.     IndexSize = GetVarLengthIdx(RecordP, &GroupIndex);
  371.     RecordP += IndexSize;
  372.     RecordLength -= IndexSize;
  373.     if (GroupIndex != 0)
  374.         ListNodeP = GetListNode(ListLNAMES, GroupIndex);
  375.     Output(Message, AnalysisFH, "     Group   Name Index :  %u  --  %s\n",
  376.             GroupIndex, ListNodeP != NULL ? ListNodeP->InfoP : "NO GROUP");
  377.  
  378.     /* The Segment Index indexes to previous SEGDEF records to associate a
  379.        segment with this PUBDEF. If Segment Index = 0, Group Index = 0. */
  380.     ListNodeP = NULL;
  381.     IndexSize = GetVarLengthIdx(RecordP, &SegmentIndex);
  382.     RecordP += IndexSize;
  383.     RecordLength -= IndexSize;
  384.     if (SegmentIndex != 0)
  385.         ListNodeP = GetListNode(ListSEGDEF, SegmentIndex);
  386.     Output(Message, AnalysisFH, "     Segment Name Index :  %u  --  %s\n",
  387.         SegmentIndex, ListNodeP != NULL ? ListNodeP->InfoP : "NO SEGMENT");
  388.  
  389.     /* If both Group and Segment Index are 0, a Frame Number follows
  390.        which indexes the frame containing the Public symbols */
  391.     if (GroupIndex == 0 && SegmentIndex == 0) {
  392.         Output(Message, AnalysisFH, "     Frame Number = %Xx\n",
  393.                 *(int *) RecordP);
  394.         RecordP += 2;
  395.         RecordLength -= 2;
  396.     }
  397.  
  398.     while (RecordLength > 0) {
  399.         /* PUBLIC's name */
  400.         PubName = MakeASCIIZ(RecordP);
  401.         Output(Message, AnalysisFH, "\n     Public Name        :  %s \n",
  402.                 PubName);
  403.         free(PubName);
  404.         RecordLength -= ((int) *RecordP + 1);
  405.         RecordP += ((int) *RecordP + 1);
  406.  
  407.         /* PUBLIC's offset relative to segment, group, or frame (supra) */
  408.         Output(Message, AnalysisFH,
  409.                 "     Public Offset      :  %Xx\n", *(int *) RecordP);
  410.         RecordP += 2;
  411.         RecordLength -= 2;
  412.  
  413.         /* Type Index refers to preceding TYPDEF record. 0 = no data type */
  414.         IndexSize = GetVarLengthIdx(RecordP, &TypeIndex);
  415.         RecordP += IndexSize;
  416.         RecordLength -= IndexSize;
  417.         Output(Message, AnalysisFH, "     Type Index         :  %u\n",
  418.                 TypeIndex);
  419.     }
  420.     if (RecordLength)
  421.         Output(Error, AnalysisFH,
  422.                 "PUBDEF record not recognized.  Terminating\n");
  423. }
  424.  
  425. /*====================================
  426. *  3. Memory layout info:
  427. *   SEGDEF      0x98
  428. *   GRPDEF      0x9A
  429. *   COMDEF      0xB0
  430. *   TYPDEF      0x8E
  431. *====================================*/
  432.  
  433. /*---------------------------------------------------------
  434. *  DoSEGDEF --  Segment Definition record
  435. *    Describes a logical segment: name, length, alignment,
  436. *    combination with other logical segments.
  437. *    MS LINK limit: 255 SEGDEF records per OBJ modules
  438. *---------------------------------------------------------*/
  439. PUBLIC void DoSEGDEF(unsigned char *RecordP)
  440. {
  441.     char  *SegmentName;
  442.     long SegmentLength;
  443.     int SegmentIndex;
  444.     int ClassIndex;
  445.     int OverlayIndex;
  446.     char IndexSize;
  447.  
  448.     struct ACBP {
  449.         unsigned Page    : 1;
  450.         unsigned Big     : 1;
  451.         unsigned Combine : 3;
  452.         unsigned Align :   3;
  453.     } ACBP;
  454.  
  455.     ACBP = *(struct ACBP *) RecordP++;
  456.  
  457.     /* Segment Alignment at runtime */
  458.     switch(ACBP.Align) {
  459.         case 0 :
  460.             Output(Message, AnalysisFH, "     ABSOLUTE Segment\n");
  461.             break;
  462.         case 1 :
  463.             Output(Message, AnalysisFH, "     Relocatable/Align  :  BYTE\n");
  464.             break;
  465.         case 2 :
  466.             Output(Message, AnalysisFH, "     Relocatable/Align  :  WORD\n");
  467.             break;
  468.         case 3 :
  469.             Output(Message, AnalysisFH, "     Relocatable/Align  :  PARA\n");
  470.             break;
  471.         case 4 :
  472.             Output(Message, AnalysisFH, "     Relocatable/Align  :  PAGE\n");
  473.             break;
  474.         default:
  475.             Output(Warning, AnalysisFH,
  476.                     "Unrecognizable Segment Alignment Record\n");
  477.             break;
  478.     }
  479.  
  480.     /* Segment Combination that linker may perform to segments of same name.
  481.        Can either concatenate segments, or overlap them. Note: Absolute
  482.        segments (Align = 0) canNOT be combined (Combine = 0). */
  483.     switch(ACBP.Combine) {
  484.         case 0 :
  485.             Output(Message, AnalysisFH, "     PRIVATE Segment\n");
  486.             break;
  487.         case 2 :
  488.         case 4 :
  489.         case 7:
  490.             Output(Message, AnalysisFH,
  491.                     "     Combine Type  :  PUBLIC/Concatenate\n");
  492.             break;
  493.         case 5 :
  494.             Output(Message, AnalysisFH,
  495.                     "     Combine Type  :  STACK/Concatenate\n");
  496.             break;
  497.         case 6 :
  498.             Output(Message, AnalysisFH,
  499.                     "     Combine Type  :  COMMON/Overlap\n");
  500.             break;
  501.         default:
  502.             Output(Warning, AnalysisFH,
  503.                     "Unrecognizable Segment Combination Record\n");
  504.             break;
  505.     }
  506.  
  507.     /*  Big Field determines if segment size is EXACTLY 64k */
  508.     if (ACBP.Big == 1)
  509.         Output(Message, AnalysisFH, "     Segment Size       =  64Kb\n");
  510.     else
  511.         Output(Message, AnalysisFH, "     Segment Size       <  64Kb\n");
  512.  
  513.     /* Page field is unused in DOS and should be 0. */
  514.     if (ACBP.Page != 0)
  515.         Output(Message, AnalysisFH,
  516.                 "Unrecognized Page value in SEGDEF record\n");
  517.  
  518.  
  519.     /* Frame Number and Offset fields are present only for absolute segments.
  520.        Taken together, they provide the segment's starting address: */
  521.     if (ACBP.Align == 0) {          /* absolute segment specific fields */
  522.         Output(Message, AnalysisFH,
  523.                 "     Absolute Segment   : Frame Number   = %Xx\n",
  524.                 *(int *) RecordP);
  525.         RecordP += 2;
  526.         Output(Message, AnalysisFH,
  527.                 "     Absolute Segment   : Segment Offset = %Xx\n",
  528.                 *(unsigned char *) RecordP++);
  529.     }
  530.  
  531.     /* Segment Length in bytes */
  532.     SegmentLength = (long) *(unsigned int *) RecordP;
  533.     /* if Big field was 1 (i.e., 64K segment), 
  534.        Segment Length field is set to 0 */
  535.     if (ACBP.Big == 1 && SegmentLength == 0)
  536.         SegmentLength = 65536;          /* 64k */
  537.     Output(Message, AnalysisFH, "     Segment Length     :  %ld\n",
  538.             SegmentLength);
  539.     RecordP += 2;
  540.  
  541.     /* The Segment Name Index, Class Name Index, and Overlay Name Index
  542.        provide the names from previous LNAMES records. */
  543.     IndexSize = GetVarLengthIdx(RecordP, &SegmentIndex);
  544.     SegmentName = GetListNode(ListLNAMES, SegmentIndex)->InfoP;
  545.     Output(Message, AnalysisFH, "     Segment Name Index :  %d  --  %s\n",
  546.             SegmentIndex, SegmentName);
  547.     ListSEGDEF = AddListNode(ListSEGDEF, SegmentName);
  548.     RecordP += IndexSize;
  549.  
  550.     /* The Class Name Index gives the segment's class(e.g. CODE, or STACK),
  551.        so that linker can combine segments of equal class name. */
  552.     IndexSize = GetVarLengthIdx(RecordP, &ClassIndex);
  553.     Output(Message, AnalysisFH, "     Class   Name Index :  %d  --  %s\n",
  554.             ClassIndex, GetListNode(ListLNAMES, ClassIndex)->InfoP);
  555.     RecordP += IndexSize;
  556.  
  557.     /* The Overlay Name Index identifies a segment with a runtime overlay.
  558.        MS LINK ignores it, using command-line parameters to LINK instead. */
  559.     IndexSize = GetVarLengthIdx(RecordP, &OverlayIndex);
  560.     Output(Message, AnalysisFH, "     Overlay Name Index :  %d  --  %s\n",
  561.             OverlayIndex, GetListNode(ListLNAMES, OverlayIndex)->InfoP);
  562. }
  563. /*---------------------------------------------------------
  564. *   DoGRPDEF -- Group Definition record
  565. *     Defines a group of segments to reside together within
  566. *     64K frame at runtime.
  567. *     MS LINK limit: 21 GRPDEF records per OBJ module.
  568. *--------------------------------------------------------*/
  569. PUBLIC void DoGRPDEF(unsigned char *RecordP, int  RecordLength)
  570. {
  571.     char  *GroupName;
  572.     int GroupIndex;
  573.     int SegmentIndex;
  574.     char IndexSize;
  575.  
  576.     /* Get the Group Name via Group Name Index */
  577.     IndexSize = GetVarLengthIdx(RecordP, &GroupIndex);
  578.     GroupName = GetListNode(ListLNAMES, GroupIndex)->InfoP;
  579.     Output(Message, AnalysisFH, "     Group   Name Index :  %d  --  %s\n",
  580.             GroupIndex, GroupName);
  581.     /* Group Name may be later referenced in FIXUPP */
  582.     ListGRPDEF = AddListNode(ListGRPDEF, GroupName);
  583.     RecordLength -= IndexSize;
  584.     RecordP += IndexSize;
  585.  
  586.     /* Remainder of record is made up of Group Component Descriptors: */
  587.     while (RecordLength > 0) {
  588.         /* First byte is always FF, indicating following 
  589.            of Segment Name Index  */
  590.         ++RecordP;
  591.         RecordLength--;
  592.  
  593.         /* Segment Name Index relative to previous SEGDEF record */
  594.         IndexSize = GetVarLengthIdx(RecordP, &SegmentIndex);
  595.         Output(Message, AnalysisFH, 
  596.             "     Segment Name Index :  %d  --  %s\n",
  597.                   SegmentIndex, GetListNode(ListSEGDEF, 
  598.                   SegmentIndex)->InfoP);
  599.         RecordP += IndexSize;
  600.         RecordLength -= IndexSize;
  601.     }
  602.  
  603.     if (RecordLength)
  604.         Output(Error, AnalysisFH,
  605.                 "GRPDEF record not recognized.  Terminating\n");
  606. }
  607.  
  608. /*-------------------------------------------------------------------
  609. *   DoCOMDEF -- Common Name Definitions record
  610. *      MS extension declaring a (list of) communal variable(s).
  611. *      Being an extension COMDEF records must be indicated by COMENT
  612. *      record of Comment Class A1.
  613. *------------------------------------------------------------------*/
  614. PUBLIC void DoCOMDEF(unsigned char *RecordP, int RecordLength)
  615. {
  616.     char *ComName;
  617.     long CommunalSize;
  618.     int TypeIndex;
  619.     unsigned char DataSegmentType;
  620.     unsigned int  NameLength;
  621.     char IndexSize;
  622.     int i;
  623.  
  624.     while (RecordLength > 0) {
  625.         /* Communal Name */
  626.         ComName = MakeASCIIZ(RecordP);
  627.         ListEXTDEF = AddListNode(ListEXTDEF, ComName); /*EXTDEF name list*/
  628.         Output(Message, AnalysisFH,
  629.                 "\n     Communal Symbol    :  %s \n", ComName);
  630.         NameLength = *RecordP + 1;  /* name + length byte */
  631.         RecordLength -= NameLength;
  632.         RecordP += NameLength;
  633.  
  634.         /* Type Index indexes to TYPDEF, or is 0 if no associated type */
  635.         IndexSize = GetVarLengthIdx(RecordP, &TypeIndex);
  636.         Output(Message, AnalysisFH,
  637.                 "     Type Index         :  %X\n", (int) TypeIndex);
  638.         RecordLength -= IndexSize;
  639.         RecordP += IndexSize;
  640.  
  641.         /* Data Segment Type: is Communal Variable NEAR or FAR ? */
  642.         DataSegmentType = *RecordP++;
  643.         --RecordLength;
  644.         if (DataSegmentType == FAR)
  645.             Output(Message, AnalysisFH, 
  646.                     "     Default Data Segm. :  NO/FAR\n");
  647.         else if (DataSegmentType == NEAR)
  648.             Output(Message, AnalysisFH,
  649.                     "     Default Data Segm. :  YES/NEAR\n");
  650.         else
  651.             Output(Error, AnalysisFH,
  652.                     "COMDEF record not recognized.  Terminating\n");
  653.  
  654.         /* Communal Length field: amount of memory to allocate for communal.
  655.            Depending on Data Segment Type, the following bytes are 
  656.            interpreted: NEAR: variable size in bytes, FAR: number 
  657.            of elements, element size.
  658.  
  659.            NEAR: Variable Size field , 
  660.            FAR: Number of Elements/Element Size */
  661.  
  662.         for (i = 0; i < (DataSegmentType == NEAR ? 1 : 2); i++) {
  663.             /* The size field(s) is/are determined from first byte: */
  664.             switch (*RecordP) {
  665.                 /* 2 byte unsigned length field follows, i.e. < 64k */
  666.                 case  0x81 :
  667.                     ++RecordP;
  668.                     CommunalSize = (long) *(unsigned int *) RecordP;
  669.                     RecordLength -= 3;
  670.                     RecordP += 2;
  671.                     break;
  672.                 /* 3 byte unsigned length field: < 16M */
  673.                 case  0x84 :
  674.                     ++RecordP;
  675.                     CommunalSize = *(long *) RecordP & 0x00FFFFFF;
  676.                     RecordLength -= 4;
  677.                     RecordP += 3;
  678.                     break;
  679.                 /* 4 byte signed length field: < 2G */
  680.                 case  0x88 :
  681.                     ++RecordP;
  682.                     CommunalSize = *(long *) RecordP;
  683.                     RecordLength -= 5;
  684.                     RecordP += 4;
  685.                     break;
  686.                 /* char field of value < 80h is actual communal length: 
  687.                     < 128b */
  688.                 default :       /* 1 byte signed length field: < 128b */
  689.                     CommunalSize = (long) *RecordP++;
  690.                     --RecordLength;
  691.                     break;
  692.             }
  693.             if (DataSegmentType == NEAR)
  694.                 Output(Message, AnalysisFH,
  695.                         "     Communal Length    :  %ld bytes\n",
  696.                         CommunalSize);
  697.             else if (i == 0)
  698.                 Output(Message, AnalysisFH,
  699.                         "     Communal Elements  :  %ld bytes\n",
  700.                         CommunalSize);
  701.             else
  702.                 Output(Message, AnalysisFH,
  703.                         "     Element Size       :  %ld bytes\n",
  704.                         CommunalSize);
  705.         }
  706.     }
  707.  
  708.     if (RecordLength)
  709.         Output(Error, AnalysisFH,
  710.                 "COMDEF record not recognized.  Terminating\n");
  711. }
  712.  
  713. /*------------------------------------------------------------
  714. *  DoTYPDEF --  Type Definition record
  715. *    Type information about PUBDEF or EXTDEF name
  716. *------------------------------------------------------------*/
  717. PUBLIC void DoTYPDEF()
  718. {
  719.     Output(Warning, AnalysisFH, "TYPDEF not implemented\n");
  720. }
  721.  
  722. /*===============================================
  723. *  4. Code and data
  724. *   LEDATA      0xA0
  725. *   LIDATA      0xA2
  726. *==============================================*/
  727.  
  728. /*-------------------------------------------------------------
  729. *   DoLEDATA -- Logical Enumerated Data record
  730. *     Contiguous binary data, executable code or program data.
  731. *     Typically, preceded by SEGDEF and followed by FIXUPP record.
  732. *     Max. length for data field is 1024 bytes.
  733. *-------------------------------------------------------------*/
  734. PUBLIC void DoLEDATA(unsigned char *RecordP, int  RecordLength)
  735. {
  736.     int Offset;
  737.     int PrintLength;
  738.     int SegmentIndex;
  739.     char IndexSize;
  740.  
  741.     /* Segment Index field refers to SEGDEF record, indicating
  742.        segment into which to place this binary code/data. */
  743.     IndexSize = GetVarLengthIdx(RecordP, &SegmentIndex);
  744.     Output(Message, AnalysisFH, "     Segment Name Index :  %d  --  %s\n",
  745.             SegmentIndex, GetListNode(ListSEGDEF, SegmentIndex)->InfoP);
  746.     RecordP += IndexSize;
  747.     RecordLength -= IndexSize;
  748.  
  749.     /* Enumerated Data Offset: relative to Segment Index's segment base */
  750.     Output(Message, AnalysisFH, "     Enum. Data  Offset : %Xx\n",
  751.             *(int *) RecordP);
  752.     RecordP += 2;
  753.     RecordLength -= 2;
  754.  
  755.     Output(Message, AnalysisFH, "\nEnumerated Data:\n\n");
  756.  
  757.     Offset = 0;         /* offset of data relative to its record */
  758.     while (RecordLength > 0) {
  759.         PrintLength = (RecordLength > MAXLINELENGTH) ?
  760.                 MAXLINELENGTH : RecordLength;
  761.         PrintObjDumpLine(RecordP, AnalysisFH, Offset, PrintLength);
  762.         RecordLength -= PrintLength;
  763.         Offset += PrintLength;
  764.         RecordP    += PrintLength;
  765.     }
  766.  
  767.     if (RecordLength)
  768.         Output(Error, AnalysisFH,
  769.                 "LEDATA record not recognized.  Terminating\n");
  770. }
  771.  
  772. /*--------------------------------------------------------------
  773. *   DoLIDATA -- Logical Iterated Data record
  774. *      Binary code/data represented in repeating patterns (iterations).
  775. *      Typically, preceded by SEGDEF and followed by FIXUPP record.
  776. *      Max. size of iterated data block field is 512 bytes.
  777. *--------------------------------------------------------------*/
  778. PUBLIC void DoLIDATA(unsigned char *RecordP, int RecordLength)
  779. {
  780.     int BytesDone;
  781.     int SegmentIndex;
  782.     char IndexSize;
  783.  
  784.     /* Segment Index field refers to SEGDEF record, indicating segment
  785.     ** into which to place this binary code/data. */
  786.     IndexSize = GetVarLengthIdx(RecordP, &SegmentIndex);
  787.     Output(Message, AnalysisFH, "     Segment Name Index :  %d  --  %s\n",
  788.             SegmentIndex, GetListNode(ListSEGDEF, SegmentIndex)->InfoP);
  789.     RecordP += IndexSize;
  790.     RecordLength -= IndexSize;
  791.  
  792.     /* Iterated Data Offset: relative to Segment Index's segment base */
  793.     Output(Message, AnalysisFH, "     Iter. Data  Offset : %Xx\n",
  794.             *(int *) RecordP);
  795.     RecordP += 2;
  796.     RecordLength -= 2;
  797.  
  798.     while (RecordLength > 0) {
  799.         /* Iterated Data Blocks are defined recursively */
  800.         BytesDone = IteratedDataBlock(RecordP);
  801.         RecordLength -= BytesDone;
  802.         RecordP += BytesDone;
  803.     }
  804.  
  805.     if (RecordLength)
  806.         Output(Error, AnalysisFH,
  807.                 "LIDATA record not recognized.  Terminating\n");
  808. }
  809.  
  810. /*-----------------------------------------------------------------
  811. *   IteratedDataBlock -- Analyzes one Logical Iterated Data record
  812. *      This is separated out because of its recursive nature.
  813. *----------------------------------------------------------------*/
  814. PRIVATE int IteratedDataBlock(unsigned char *RecordP)
  815. {
  816.     int RepeatCount;
  817.     int BlockCount;
  818.     int BytesDone;
  819.     int Offset;
  820.     int DataBlockLength;
  821.     int PrintLength;
  822.     int RecordLength;
  823.  
  824.     /* Repeat Count is number of times to repeat Content field */
  825.     RepeatCount = *(int *) RecordP;
  826.     Output(Message, AnalysisFH, "\n     Repeat Count       : %d\n",
  827.             RepeatCount);
  828.     RecordP += 2;
  829.  
  830.     /* Block Count is number of iterated data blocks in Content field.
  831.     ** If 0, Content field contains data only. */
  832.     BlockCount = *(int *) RecordP;
  833.     Output(Message, AnalysisFH, "     Block Count       : %d\n", BlockCount);
  834.     RecordP += 2;
  835.     /* So far: Block Count and Repeat Count words */
  836.     BytesDone = 4;
  837.  
  838.     /* Content field: if Block Count != 0, nested iterated Data Blocks */
  839.     if (BlockCount > 0) {
  840.         FOREVER {
  841.             RecordLength = IteratedDataBlock(RecordP);
  842.             RecordP += RecordLength;
  843.             BytesDone += RecordLength;
  844.             if (--BlockCount == 0)
  845.                 return (BytesDone);
  846.         }
  847.     }
  848.  
  849.     /* With zero Block Count, this is data: length byte, then data bytes */
  850.     DataBlockLength = *(char *) RecordP++;
  851.     Output(Message, AnalysisFH, "     Data Block Length  : %d\n",
  852.             DataBlockLength);
  853.  
  854.     /* We've traversed: Data and its Length byte */
  855.     BytesDone += DataBlockLength + 1;
  856.  
  857.     /* Print the raw data */
  858.     Offset = 0;
  859.     while (DataBlockLength > 0) {
  860.         PrintLength = (DataBlockLength > MAXLINELENGTH) ?
  861.                 MAXLINELENGTH : DataBlockLength;
  862.         PrintObjDumpLine(RecordP, AnalysisFH, Offset, PrintLength);
  863.         DataBlockLength -= PrintLength;
  864.         Offset += PrintLength;
  865.         RecordP    += PrintLength;
  866.     }
  867.     return (BytesDone);
  868. }
  869.  
  870. /*===============================================
  871. *  5. Address binding/relocation:
  872. *   FIXUPP      0x9C
  873. *==============================================*/
  874.  
  875. /*----------------------------------------------------------------
  876. *   DoFIXUPP -- Relocation Fixup records: Used to resolve addresses             
  877. *     whose values cannot be determined prior to link time.
  878. *     LOCATION: address in OBJ module to be fixed up
  879. *     TARGET: address to which fixup refers (to be computed)
  880. *     FRAME: relative to which the address is computed
  881. *----------------------------------------------------------------*/
  882.  
  883. PUBLIC void DoFIXUPP(unsigned char *RecordP, int RecordLength)
  884. {
  885.     bool IsFixup;
  886.     int  FixupLength;
  887.  
  888.     while (RecordLength > 0) {
  889.         /* High bit determines difference between Thread field 
  890.             and Fixup field */
  891.         IsFixup = (bool) (*(char *) RecordP & 0x80);
  892.         if (IsFixup)
  893.             FixupLength = GetExplicitFixupp(RecordP);
  894.         else
  895.             FixupLength = GetFixupThread(RecordP);
  896.         RecordP += FixupLength;
  897.         RecordLength -= FixupLength;
  898.     }
  899.     if (RecordLength)
  900.         Output(Error, AnalysisFH,
  901.                 "FIXUPP record not recognized.  Terminating\n");
  902. }
  903.  
  904. /*-----------------------------------------------------------
  905. *   GetFixupThread --   Thread FIXUPP records
  906. *     Provides common info for reference by succeeding
  907. *     explicit fixup or thread fields in same or subsequent
  908. *     FIXUPP records.                                      
  909. *-----------------------------------------------------------*/
  910. PRIVATE int GetFixupThread(unsigned char *RecordP)
  911. {
  912.     struct ThrData {
  913.         unsigned ThreadNumber : 2;
  914.         unsigned Method       : 3;
  915.         unsigned NotUsed      : 1;
  916.         unsigned D            : 1;
  917.         unsigned FixupType    : 1;  /* 0 = Thread, 1 = Explicit FIXUPP */
  918.     }  ThreadData;
  919.  
  920.     FIXUPTHREAD Thread;
  921.     LNODE *ThreadName;
  922.     int RecLength = 1;      /* min. record length in bytes */
  923.     int IndexSize;
  924.  
  925.     Output(Message, AnalysisFH, "\n%04X  --  FIXUPP Thread:\n",
  926.             GetRecordRelPos(RecordP));
  927.  
  928.     /* Interpret the thread record */
  929.     ThreadData = *(struct ThrData *) RecordP++;
  930.     /* Thread will be known by an index 0-3 (for each, Frame and Target) */
  931.     Thread.ID = (char) ThreadData.ThreadNumber;
  932.  
  933.     /* D = 0 : Target Thread, identifies the fixup target */
  934.     /* D = 1 : Frame Thread, provides info about 64k frame */
  935.     Thread.Type = (char) (ThreadData.D == 0 ? 'T' : 'F');
  936.  
  937.     /* Methods: T0 - T7 (for D = 0), and F0 - F5 (for D = 1) */
  938.     Thread.Method = (char) ThreadData.Method;
  939.  
  940.  
  941.     /* Index Field appears always, except for frame threads 
  942.        using methods F3/4/5  */
  943.     if (!(Thread.Type == 'F' && Thread.Method > 2))
  944.         IndexSize = GetVarLengthIdx(RecordP, &Thread.ListIndex);
  945.     else
  946.         Thread.ListIndex = -1;      /* none */
  947.  
  948.     Output(Message, AnalysisFH, "\n     %s Thread #    :  %d\n",
  949.             Thread.Type == 'F' ? "Frame" : "Target",
  950.             (int) Thread.ID);
  951.  
  952.     /* The Method field (combined with D) gives linker method 
  953.        to identify T/F. DefList is applicable xxxDEF list to r
  954.        efer to via Index */
  955.     Thread.DefList = GetThreadFixupMethod((int) ThreadData.Method,
  956.             (int) ThreadData.D, RecordP - 1);
  957.  
  958.     if (Thread.ListIndex > 0) {
  959.         ThreadName = GetListNode(*(Thread.DefList),
  960.                 Thread.ListIndex)->InfoP;
  961.         Output(Message, AnalysisFH, "     %s Thread Index:  %u   --  %s\n",
  962.                 Thread.Type == 'F' ? "Frame" : "Target",
  963.                 Thread.ListIndex, ThreadName);
  964.         RecLength += IndexSize;         /* Record Length in bytes */
  965.     }
  966.  
  967.     PutThread(Thread);
  968.     return (RecLength);         /* Record Length in bytes */
  969. }
  970.  
  971. /*------------------------------------------------------------------
  972. *  GetThreadFixupMethod -- Interpret Method / D fields of Thread FIXUPP rec   
  973. *------------------------------------------------------------------*/
  974. PRIVATE LNODE *GetThreadFixupMethod(unsigned int Method, unsigned int D,
  975.         char *RecordP)
  976. {
  977.     if (D) {                            /* Frame Thread */
  978.         Output(Message, AnalysisFH, "     Frame ID Method   :  F%u  --  ",
  979.                 Method);
  980.         switch(Method) {
  981.             case 0 :
  982.                 Output(Message, AnalysisFH,
  983.                         "SEGDEF index: Highest #ered Frame cont. segm\n");
  984.                 return (&ListSEGDEF);
  985.             case 1 :
  986.                 Output(Message, AnalysisFH, "GRPDEF index\n");
  987.                 return (&ListGRPDEF);
  988.             case 2 :
  989.                 Output(Message, AnalysisFH, "EXTDEF index\n");
  990.                 return (&ListEXTDEF);
  991.             case 3 :
  992.                 Output(Message, AnalysisFH, "Frame Number\n");
  993.                 return (NULL);
  994.             case 4 :
  995.                 Output(Message, AnalysisFH,
  996.                         "Highest #ered Frame cont. segm of fixup loc\n");
  997.                 return (NULL);
  998.             case 5 :
  999.                 Output(Message, AnalysisFH, "Same as target frame\n");
  1000.                 return (NULL);
  1001.             default:
  1002.                 Output(Warning, AnalysisFH,
  1003.                    "\n%04X  --  FIXUPP: Bad Frame Thread Method Value\n",
  1004.                    GetRecordRelPos(RecordP));
  1005.                 return (NULL);
  1006.         }
  1007.     }
  1008.     else {                              /* Target Thread */
  1009.         Output(Message, AnalysisFH, "     Target ID Method   :  T%u  --  ",
  1010.                 Method);
  1011.         switch (Method) {
  1012.             case 0 :
  1013.                 Output(Message, AnalysisFH, "SEGDEF index and offset\n");
  1014.                 return (&ListSEGDEF);
  1015.             case 1 :
  1016.                 Output(Message, AnalysisFH, "GRPDEF index and offset\n");
  1017.                 return (&ListGRPDEF);
  1018.             case 2 :
  1019.                 Output(Message, AnalysisFH, "EXTDEF index and offset\n");
  1020.                 return (&ListEXTDEF);
  1021.             case 3 :
  1022.                 Output(Message, AnalysisFH, "Frame Number and offset\n");
  1023.                 return (NULL);
  1024.             case 4 :
  1025.                 Output(Message, AnalysisFH, "SEGDEF index only.");
  1026.                 Output(Message, AnalysisFH, "Target at Segment beginning\n");
  1027.                 return (&ListSEGDEF);
  1028.             case 5 :
  1029.                 Output(Message, AnalysisFH, "GRPDEF index only\n");
  1030.                 return (&ListGRPDEF);
  1031.             case 6 :
  1032.                 Output(Message, AnalysisFH, "EXTDEF index only\n");
  1033.                 return (&ListEXTDEF);
  1034.             case 7 :
  1035.                 Output(Message, AnalysisFH, "Frame Number only\n");
  1036.                 return (NULL);
  1037.             default:
  1038.                 Output(Warning, AnalysisFH,
  1039.                    "\n%04X  --  FIXUPP: Bad Target Thread Method Value\n",
  1040.                    GetRecordRelPos(RecordP));
  1041.                 return (NULL);
  1042.         }
  1043.     }
  1044. }
  1045.  
  1046. /*---------------------------------------------------------------
  1047. *   GetThread   --  Retrieve a thread from the thread data table
  1048. *                   If no valid thread, return NULL.
  1049. *--------------------------------------------------------------*/
  1050. PRIVATE FIXUPTHREAD *GetThread(unsigned char ThreadID, char ThreadType,
  1051.         char *RecordP)
  1052. {
  1053.     int Idx;
  1054.  
  1055.     if (ThreadID <= 3) {
  1056.         /* In table, we store Frame threads first then Target threads */
  1057.         Idx = (int) (ThreadType == 'F' ? ThreadID :
  1058.                 ThreadID + (char) THREADMAX);
  1059.         if (ThreadTable[Idx].ListIndex != -1)
  1060.             return (&ThreadTable[Idx]);
  1061.     }
  1062.  
  1063.     /* If we get here, we're in trouble! */
  1064.     Output(Warning, AnalysisFH,
  1065.             "\n%04X  --  FIXUPP: Bad Thread Reference\n",
  1066.             GetRecordRelPos(RecordP));
  1067.     return (NULL);
  1068. }
  1069.  
  1070. /*--------------------------------------------------------
  1071. *   PutThread   --  Save a thread in the thread data table
  1072. *-------------------------------------------------------*/
  1073. PRIVATE void PutThread(FIXUPTHREAD NewThread)
  1074. {
  1075.     int Idx;
  1076.  
  1077.     /* In table, we store Frame threads first then Target threads */
  1078.     Idx = (int) (NewThread.Type == 'F' ? NewThread.ID :
  1079.             NewThread.ID + (char) THREADMAX);
  1080.     ThreadTable[Idx] = NewThread;
  1081. }
  1082.  
  1083. /*-------------------------------------------------------
  1084. *   InstThreadTable --  Instantiate the Thread Table
  1085. *------------------------------------------------------*/
  1086. PRIVATE void InstThreadTable()
  1087. {
  1088.     int i;
  1089.  
  1090.     for (i = 0; i < THREADMAX * 2; i++)
  1091.         ThreadTable[i].ID = -1;
  1092. }
  1093.  
  1094. /*-------------------------------------------------------
  1095. *  GetExplicitFixupp -- Explicit FIXUPP records
  1096. *-------------------------------------------------------*/
  1097. PRIVATE int GetExplicitFixupp(unsigned char *RecordP)
  1098. {
  1099.     int RecordLength;
  1100.  
  1101.     union {
  1102.         struct {
  1103.           unsigned DataRecOffset : 10; /* LOCATION position in LxDATA rec */
  1104.           unsigned Loc         : 3;  /* location type to be fixed up */
  1105.           unsigned S           : 1;  /* unused, should be 0 */
  1106.           unsigned Mode        : 1;  /* segment-relative vs self-relative */
  1107.           unsigned FixupType   : 1;  /* explicit or thread */
  1108.         } Word;
  1109.         char Byte[2];
  1110.     } Locat;
  1111.  
  1112.     Output(Message, AnalysisFH, "\n%04X  --  Explicit FIXUPP :\n",
  1113.             GetRecordRelPos(RecordP));
  1114.  
  1115.     Locat.Byte[1] = *RecordP++;            /* read bit fields   */
  1116.     Locat.Byte[0] = *RecordP++;            /* in reverse order  */
  1117.  
  1118.     /* Mode bit */
  1119.     Output(Message, AnalysisFH, "\n     Fixup Relativity   :  %s \n",
  1120.             Locat.Word.Mode ? "SEGMENT" : "SELF");
  1121.  
  1122.     GetFixupLocation((int) Locat.Word.Loc, RecordP - 2);  /* Loc field */
  1123.  
  1124.                                  /* Data Rec Offset in previous LxDATA */
  1125.     Output(Message, AnalysisFH, "     Location Offset    :  %Xx\n",
  1126.             (int) Locat.Word.DataRecOffset);
  1127.  
  1128.     RecordLength = GetFixDatField(RecordP);
  1129.  
  1130.     return (RecordLength);
  1131. }
  1132.  
  1133. /*----------------------------------------------------------
  1134. *  GetFixupLocation --  Determine location to be fixed up.
  1135. *                       (Explicit FIXUPP record)
  1136. *----------------------------------------------------------*/
  1137. PRIVATE void GetFixupLocation(unsigned int Loc, char *RecordP)
  1138. {
  1139.     Output(Message, AnalysisFH, "     Fixup Location     :  ");
  1140.     switch (Loc) {
  1141.         case 0 :
  1142.             Output(Message, AnalysisFH, "Low-Order Byte\n");
  1143.             break;
  1144.         case 5 :        /* Loc = 5 is treated as Loc - 1 by linker */
  1145.             Output(Message, AnalysisFH, "Loader-resolved Offset/");
  1146.         case 1 :
  1147.             Output(Message, AnalysisFH, "Ptr-Offset (16-bit)\n");
  1148.             break;
  1149.         case 2 :
  1150.             Output(Message, AnalysisFH, "Ptr-Segment (16-bit)\n");
  1151.             break;
  1152.         case 3 :
  1153.             Output(Message, AnalysisFH, "FAR Pointer (32-bit)\n");
  1154.             break;
  1155.         case 4 :
  1156.             Output(Message, AnalysisFH, "High-Order Byte\n");
  1157.             break;
  1158.         default:
  1159.             Output(Warning, AnalysisFH,
  1160.                     "\n%04X  --  FIXUPP: Bad Loc field %04X\n",
  1161.                     GetRecordRelPos(RecordP), Loc);
  1162.             break;
  1163.     }
  1164. }
  1165.  
  1166. /*-----------------------------------------------------------------
  1167. *  GetFixDatField -- Interpret the FixDat field in explicit FIXUPP
  1168. *  record and its equivalent, the EndDat in MODEND.
  1169. *----------------------------------------------------------------*/
  1170. PRIVATE int GetFixDatField(unsigned char *RecordP)
  1171. {
  1172.     struct fd {
  1173.         unsigned Targt   : 2;           /* data record offset */
  1174.         unsigned P       : 1;
  1175.         unsigned T       : 1;
  1176.         unsigned Frame   : 3;
  1177.         unsigned F       : 1;
  1178.     } FixDat;
  1179.  
  1180.     LNODE *FrameList;
  1181.     LNODE *TargetList;
  1182.     FIXUPTHREAD *ThreadP;
  1183.     int FrameMethod;
  1184.     int TargetMethod;
  1185.     int FrameDatum;
  1186.     int TargetDatum;
  1187.     int DatumSize;
  1188.     int RecordLength;
  1189.                                         /* F/Frame fields */
  1190.     FixDat = *(struct fd *) RecordP++;
  1191.     if (FixDat.F) {               /* F = 1 => frame in previous thread */
  1192.         Output(Message, AnalysisFH, "     Frame  Reference   :  THREAD\n");
  1193.         ThreadP = GetThread((char) FixDat.Frame, 'F', RecordP - 1);
  1194.         Output(Message, AnalysisFH,
  1195.                 "     Frame  ID Method   :  Thread # %u  --  %s\n",
  1196.                 (int) FixDat.Frame,
  1197.                 GetListNode(*ThreadP->DefList, ThreadP->ListIndex)->InfoP);
  1198.     }
  1199.     else {                      /* F = 0 => explicit frame */
  1200.         Output(Message, AnalysisFH, "     Frame  Reference   :  EXPLICIT\n");
  1201.         FrameMethod = (int) FixDat.Frame;
  1202.         FrameList = GetThreadFixupMethod(FrameMethod, 1, RecordP - 1);
  1203.     }
  1204.  
  1205.                                 /* T field */
  1206.     if (FixDat.T)                 /* T = 1 => target in prev. thread */
  1207.         Output(Message, AnalysisFH, "     Target Reference   :  THREAD\n");
  1208.     else                        /* T = 0 => target explicit in FUP */
  1209.         Output(Message, AnalysisFH, "     Target Reference   :  EXPLICIT\n");
  1210.  
  1211.                                 /* P field */
  1212.     if (FixDat.P)                 /* P = 1 => target spec 2ndary way */
  1213.         Output(Message, AnalysisFH,
  1214.            "     Target Specific.   :  SECONDARY  --  IDX / NO OFFSET\n");
  1215.     else
  1216.         Output(Message, AnalysisFH,
  1217.            "     Target Specific.   :  PRIMARY  --  IDX / OFFSET\n");
  1218.  
  1219.                                         /* Target field */
  1220.     if (FixDat.T) {               /* T = 1 => thread target spec */
  1221.         ThreadP = GetThread((char) FixDat.Targt, 'T', RecordP - 1);
  1222.         Output(Message, AnalysisFH,
  1223.                 "     Target ID Method   :  Thread # %u  --  %s\n",
  1224.                 (int) FixDat.Targt,
  1225.                 GetListNode(*ThreadP->DefList, ThreadP->ListIndex)->InfoP);
  1226.     }
  1227.     else {          /*  T = 0 => explicit target spec */
  1228.                     /* Target = method of identifying target */
  1229.       TargetMethod = (int) ((FixDat.P) ? (FixDat.Targt + 4) : FixDat.Targt);
  1230.       TargetList = GetThreadFixupMethod(TargetMethod, 0, RecordP - 1);
  1231.     }
  1232.     RecordLength = 3;
  1233.  
  1234.     /* Frame Datum */
  1235.     if (FixDat.F == 0 && FrameMethod < 4) {
  1236.         DatumSize = GetVarLengthIdx(RecordP, &FrameDatum);
  1237.         Output(Message, AnalysisFH, 
  1238.             "     Frame  Datum       :  %d  --  %s\n",
  1239.             FrameDatum, (FrameList != NULL) ?
  1240.             GetListNode(*FrameList, FrameDatum)->InfoP : " ");
  1241.         RecordP += DatumSize;
  1242.         RecordLength += DatumSize;
  1243.     }
  1244.  
  1245.     /* Target Datum */
  1246.     if (FixDat.T == 0) {
  1247.         DatumSize = GetVarLengthIdx(RecordP, &TargetDatum);
  1248.         Output(Message, AnalysisFH, 
  1249.             "     Target Datum       :  %d  --  %s\n",
  1250.             TargetDatum, (TargetList != NULL) ?
  1251.             GetListNode(*TargetList, TargetDatum)->InfoP : " ");
  1252.         RecordP += DatumSize;
  1253.         RecordLength += DatumSize;
  1254.     }
  1255.  
  1256.     /* Target Displacement */
  1257.     if (FixDat.P == 0) {
  1258.         Output(Message, AnalysisFH, "     Target Displacement:  %Xx\n",
  1259.                 *(int *) RecordP);
  1260.         RecordP += 2;
  1261.         RecordLength += 2;
  1262.     }
  1263.     return (RecordLength);
  1264. }
  1265.  
  1266. /*===========================
  1267. *  6. Debugging info:
  1268. *   LINNUM      0x94
  1269. *==========================*/
  1270.  
  1271. /*----------------------------------------------------
  1272. *  DoLINNUM --  Line Numbers record: relates source code line 
  1273. *      numbers to OBJ code addresses.
  1274. *---------------------------------------------------*/
  1275. PUBLIC void DoLINNUM(unsigned char *RecordP, int  RecordLength)
  1276. {
  1277.     int  GroupIndex;
  1278.     int  SegmentIndex;
  1279.     char IndexSize;
  1280.     LNODE *ListNodeP;
  1281.     int LineNumber;
  1282.     unsigned int LineNumberOffset;
  1283.  
  1284.     /* The Line Number Base (Group Index/Segment Index) describes the
  1285.        segment to which the line number refers.
  1286.        Group containing this code (always 0 for MS translators) */
  1287.     if ((GroupIndex = (int) *RecordP++) != 0) {
  1288.        ListNodeP = GetListNode(ListLNAMES, GroupIndex);
  1289.        Output(Message, AnalysisFH, "     Group   Name Index :  %u  --  %s\n",
  1290.               GroupIndex, (ListNodeP != NULL) ? ListNodeP->InfoP : " ");
  1291.     }
  1292.     else
  1293.         Output(Message, AnalysisFH,
  1294.                 "     Group   Name Index :  %u  --  NO GROUP\n", GroupIndex);
  1295.     RecordLength--;
  1296.  
  1297.     /* Segment Index refers to a previous SEGDEF record. */
  1298.     IndexSize = GetVarLengthIdx(RecordP, &SegmentIndex);
  1299.     RecordP += IndexSize;
  1300.     RecordLength -= IndexSize;
  1301.     if (SegmentIndex != 0) {
  1302.        ListNodeP = GetListNode(ListSEGDEF, SegmentIndex);
  1303.        Output(Message, AnalysisFH, "     Segment Name Index :  %u  --  %s\n",
  1304.                SegmentIndex, (ListNodeP != NULL) ? ListNodeP->InfoP : " ");
  1305.     }
  1306.     else
  1307.         Output(Message, AnalysisFH,
  1308.                 "     Segment Name Index :  %u  --  NO SEGMENT\n",
  1309.                 SegmentIndex);
  1310.  
  1311.     while (RecordLength > 0) {
  1312.         /* Line Number: source code line number (0 <= n <= 32,767) */
  1313.         LineNumber = *(int *) RecordP;
  1314.         Output(Message, AnalysisFH, "     Line Number        :  %d\n",
  1315.                 LineNumber);
  1316.         RecordP += 2;
  1317.  
  1318.         /* Line Number Offset: offset into code (in segment specified
  1319.            by Line Number Base) to which line number refers */
  1320.         LineNumberOffset = *(unsigned int *) RecordP;
  1321.         Output(Message, AnalysisFH, "     Line # Offset      :  %Xx\n\n",
  1322.                 LineNumberOffset);
  1323.         RecordP += 2;
  1324.         RecordLength -= 4;
  1325.     }
  1326.  
  1327.     if (RecordLength)
  1328.         Output(Error, AnalysisFH,
  1329.                 "LINNUM record not recognized.  Terminating\n");
  1330. }
  1331.  
  1332. /*================================
  1333. *  7. Obsolete record types
  1334. *   BLKDEF      0x7A
  1335. *   BLKEND      0x7C
  1336. *   LHEADR      0x82
  1337. *===============================*/
  1338.  
  1339. /*----------------------------------------
  1340. *   DoBLKDEF -- Block Definition record
  1341. *----------------------------------------*/
  1342. PUBLIC void DoBLKDEF()
  1343. {
  1344.     Output(Warning, AnalysisFH, "BLKDEF not implemented\n");
  1345. }
  1346.  
  1347. /*----------------------------------------
  1348. *   DoBLKEND -- Block End Record
  1349. *----------------------------------------*/
  1350. PUBLIC void DoBLKEND()
  1351. {
  1352.     Output(Message, AnalysisFH, "\nBLOCK END\n");
  1353. }
  1354.  
  1355. /*----------------------------------------
  1356. *  DoLHEADR --  Translator Header Record (L-module)
  1357. *  NOTE: MUST always appear as the first record in OBJ module
  1358. *---------------------------------------*/
  1359. PUBLIC void DoLHEADR(unsigned char *RecordP)
  1360. {
  1361.     char *ModuleName;
  1362.  
  1363.     ModuleName = MakeASCIIZ(RecordP);
  1364.  
  1365.     Output(Message, AnalysisFH, "Module Name:\n     %s\n", ModuleName);
  1366.     free(ModuleName);
  1367. }
  1368.  
  1369. /*===============================================
  1370. *  8. Microsoft extensions
  1371. *   BAKPAT      0xB2 (0xB3, for 32-bit offsets)
  1372. *   LEXTDEF     0xB4
  1373. *   LPUBDEF     0xB6 (0xB7, for 32-bit offsets)
  1374. *   LCOMDEF     0xB8
  1375. *===============================================*/
  1376.  
  1377. /*-------------------------------------------------------
  1378. ** DoBAKPAT --  Back Patch record: Supplementary to FIXUPP records,
  1379. *    BAKPAT handles back patches to locations that a regular fix-up
  1380. *    record cannot easily deal with, e.g. forward references in
  1381. *    one-pass compilers. This record is specific to Quick C.
  1382. *-------------------------------------------------------*/
  1383. PUBLIC void DoBAKPAT(unsigned char *RecordP, int  RecordLength)
  1384. {
  1385.     int  SegmentIndex;
  1386.     int IndexSize;
  1387.     LNODE *ListNodeP;
  1388.     char LocTyp;
  1389.     unsigned int Offset;
  1390.     int PatchValue;
  1391.  
  1392.     /* Segment Index refers to a previous SEGDEF record. */
  1393.     IndexSize = GetVarLengthIdx(RecordP, &SegmentIndex);
  1394.     RecordP += IndexSize;
  1395.     RecordLength -= IndexSize;
  1396.     ListNodeP = GetListNode(ListSEGDEF, SegmentIndex);
  1397.     Output(Message, AnalysisFH, "     Segment Name Index :  %u  --  %s\n",
  1398.             SegmentIndex, (ListNodeP != NULL) ? ListNodeP->InfoP : " ");
  1399.  
  1400.     /* LocTyp  indicates type of location to patch: 0 -> low-byte,
  1401.     **  1 -> word offset, 32 -> double-word offset              */
  1402.     LocTyp = *RecordP++;
  1403.     RecordLength--;
  1404.     Output(Message, AnalysisFH, "     Location Type      :  %d\n",
  1405.             LocTyp);
  1406.  
  1407.     /* The remainder of the record is a repeatable pair of Offset into
  1408.        segment to patch, and value to add to patched Location   */
  1409.     while (RecordLength > 0) {
  1410.         Offset = *(unsigned int *) RecordP;
  1411.         Output(Message, AnalysisFH, "     Offset             :  %04Xx\n",
  1412.                 Offset);
  1413.         RecordP += 2;
  1414.  
  1415.         PatchValue = *(int *) RecordP;
  1416.         Output(Message, AnalysisFH, "     Patch Value        :  %04Xx\n\n",
  1417.                 PatchValue);
  1418.         RecordP += 2;
  1419.         RecordLength -= 4;
  1420.     }
  1421.  
  1422.     if (RecordLength)
  1423.         Output(Error, AnalysisFH,
  1424.                 "BAKPAT record not recognized.  Terminating\n");
  1425. }
  1426.  
  1427. #define  OTRANGE  32
  1428. #define  LOREC    0x7A
  1429. #define  HIREC    0xB8
  1430.  
  1431. PRIVATE char ObjTypes[OTRANGE][OMFNAMELENGTH] = {
  1432.     { "BLKDEF" },        /* 0x7A */
  1433.     { "BLKEND" },        /* 0x7C */
  1434.     { ""       },        /* 0x7E */
  1435.     { "THEADR" },        /* 0x80 */
  1436.     { ""       },        /* 0x82 */
  1437.     { ""       },        /* 0x84 */
  1438.     { ""       },        /* 0x86 */
  1439.     { "COMENT" },        /* 0x88 */
  1440.     { "MODEND" },        /* 0x8A */
  1441.     { "EXTDEF" },        /* 0x8C */
  1442.     { "TYPDEF" },        /* 0x8E */
  1443.     { "PUBDEF" },        /* 0x90 */
  1444.     { ""       },        /* 0x92 */
  1445.     { "LINNUM" },        /* 0x94 */
  1446.     { "LNAMES" },        /* 0x96 */
  1447.     { "SEGDEF" },        /* 0x98 */
  1448.     { "GRPDEF" },        /* 0x9A */
  1449.     { "FIXUPP" },        /* 0x9C */
  1450.     { ""       },        /* 0x9E */
  1451.     { "LEDATA" },        /* 0xA0 */
  1452.     { "LIDATA" },        /* 0xA2 */
  1453.     { ""       },        /* 0xA4 */
  1454.     { ""       },        /* 0xA6 */
  1455.     { ""       },        /* 0xA8 */
  1456.     { ""       },        /* 0xAA */
  1457.     { ""       },        /* 0xAC */
  1458.     { ""       },        /* 0xAE */
  1459.     { "COMDEF" },        /* 0xB0 */
  1460.     { "BAKPAT" },        /* 0xB2 */
  1461.     { "LEXTDEF" },       /* 0xB4 */
  1462.     { "LPUBDEF" },       /* 0xB6 */
  1463.     { "LCOMDEF" }        /* 0xB8 */
  1464. };
  1465.  
  1466. /*---------------------------------------------------------------------
  1467. *   GetObjRecordName -- Supply an OBJ record type number, receive the
  1468. *      record-type name. NOTE: this table has been tailored to a subset
  1469. *      of Intel records plus extensions as used by Microsoft.
  1470. *--------------------------------------------------------------------*/
  1471. PUBLIC RC GetObjRecordName(unsigned char ObjRecType, char ObjRecName[])
  1472. {
  1473.     if (ObjRecType < LOREC || ObjRecType > HIREC) {
  1474.         ObjRecName[0] = '\0';
  1475.         return (!OK);
  1476.     }
  1477.  
  1478.     strcpy(ObjRecName, ObjTypes[(ObjRecType - LOREC) / 2]);
  1479.     if (ObjRecName[0] == '\0')
  1480.         return (!OK);
  1481.     return (OK);
  1482. }
  1483.  
  1484. /*-------------------------------------------------------------------
  1485. *   GetRecordRelPos --  Get an OBJ record's relative position in the 
  1486. *      OBJ module. Note : The return type is unsigned int, assuming a     
  1487. *      a maximum  OBJ module size of 64K.
  1488. *------------------------------------------------------------------*/
  1489. PUBLIC unsigned int GetRecordRelPos(char *CurrentPosition)
  1490. {
  1491.     return (CurrentPosition - ObjBase);
  1492. }
  1493.  
  1494. /*-------------------------------------------------------------------
  1495. *   GetVarLengthIdx --  Indexes are variable length: 0-7Fh is fit into 
  1496. *      one byte; 80-7FFF (the max index), is fit into two bytes.
  1497. *      A two byte field is indicated by the high bit being set,
  1498. *      and is non-INTEL byte order.
  1499. *    Example: 8283 equals 283h.
  1500. *    Returns: Length of index in bytes
  1501. *-------------------------------------------------------------------*/
  1502. PRIVATE char GetVarLengthIdx(char *RecordP, int *Index)
  1503. {
  1504.     #define BYTE    1
  1505.     #define WORD    2
  1506.  
  1507.     union {
  1508.         char Byte[2];
  1509.         int  Word;
  1510.     } Int;
  1511.  
  1512.     if (*RecordP & 0x80) {      /* we're dealing with TWO bytes */
  1513.         /* Clear high bit, and make this index's high byte */
  1514.         Int.Byte[1] = *RecordP++ & (char) 0x7F;
  1515.         Int.Byte[0] = *RecordP;
  1516.         *Index = Int.Word;
  1517.         return (WORD);
  1518.     }
  1519.     else {                      /* simple byte 0 - 7Fh */
  1520.         *Index = (int) *RecordP;
  1521.         return (BYTE);
  1522.     }
  1523. }