Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /****************************    omf.cpp    *********************************
  2. * Author:        Agner Fog
  3. * Date created:  2007-01-29
  4. * Last modified: 2018-05-26
  5. * Project:       objconv
  6. * Module:        omf.cpp
  7. * Description:
  8. * Module for reading OMF files
  9. *
  10. * Class COMF is used for reading, interpreting and dumping OMF files.
  11. *
  12. * Copyright 2007-2018 GNU General Public License http://www.gnu.org/licenses
  13. *****************************************************************************/
  14. #include "stdafx.h"
  15.  
  16. // OMF Record type names
  17. SIntTxt OMFRecordTypeNames[] = {
  18.    {OMF_THEADR,      "Translator Header"},
  19.    {OMF_LHEADR,      "Library Module Header"},
  20.    {OMF_COMENT,      "Comment"},
  21.    {OMF_MODEND,      "Module End"},
  22.    {OMF_EXTDEF,      "External Names Definition"},
  23.    {OMF_PUBDEF,      "Public Names Definition"},
  24.    {OMF_LINNUM,      "Line Numbers"},
  25.    {OMF_LNAMES,      "List of Names"},
  26.    {OMF_SEGDEF,      "Segment Definition"},
  27.    {OMF_GRPDEF,      "Group Definition"},
  28.    {OMF_FIXUPP,      "Fixup"},
  29.    {OMF_LEDATA,      "Enumerated Data"},
  30.    {OMF_LIDATA,      "Iterated Data"},
  31.    {OMF_COMDEF,      "Communal Names Definition"},
  32.    {OMF_BAKPAT,      "Backpatch"},
  33.    {OMF_LEXTDEF,     "Local External Names"},
  34.    {OMF_LPUBDEF,     "Local Public Names"},
  35.    {OMF_LCOMDEF,     "Local Communal Names"},
  36.    {OMF_CEXTDEF,     "COMDAT External Names"},
  37.    {OMF_COMDAT,      "Initialized Communal Data"},
  38.    {OMF_LINSYM,      "Symbol Line Numbers"},
  39.    {OMF_ALIAS,       "Alias Definition"},
  40.    {OMF_NBKPAT,      "Named Backpatch"},
  41.    {OMF_LLNAMES,     "Local Logical Names"},
  42.    {OMF_VERNUM,      "OMF Version Number"},
  43.    {OMF_VENDEXT,     "Vendor-specific OMF Extension"},
  44.    {OMF_LIBHEAD,     "Library Header"},
  45.    {OMF_LIBEND,      "Library End"}
  46. };
  47.  
  48. // Segment combination names
  49. SIntTxt OMFSegmentCombinationNames[] = {
  50.    {0,     "Private"},
  51.    {1,     "Invalid"},
  52.    {2,     "Public"},
  53.    {3,     "Invalid"},
  54.    {4,     "Public 4"},
  55.    {5,     "Stack"},
  56.    {6,     "Common"},
  57.    {7,     "Public 7"}
  58. };
  59.  
  60. // Relocation mode names
  61. static SIntTxt OMFRelocationModeNames[] = {
  62.    {0,     "Relatv"},
  63.    {1,     "Direct"}
  64. };
  65.  
  66.  
  67. // Fixup location names
  68. static SIntTxt OMFFixupLocationNames[] = {
  69.    {OMF_Fixup_8bit,        "8 bit"},                       // 0
  70.    {OMF_Fixup_16bit,       "16 bit"},                      // 1
  71.    {OMF_Fixup_Segment,     "segment selector, 16 bit"},    // 2
  72.    {OMF_Fixup_Far,         "far pointer 16+16 bit"},       // 3
  73.    {OMF_Fixup_Hi8bit,      "high 8 bit of 16 bits"},       // 4
  74.    {OMF_Fixup_16bitLoader, "16 bit loader resolved"},      // 5
  75.    {OMF_Fixup_Pharlab48,   "farword 48 bit, Pharlab only"},// 6
  76.    {OMF_Fixup_32bit,       "32 bit"},                      // 9
  77.    {OMF_Fixup_Farword,     "farword 32+16 bit"},           // 11
  78.    {OMF_Fixup_32bitLoader, "32 bit loader resolved"}       // 13
  79. };
  80.  
  81. // Alignment value translation table
  82. static const uint32 OMFAlignTranslate[8] = {0,1,2,16,256,4,0,0};
  83.  
  84.  
  85. // Class COMF members:
  86. // Constructor
  87.  
  88. COMF::COMF() {
  89.    // Default constructor
  90.    memset(this, 0, sizeof(*this));     // reset everything
  91. }
  92.  
  93.  
  94. void COMF::ParseFile() {
  95.    // Parse file buffer
  96.    //uint8  RecordType;                            // Type of current record
  97.    uint32 Checksum;                              // Record checksum
  98.    uint32 ChecksumZero = 0;                      // Count number of records with zero checksum
  99.    SOMFRecordPointer rec;                        // Current record pointer
  100.  
  101.    // Make first entry zero in name lists
  102.    LocalNameOffset.PushZero();
  103.    SegmentNameOffset.PushZero();
  104.    GroupNameOffset.PushZero();
  105.    SymbolNameOffset.PushZero();
  106.  
  107.    // Initialize record pointer
  108.    rec.Start(Buf(), 0, GetDataSize());
  109.  
  110.    // Loop through records to set record pointers and store names
  111.    do {
  112.       // Read record
  113.       //RecordType = rec.Type2;                    // First byte of record = type
  114.  
  115.       // Compute checksum
  116.       Checksum = 0;  rec.Index = 0;
  117.       while (rec.Index < rec.End) Checksum += rec.GetByte();
  118.       uint32 CheckByte = rec.GetByte();
  119.       if ((Checksum + CheckByte) & 0xFF) {
  120.          // Checksum failed
  121.          if (CheckByte == 0) {
  122.             ChecksumZero++;
  123.          }
  124.          else err.submit(1202);                  // Checksum error
  125.       }
  126.  
  127.       // Store record pointer
  128.       rec.Index = 3;                             // Offset to current byte while parsing
  129.       Records.Push(rec);                         // Store record pointer in list
  130.  
  131.       if (rec.Type2 == OMF_LNAMES) {
  132.          // LNAMES record. Store local names by name index
  133.          // Loop through strings in record
  134.          while (rec.Index < rec.End) {
  135.             char * LocalName = rec.GetString();
  136.             uint32 LocalNameIndex = NameBuffer.PushString(LocalName); // Store local name
  137.             LocalNameOffset.Push(LocalNameIndex);// Store local name index
  138.          }
  139.          if (rec.Index != rec.End) err.submit(1203);  // Check for consistency
  140.       }
  141.  
  142.       if (rec.Type2 == OMF_SEGDEF) {
  143.          // SEGDEF record. Store segment names by segment index
  144.          OMF_SAttrib Attributes;
  145.          if (rec.Type2 == OMF_SEGDEF) {
  146.             Attributes.b = rec.GetByte();     // Read attributes
  147.             if (Attributes.u.A == 0) {
  148.                // Frame and Offset only included if A = 0
  149.                rec.GetWord();  rec.GetByte();
  150.             }
  151.             rec.GetNumeric(); // Length
  152.          }
  153.          uint32 NameIndex  = rec.GetIndex();
  154.          if (NameIndex < LocalNameOffset.GetNumEntries()) {
  155.             SegmentNameOffset.Push(LocalNameOffset[NameIndex]); // List by segment index
  156.          }
  157.       }
  158.  
  159.       if (rec.Type2 == OMF_GRPDEF) {
  160.          // GRPDEF record. Store group name
  161.          uint32 NameIndex  = rec.GetIndex();
  162.          if (NameIndex < LocalNameOffset.GetNumEntries()) {
  163.             GroupNameOffset.Push(LocalNameOffset[NameIndex]); // List by group index
  164.          }
  165.       }
  166.  
  167.       if (rec.Type2 == OMF_EXTDEF) {
  168.          // EXTDEF record. Store external symbol names
  169.          // Loop through strings in record
  170.          while (rec.Index < rec.End) {
  171.             char * symbolname = rec.GetString();
  172.             rec.GetIndex();
  173.             uint32 SymbolNameIndex = NameBuffer.PushString(symbolname); // Store external name
  174.             SymbolNameOffset.Push(SymbolNameIndex);   // Save in name index table
  175.          }
  176.          if (rec.Index != rec.End) err.submit(1203);  // Check for consistency
  177.       }
  178.  
  179.       if (rec.Type2 == OMF_CEXTDEF) {
  180.          // CEXTDEF record. Store communal symbol names
  181.          // Loop through entries in record
  182.          uint32 SymbolNameIndex;                 // Index into NameBuffer
  183.          while (rec.Index < rec.End) {
  184.             uint32 LIndex = rec.GetIndex();      // Index into preceding LNAMES
  185.             rec.GetIndex();                      // Type index. Ignore
  186.             // Get name from LocalNameOffset and put into SymbolNameOffset.
  187.             if (LIndex < LocalNameOffset.GetNumEntries()) {
  188.                SymbolNameIndex = LocalNameOffset[LIndex];
  189.             }
  190.             else SymbolNameIndex = 0;
  191.             SymbolNameOffset.Push(SymbolNameIndex);   // Save in name index table
  192.          }
  193.          if (rec.Index != rec.End) err.submit(1203);  // Check for consistency
  194.       }
  195.    }  // Point to next record
  196.    while (rec.GetNext());                        // End of loop through records
  197.  
  198.    NumRecords = Records.GetNumEntries();         // Number of records
  199.  
  200.    if (ChecksumZero) printf("\nChecksums are zero"); // This is taken out of the loop to report it only once
  201. }
  202.  
  203.  
  204. void COMF::Dump(int options) {
  205.    // Dump file
  206.    if (options & DUMP_FILEHDR) DumpRecordTypes(); // Dump summary of record types
  207.  
  208.    if (options & DUMP_STRINGTB) DumpNames(); // Dump names records
  209.  
  210.    if (options & DUMP_SYMTAB) DumpSymbols(); // Dump public/external name records  
  211.  
  212.    if (options & DUMP_SECTHDR) DumpSegments(); // Dump segment records
  213.  
  214.    if (options & DUMP_RELTAB) DumpRelocations(); // Dump fixup records
  215.  
  216.    if (options & DUMP_COMMENT) DumpComments(); // Dump coment records
  217. }
  218.  
  219. void COMF::DumpRecordTypes() {
  220.    // Dump summary of records
  221.    printf("\nSummary of records:");
  222.    for (uint32 i = 0; i < NumRecords; i++) {
  223.       // Print record type
  224.       printf("\n  Record %02X, %s%s, total length %i", Records[i].Type,
  225.          Lookup(OMFRecordTypeNames, Records[i].Type2),
  226.          (Records[i].Type & 1) ? ".32" : "",
  227.          Records[i].End+1);
  228.    }
  229. }
  230.  
  231.  
  232. void COMF::DumpNames() {
  233.    // Dump local names records
  234.    uint32 i;           // Record index
  235.    uint32 ln = 0;     // Local name index
  236.    printf("\n\nLocal names:");
  237.    for (i = 0; i < NumRecords; i++) {
  238.       if (Records[i].Type2 == OMF_LNAMES) {
  239.          // LNAMES record. There should be only one
  240.          // Loop through strings in record
  241.          while (Records[i].Index < Records[i].End) {
  242.             printf("\n  %2i  %s", ++ln, Records[i].GetString());
  243.          }
  244.          if (Records[i].Index != Records[i].End) err.submit(1203);   // Check for consistency
  245.       }
  246.  
  247.       if (Records[i].Type2 == OMF_THEADR || Records[i].Type2 == OMF_LHEADR) {
  248.          // Module header record
  249.          // Loop through strings in record
  250.          while (Records[i].Index < Records[i].End) {
  251.             printf("\n  Module: %s\n", Records[i].GetString());
  252.          }
  253.          if (Records[i].Index != Records[i].End) err.submit(1203);   // Check for consistency
  254.       }
  255.       if (Records[i].Type2 == OMF_COMDEF) {
  256.          // COMDEF record. Communal names
  257.          uint32 DType, DSize, DNum;
  258.          printf("\n\n Communal names:");
  259.  
  260.          // Loop through strings in record
  261.          while (Records[i].Index < Records[i].End) {
  262.             printf("\n  \"%s\":", Records[i].GetString());
  263.             printf(" %i", Records[i].GetByte()); // Type index, should be 0
  264.             DType = Records[i].GetByte(); // Data type            
  265.             switch (DType) {
  266.             case 0x61:
  267.                DNum  = Records[i].GetLength();
  268.                DSize = Records[i].GetLength();
  269.                printf(" FAR: %i*%i bytes", DNum, DSize);
  270.                break;
  271.             case 0x62:
  272.                DSize = Records[i].GetLength();
  273.                printf(" NEAR: 0x%X bytes", DSize);
  274.                break;
  275.             default:
  276.                DSize = Records[i].GetLength();
  277.                if (DType < 0x60) { // Borland segment index
  278.                   printf(" segment %i, size 0x%X", DType, DSize);
  279.                   break;
  280.                }
  281.                printf(" unknown type %i, size 0x%X", DType, DSize);
  282.                break;
  283.             }
  284.          }
  285.          if (Records[i].Index != Records[i].End) err.submit(1203);   // Check for consistency
  286.       }
  287.    }
  288. }
  289.  
  290. void COMF::DumpSymbols() {
  291.    // Dump public, external and communal names records
  292.    uint32 i;          // Record index
  293.    uint32 xn = 0;     // External name index
  294.    char * string;
  295.    uint32 TypeIndex;
  296.    uint32 Group;
  297.    uint32 Segment;
  298.    uint32 BaseFrame;
  299.    uint32 Offset;
  300.  
  301.    for (i = 0; i < NumRecords; i++) {
  302.       if (Records[i].Type2 == OMF_EXTDEF) {
  303.          // EXTDEF record.
  304.          Records[i].Index = 3;
  305.          printf("\n\nExternal names:");
  306.  
  307.          // Loop through strings in record
  308.          while (Records[i].Index < Records[i].End) {
  309.             string = Records[i].GetString();
  310.             TypeIndex = Records[i].GetIndex();
  311.             printf("\n  %2i  %s, Type %i", ++xn, string, TypeIndex);
  312.          }
  313.          if (Records[i].Index != Records[i].End) err.submit(1203);   // Check for consistency
  314.       }
  315.  
  316.       if (Records[i].Type2 == OMF_PUBDEF) {
  317.          // PUBDEF record.
  318.          printf("\n\nPublic names:");
  319.          Records[i].Index = 3;
  320.          Group = Records[i].GetIndex();
  321.          Segment = Records[i].GetIndex();
  322.          BaseFrame = 0;
  323.          if (Segment == 0) BaseFrame = Records[i].GetWord();
  324.          // Loop through strings in record
  325.          while (Records[i].Index < Records[i].End) {
  326.             string = Records[i].GetString();
  327.             Offset = Records[i].GetNumeric();
  328.             TypeIndex = Records[i].GetIndex();
  329.             printf("\n  %s, Segment %s, Group %s, Offset 0x%X, Type %i",
  330.                string, GetSegmentName(Segment), GetGroupName(Group), Offset, TypeIndex);
  331.             if (BaseFrame) printf(", Frame %i", BaseFrame);
  332.          }
  333.          if (Records[i].Index != Records[i].End) err.submit(1203);   // Check for consistency
  334.       }
  335.  
  336.       if (Records[i].Type2 == OMF_CEXTDEF) {
  337.          // CEXTDEF record.
  338.          printf("\n\nCommunal names:");
  339.          Records[i].Index = 3;
  340.          while (Records[i].Index < Records[i].End) {
  341.             uint32 LIndex = Records[i].GetIndex();    // Index into preceding LNAMES
  342.             uint32 Type = Records[i].GetIndex();      // Type index. Ignored
  343.             printf("\n  %2i  %s, Type %i", ++xn, GetLocalName(LIndex), Type);
  344.          }
  345.          if (Records[i].Index != Records[i].End) err.submit(1203);   // Check for consistency
  346.       }
  347.    }
  348. }
  349.  
  350.  
  351. void COMF::DumpSegments() {
  352.    // Dump all segment records
  353.  
  354.    // Define structure of attributes
  355.    OMF_SAttrib Attributes;
  356.  
  357.    // Record values
  358.    uint32 Frame, Offset, SegLength, NameIndex, ClassIndex, OverlayIndex;
  359.  
  360.    uint32 i;                                     // Record number
  361.    uint32 SegNum = 0;                            // Segment number
  362.    
  363.    printf("\n\nSegment records:");
  364.    for (i = 0; i < NumRecords; i++) {
  365.       if (Records[i].Type2 == OMF_SEGDEF) {
  366.          // SEGDEF record
  367.          Records[i].Index = 3;
  368.          // Loop through entries in record. There should be only 1
  369.          while (Records[i].Index < Records[i].End) {
  370.             Attributes.b = Records[i].GetByte();     // Read attributes
  371.             if (Attributes.u.A == 0) {
  372.                // Frame and Offset only included if A = 0
  373.                Frame = Records[i].GetWord();  Offset = Records[i].GetByte();
  374.             }
  375.             else Frame = Offset = 0;
  376.             SegLength    = Records[i].GetNumeric();
  377.             NameIndex    = Records[i].GetIndex();
  378.             ClassIndex   = Records[i].GetIndex();
  379.             OverlayIndex = Records[i].GetIndex();
  380.  
  381.             printf("\n  Segment %2i, Name %s, Class %s, Align %i, %s, %i bit",
  382.                ++SegNum, GetLocalName(NameIndex), GetLocalName(ClassIndex),
  383.                OMFAlignTranslate[Attributes.u.A],
  384.                Lookup(OMFSegmentCombinationNames, Attributes.u.C),
  385.                Attributes.u.P ? 32 : 16);
  386.             if (Attributes.u.B) printf(", big");
  387.             if (Attributes.u.A == 0) printf(", Frame %i, Offset 0x%X", Frame, Offset);
  388.             printf(", Length %i", SegLength);
  389.             if (OverlayIndex) printf("\n   Overlay %i", OverlayIndex);
  390.          }
  391.          if (Records[i].Index != Records[i].End) err.submit(1203);   // Check for consistency
  392.       }
  393.    }
  394.    printf("\n\nGroup records:");
  395.    for (i = 0; i < NumRecords; i++) {
  396.       if (Records[i].Type2 == OMF_GRPDEF) {
  397.          // GRPDEF record
  398.          Records[i].Index = 3;
  399.          ClassIndex = Records[i].GetIndex();
  400.          printf("\n  Group: %s\n   Segments:", GetLocalName(ClassIndex));
  401.  
  402.          // Loop through remaining entries in record
  403.          while (Records[i].Index < Records[i].End) {
  404.             uint8 Type = Records[i].GetByte();
  405.             if (Type != 0xFF) printf(" Type=%X:", Type);
  406.             NameIndex =  Records[i].GetIndex();
  407.             printf(" %s", GetSegmentName(NameIndex));
  408.          }
  409.          if (Records[i].Index != Records[i].End) err.submit(1203);   // Check for consistency
  410.       }
  411.    }
  412. }
  413.  
  414.  
  415. void COMF::DumpRelocations() {
  416.    // Dump all LEDATA, LIDATA, COMDAT and FIXUPP records
  417.    //uint32 LastDataRecord = 0;          // Index to the data record that relocations refer to
  418.    uint32 LastDataRecordSize = 0;      // Size of the data record that relocations refer to
  419.    int8 * LastDataRecordPointer = 0;   // Pointer to data in the data record that relocations refer to
  420.    uint32 i;                           // Loop counter
  421.    uint32 Segment, Offset, Size;       // Contents of LEDATA or LIDATA record
  422.    uint32 LastOffset = 0;              // Offset of last LEDATA or LIDATA record
  423.    uint32 Frame, Target, TargetDisplacement; // Contents of FIXUPP record
  424.    uint8 byte1, byte2;                 // First two bytes of subrecord
  425.  
  426.    // Bitfields in subrecords
  427.    OMF_SLocat Locat;         // Structure of first two bytes of FIXUP subrecord swapped = Locat field
  428.    OMF_SFixData FixData;     // Structure of FixData field in FIXUP subrecord of FIXUPP record
  429.    OMF_STrdDat TrdDat;       // Structure of Thread Data field in THREAD subrecord of FIXUPP record
  430.  
  431.    printf("\n\nLEDATA, LIDATA, COMDAT and FIXUPP records:");
  432.    for (i = 0; i < NumRecords; i++) {
  433.       if (Records[i].Type2 == OMF_LEDATA) {
  434.          // LEDATA record
  435.          Segment = Records[i].GetIndex();             // Read segment and offset
  436.          Offset  = Records[i].GetNumeric();
  437.          Size    = Records[i].End - Records[i].Index; // Calculate size of data
  438.          //LastDataRecord = i;                          // Save for later FIXUPP that refers to this record
  439.          LastDataRecordSize = Size;
  440.          LastDataRecordPointer = Records[i].buffer + Records[i].FileOffset + Records[i].Index;
  441.          if (Segment < 0x4000) {
  442.             printf("\n  LEDATA: segment %s, Offset 0x%X, Size 0x%X", // Dump segment, offset, size
  443.                GetSegmentName(Segment), Offset, Size);
  444.             LastOffset = Offset;
  445.          }
  446.          else { // Undocumented Borland communal section
  447.             printf("\n  LEDATA communal section %i, Offset 0x%X, Size 0x%X", // Dump segment, offset, size
  448.                (Segment & ~0x4000), Offset, Size);
  449.             LastOffset = Offset;
  450.          }
  451.       }
  452.  
  453.       if (Records[i].Type2 == OMF_LIDATA) {
  454.          // LIDATA record
  455.          Segment = Records[i].GetIndex();
  456.          Offset  = Records[i].GetNumeric();
  457.          //LastDataRecord = i;
  458.          LastDataRecordSize = Records[i].End - Records[i].Index; // Size before expansion of repeat blocks
  459.          LastDataRecordPointer = Records[i].buffer + Records[i].FileOffset + Records[i].Index;
  460.          printf("\n  LIDATA: segment %s, Offset 0x%X, Size ",
  461.             GetSegmentName(Segment), Offset);
  462.          // Call recursive function to interpret repeat data block
  463.          Size = Records[i].InterpretLIDATABlock();
  464.          printf(" = 0x%X", Size);
  465.          LastOffset = Offset;
  466.       }
  467.  
  468.       if (Records[i].Type2 == OMF_COMDAT) {
  469.          // COMDAT record
  470.          //uint32 Flags = Records[i].GetByte(); // 1 = continuation, 2 = iterated, 4 = local, 8 = data in code segment
  471.          uint32 Attributes = Records[i].GetByte();
  472.          uint32 Base = 0;
  473.          // 0 = explicit, 1 = far code, 2 = far data, 3 = code32, 4 = data32
  474.          // 0x00 = no match, 0x10 = pick any, 0x20 = same size, 0x30 = exact match
  475.          uint32 Align = Records[i].GetByte(); // Alignment
  476.          Offset  = Records[i].GetNumeric();    // Offset
  477.          uint32 TypeIndex = Records[i].GetIndex(); // Type index
  478.          if ((Attributes & 0x0F) == 0) {
  479.             Base = Records[i].GetIndex(); // Public base
  480.          }
  481.          uint32 NameIndex = Records[i].GetIndex(); // LNAMES index
  482.          Size    = Records[i].End - Records[i].Index; // Calculate size of data
  483.  
  484.          printf("\n  COMDAT: name %s, Offset 0x%X, Size 0x%X, Attrib 0x%02X, Align %i, Type %i, Base %i",
  485.             GetLocalName(NameIndex), Offset, Size, Attributes, Align, TypeIndex, Base);
  486.          LastOffset = Offset;
  487.       }
  488.  
  489.       if (Records[i].Type2 == OMF_FIXUPP) {
  490.          // FIXUPP record
  491.          printf("\n  FIXUPP:");
  492.          Records[i].Index = 3;
  493.  
  494.          // Loop through entries in record
  495.          while (Records[i].Index < Records[i].End) {
  496.  
  497.             // Read first byte
  498.             byte1 = Records[i].GetByte();
  499.             if (byte1 & 0x80) {
  500.                // This is a FIXUP subrecord
  501.                Frame = 0; Target = 0; TargetDisplacement = 0;
  502.  
  503.                // read second byte
  504.                byte2 = Records[i].GetByte();
  505.                // swap bytes and put into byte12 bitfield
  506.                Locat.bytes[1] = byte1;
  507.                Locat.bytes[0] = byte2;
  508.                // Read FixData
  509.                FixData.b = Records[i].GetByte();
  510.  
  511.                // print mode and location
  512.                printf("\n   %s %s, Offset 0x%X",
  513.                   Lookup(OMFRelocationModeNames, Locat.s.M),
  514.                   Lookup(OMFFixupLocationNames, Locat.s.Location),
  515.                   Locat.s.Offset + LastOffset);
  516.  
  517.                // Read conditional fields
  518.                if (FixData.s.F == 0) {
  519.                   if (FixData.s.Frame < 4) {
  520.                      Frame = Records[i].GetIndex();
  521.                   }
  522.                   else Frame = 0;
  523.  
  524.                   switch (FixData.s.Frame) { // Frame method
  525.                   case 0:  // F0: segment
  526.                      printf(", segment %s", GetSegmentName(Frame));  break;
  527.  
  528.                   case 1:  // F1: group
  529.                      printf(", group %s", GetGroupName(Frame));  break;
  530.  
  531.                   case 2:  // F2: external symbol
  532.                      printf(", external frame %s", GetSymbolName(Frame));  break;
  533.  
  534.                   case 4:  // F4: frame = source,
  535.                            // or Borland floating point emulation record (undocumented?)
  536.                      printf(", frame = source; or Borland f.p. emulation record");
  537.                      break;
  538.  
  539.                   case 5:  // F5: frame = target
  540.                      printf(", frame = target");  break;
  541.  
  542.                   default:
  543.                      printf(", target frame %i method F%i", Frame, FixData.s.Frame);
  544.                   }
  545.                }
  546.                else {
  547.                   printf(", frame uses thread %i", FixData.s.Frame);
  548.                }
  549.                
  550.                if (FixData.s.T == 0) {
  551.                   // Target specified
  552.                   Target = Records[i].GetIndex();
  553.                   uint32 TargetMethod = FixData.s.Target + FixData.s.P * 4;
  554.  
  555.                   switch (FixData.s.Target) { // = Target method modulo 4
  556.                   case 0: // T0 and T4: Target = segment
  557.                   case 1: // T1 and T5: Target = segment group
  558.                      printf(". Segment %s (T%i)",
  559.                         GetSegmentName(Target), TargetMethod);
  560.                      break;
  561.                   case 2: // T2 and T6: Target = external symbol
  562.                      printf(". Symbol %s (T%i)",
  563.                         GetSymbolName(Target), TargetMethod);
  564.                      break;
  565.                   default: // Unknown method
  566.                      printf(", target %i unknown method T%i", Target, TargetMethod);
  567.                   }
  568.                }
  569.                else {
  570.                   // Target specified in previous thread
  571.                   printf(", target uses thread %i", FixData.s.Target);
  572.                }
  573.  
  574.                if (FixData.s.P == 0) {
  575.                   TargetDisplacement = Records[i].GetNumeric();
  576.                   printf("\n    target displacement %i", TargetDisplacement);
  577.                }
  578.                // Get inline addend
  579.                if (LastDataRecordPointer && Locat.s.Offset < LastDataRecordSize) {
  580.                   int8 * inlinep = LastDataRecordPointer + Locat.s.Offset;
  581.                   switch (Locat.s.Location) {
  582.                   case 0: case 4:  // 8 bit
  583.                      printf(", inline 0x%X", *inlinep);  break;
  584.  
  585.                   case 1: case 2: case 5: // 16 bit
  586.                      printf(", inline 0x%X", *(int16*)inlinep);  break;
  587.  
  588.                   case 3: // 16+16 bit
  589.                      printf(", inline 0x%X:0x%X", *(int16*)(inlinep+2), *(int16*)inlinep);  break;
  590.  
  591.                   case 9: case 13: // 32 bit
  592.                      printf(", inline 0x%X", *(int32*)inlinep);  break;
  593.  
  594.                   case 6: case 11: // 16+32 bit
  595.                      printf(", inline 0x%X:0x%X", *(int16*)(inlinep+4), *(int32*)inlinep);  break;
  596.                   }
  597.                }
  598.             }
  599.             else {
  600.                // This is a THREAD subrecord
  601.                TrdDat.b = byte1;                 // Put byte into bitfield
  602.  
  603.                uint32 Index  = 0;
  604.                if (TrdDat.s.Method < 4) {
  605.                   Index  = Records[i].GetIndex(); // has index field if method < 4 ?
  606.                }
  607.                printf("\n   %s Thread %i. Method %s%i, index %i",
  608.                   (TrdDat.s.D ? "Frame" : "Target"), TrdDat.s.Thread,
  609.                   (TrdDat.s.D ? "F" : "T"), TrdDat.s.Method, Index);
  610.             }
  611.          } // Finished loop through subrecords
  612.          if (Records[i].Index != Records[i].End) err.submit(1203);   // Check for consistency
  613.       }
  614.    } // Finished loop through records
  615. }
  616.  
  617.  
  618. void COMF::DumpComments() {
  619.    // Dump COMENT records
  620.    uint32 i;           // Record index
  621.    int startindex;
  622.    printf("\n");
  623.    for (i = 0; i < NumRecords; i++) {
  624.       if (Records[i].Type2 == OMF_COMENT) {
  625.          // COMENT record
  626.          printf("\nCOMENT record:\n");
  627.          startindex = Records[i].Index;
  628.          // Print as hex
  629.          while (Records[i].Index < Records[i].End) {
  630.             printf("%02X ", Records[i].GetByte());
  631.          }
  632.          // Print again as string
  633.          Records[i].Index = startindex;
  634.          printf("\n");
  635.          while (Records[i].Index < Records[i].End) {
  636.             printf("%c ", Records[i].GetByte());
  637.          }
  638.          printf("\n");
  639.          if (Records[i].Index != Records[i].End) err.submit(1203);   // Check for consistency
  640.       }
  641.    }
  642. }
  643.  
  644.  
  645. void COMF::PublicNames(CMemoryBuffer * Strings, CSList<SStringEntry> * Index, int m) {
  646.    // Make list of public names
  647.    // Strings will receive ASCIIZ strings
  648.    // Index will receive records of type SStringEntry with Member = m
  649.    SOMFRecordPointer rec;                        // Current OMF record
  650.    char * string;                                // Symbol name
  651.    SStringEntry se;                              // String entry record to save
  652.  
  653.    // Initialize record pointer
  654.    rec.Start(Buf(), 0, GetDataSize());
  655.  
  656.    // Loop through records and search for PUBDEF records
  657.    do {
  658.       // Read record
  659.       if (rec.Type2 == OMF_PUBDEF) {
  660.  
  661.          // Public symbols definition found
  662.          rec.GetIndex(); // Read group
  663.          uint32 Segment = rec.GetIndex(); // Read segment
  664.          if (Segment == 0) rec.GetWord(); // Read base frame
  665.          // Loop through strings in record
  666.          while (rec.Index < rec.End) {
  667.             string = rec.GetString();  // Read name
  668.             rec.GetNumeric(); // Read offset
  669.             rec.GetIndex(); // Read type
  670.             // Make SStringEntry record
  671.             se.Member = m;
  672.             // Store name
  673.             se.String = Strings->PushString(string);
  674.             // Store name index
  675.             Index->Push(se);
  676.          }
  677.          if (rec.Index != rec.End) err.submit(1203);   // Check for consistency
  678.       }
  679.       if (rec.Type2 == OMF_CEXTDEF) {
  680.          // CEXTDEF record. Store communal symbol names
  681.          // Loop through entries in record
  682.          while (rec.Index < rec.End) {
  683.             uint32 LIndex = rec.GetIndex() - 1;  // Index into preceding LNAMES
  684.             rec.GetIndex();                      // Type index. Ignore
  685.             // Check if index valid
  686.             if (LIndex < LocalNameOffset.GetNumEntries()) {
  687.                // Make SStringEntry record
  688.                se.Member = m;
  689.                // Get name
  690.                char * name = GetLocalName(LIndex);
  691.                if (strlen(name) > 0) {
  692.                   // Store name
  693.                   se.String = Strings->PushString(name);
  694.                   // Store name index
  695.                   Index->Push(se);
  696.                }
  697.             }
  698.          }
  699.          if (rec.Index != rec.End) err.submit(1203);  // Check for consistency
  700.       }
  701.       if (rec.Type2 == OMF_LNAMES) {
  702.          // LNAMES record. Check if file has been parsed
  703.          if (Records.GetNumEntries() == 0) {
  704.             // ParseFile has not been called. We need to store LNAMES table because
  705.             // these names may be needed by subsequent EXTDEF records.
  706.             // Loop through strings in record
  707.             while (rec.Index < rec.End) {
  708.                char * LocalName = rec.GetString();
  709.                uint32 LocalNameIndex = NameBuffer.PushString(LocalName); // Store local name
  710.                LocalNameOffset.Push(LocalNameIndex);// Store local name index
  711.             }
  712.             if (rec.Index != rec.End) err.submit(1203);  // Check for consistency
  713.          }
  714.       }
  715.    } // Get next record
  716.    while (rec.GetNext());                        // End of loop through records
  717. }
  718.  
  719. char * COMF::GetLocalName(uint32 i) {
  720.    // Get section name or class name by name index
  721.     if (i == 0 || i >= LocalNameOffset.GetNumEntries())  {
  722.         i = NameBuffer.PushString("null");
  723.         return NameBuffer.Buf() + i;
  724.     }
  725.     return NameBuffer.Buf() + LocalNameOffset[i];
  726. }
  727.  
  728. uint32 COMF::GetLocalNameO(uint32 i) {
  729.    // Get section name or class by converting name index offset into NameBuffer
  730.    if (i > 0 && i < LocalNameOffset.GetNumEntries()) {
  731.       return LocalNameOffset[i];
  732.    }
  733.    return 0;
  734. }
  735.  
  736. const char * COMF::GetSegmentName(uint32 i) {
  737.    // Get section name by segment index
  738.    if (i == 0) return "none";
  739.    if ((i & 0xC000) == 0x4000) {
  740.       // Borland communal section
  741.       static char text[32];
  742.       sprintf(text, "communal section %i", i - 0x4000);
  743.       return text;
  744.    }
  745.    if (i <= NumRecords) {
  746.       return NameBuffer.Buf() + SegmentNameOffset[i];
  747.    }
  748.    return "?";
  749. }
  750.  
  751.  
  752. const char * COMF::GetSymbolName(uint32 i) {
  753.    // Get external symbol name by index
  754.    if (i == 0) return "null";
  755.    if (i < SymbolNameOffset.GetNumEntries()) {
  756.       return NameBuffer.Buf() + SymbolNameOffset[i];
  757.    }
  758.    // return "?";
  759.    // index out of range
  760.    static char temp[100];
  761.    sprintf(temp, "Unknown index %i", i);
  762.    return temp;
  763. }
  764.  
  765. const char * COMF::GetGroupName(uint32 i) {
  766.    // Get group name by index
  767.    if (i == 0) return "none";
  768.    if (i <= NumRecords) {
  769.       return NameBuffer.Buf() + GroupNameOffset[i];
  770.    }
  771.    return "?";
  772. }
  773.  
  774. const char * COMF::GetRecordTypeName(uint32 i) {
  775.    // Get record type name
  776.    return Lookup(OMFRecordTypeNames, i);
  777. }
  778.  
  779. // Member functions for parsing SOMFRecordPointer
  780. uint8  SOMFRecordPointer::GetByte() {
  781.    // Read next byte from buffer
  782.    return *(buffer + FileOffset + Index++);
  783. }
  784.  
  785. uint16 SOMFRecordPointer::GetWord() {
  786.    // Read next 16 bit word from buffer
  787.    uint16 x = *(uint16*)(buffer + FileOffset + Index);
  788.    Index += 2;
  789.    return x;
  790. }
  791.  
  792. uint32 SOMFRecordPointer::GetDword() {
  793.    // Read next 32 bit dword from buffer
  794.    uint32 x = *(uint32*)(buffer + FileOffset + Index);
  795.    Index += 4;
  796.    return x;
  797. }
  798.  
  799. uint32 SOMFRecordPointer::GetIndex() {
  800.    // Read byte or word, depending on sign of first byte
  801.    uint32 byte1, byte2;
  802.    byte1 = GetByte();
  803.    if (byte1 & 0x80) {
  804.       // Two byte index
  805.       byte2 = GetByte();
  806.       return ((byte1 & 0x7F) << 8) | byte2;
  807.    }
  808.    else {
  809.       // One byte index
  810.       return byte1;
  811.    }
  812. }
  813.  
  814. uint32 SOMFRecordPointer::GetNumeric(){
  815.    // Read word or dword, depending on record type even or odd
  816.    if (Type & 1) {
  817.       // Odd record type. Number is 32 bits
  818.       return GetDword();
  819.    }
  820.    else {
  821.       // Even record type. Number is 16 bit s
  822.       return GetWord();
  823.    }
  824. }
  825.  
  826. uint32 SOMFRecordPointer::GetLength() {
  827.    // Read 1, 2, 3 or 4 bytes, depending on value of first byte
  828.    uint32 x = GetByte();
  829.    switch (x) {
  830.    case 0x81: // 16-bit value
  831.       return GetWord();
  832.    case 0x82: // 24-bit value
  833.       x = GetWord();
  834.       return (GetByte() << 16) + x;
  835.    case 0x84: // 32-bit value
  836.       return GetDword();
  837.    default: // 8-bit value
  838.       if (x > 0x80) err.submit(1203);
  839.       return x;
  840.    }
  841. }
  842.  
  843. char * SOMFRecordPointer::GetString() {
  844.    // Read string and return as ASCIIZ string in static buffer
  845.    static char String[256];
  846.    uint8 Length = GetByte();
  847.    if (Length == 0 /*|| Length >= sizeof(String)*/) {
  848.       String[0] = 0;
  849.    }
  850.    else {
  851.       // Copy string
  852.       memcpy(String, buffer + FileOffset + Index, Length);
  853.       // Terminate by 0
  854.       String[Length] = 0;
  855.    }
  856.    // Point to next
  857.    Index += Length;
  858.  
  859.    return String;
  860. }
  861.  
  862. void SOMFRecordPointer::Start(int8 * Buffer, uint32 FileOffset, uint32 FileEnd) {
  863.    // Start scanning through records
  864.    this->buffer = Buffer;
  865.    this->FileOffset = FileOffset;
  866.    this->FileEnd = FileEnd;
  867.    Index = 0;
  868.    Type = GetByte();
  869.    Type2 = Type;  if (Type2 < OMF_LIBHEAD) Type2 &= ~1; // Make even
  870.    uint16 RecordSize = GetWord();
  871.    End = Index + RecordSize - 1;
  872.    if (FileOffset + RecordSize + 3 > FileEnd) err.submit(2301); // Extends beyond end of file
  873. }
  874.  
  875. uint8 SOMFRecordPointer::GetNext(uint32 align) {
  876.    // Get next record. Returns record type, made even. Returns 0 if finished
  877.    // align = alignment after MODEND records = page size. Applies to lib files only
  878.    FileOffset += End + 1;
  879.  
  880.    // Check if alignment needed
  881.    if (align > 1 && Type2 == OMF_MODEND) {
  882.       // Align after MODEND record in library
  883.       FileOffset = (FileOffset + align - 1) & - (int32)align;
  884.    }
  885.    if (FileOffset >= FileEnd) return 0;          // End of file
  886.    Index = 0;                                    // Start reading record
  887.    Type = GetByte();                             // Get record type
  888.    Type2 = Type;  if (Type2 < OMF_LIBHEAD) Type2 &= ~1; // Make even
  889.    uint16 RecordSize = GetWord();                // Get record size
  890.    End = Index + RecordSize - 1;                 // Point to checksum byte
  891.    if ((uint64)FileOffset + RecordSize + 3 > FileEnd) err.submit(2301); // Extends beyond end of file
  892.    return Type2;
  893. }
  894.  
  895. uint32 SOMFRecordPointer::InterpretLIDATABlock() {
  896.    // Interpret Data block in LIDATA record recursively
  897.    // Prints repeat count and returns total size
  898.    uint32 RepeatCount = GetNumeric();
  899.    uint32 BlockCount  = GetWord();
  900.    uint32 Size = 0;
  901.    printf("%i * ", RepeatCount);
  902.    if (BlockCount == 0) {
  903.       Size = GetByte();
  904.       Index += Size;
  905.       printf("%i", Size);
  906.       return RepeatCount * Size;
  907.    }
  908.    // Nested repeat blocks
  909.    printf("(");
  910.    for (uint32 i = 0; i < BlockCount; i++) {
  911.       // Recursion
  912.       Size += InterpretLIDATABlock();
  913.       if (i+1 < BlockCount) printf(" + ");
  914.    }
  915.    printf(")");
  916.    return RepeatCount * Size;
  917. }
  918.  
  919.  
  920. uint32 SOMFRecordPointer::UnpackLIDATABlock(int8 * destination, uint32 MaxSize) {
  921.    // Unpack Data block in LIDATA record recursively and store data at destination
  922.    uint32 RepeatCount = GetNumeric();            // Outer repeat count
  923.    uint32 BlockCount  = GetWord();               // Inner repeat count
  924.    uint32 Size = 0;                              // Size of data expanded so far
  925.    uint32 RSize;                                 // Size of recursively expanded data
  926.    uint32 SaveIndex;                             // Save Index for repetition
  927.    uint32 i, j;                                  // Loop counters
  928.    if (BlockCount == 0) {
  929.       // Contains one repeated block
  930.       Size = GetByte();                          // Size of repeated block
  931.       if (RepeatCount * Size > MaxSize) {
  932.          // Data outside allowed area
  933.          err.submit(2310);                       // Error message
  934.          Index += Size;                          // Point to after block
  935.          return 0;                               // No data stored
  936.       }
  937.  
  938.       // Loop RepeatCount times
  939.       for (i = 0; i < RepeatCount; i++) {
  940.          // copy data block into destination
  941.          memcpy(destination, buffer + FileOffset + Index, Size);
  942.          destination += Size;
  943.       }
  944.       Index += Size;                             // Point to after block
  945.       return RepeatCount * Size;                 // Size of expanded data
  946.    }
  947.    // Nested repeat blocks
  948.    SaveIndex = Index;
  949.    // Loop RepeatCount times
  950.    for (i = 0; i < RepeatCount; i++) {
  951.       // Go back and repeat unpacking
  952.       Index = SaveIndex;
  953.       // Loop BlockCount times
  954.       for (j = 0; j < BlockCount; j++) {
  955.          // Recursion
  956.          RSize = UnpackLIDATABlock(destination, MaxSize);
  957.          destination += RSize;
  958.          MaxSize -= RSize;
  959.          Size += RSize;
  960.       }
  961.    }
  962.    return Size;
  963. }
  964.  
  965.  
  966. // Members of COMFFileBuilder, class for building OMF files
  967. COMFFileBuilder::COMFFileBuilder() {
  968.    // Constructor
  969.    Index = 0;
  970. }
  971.  
  972. void COMFFileBuilder::StartRecord(uint8 type) {
  973.    // Start building new record
  974.    this->Type = type;                            // Save type
  975.    RecordStart = Index = GetDataSize();          // Remember start position
  976.    PutByte(Type);                                // Put type into record
  977.    PutWord(0);                                   // Reserve space for size, put in later
  978. }
  979.  
  980. void COMFFileBuilder::EndRecord() {
  981.    // Finish building current record
  982.    // Update length
  983.    Get<uint16>(RecordStart + 1) = GetSize() + 1;
  984.  
  985.    // Make checksum
  986.    int8 checksum = 0;
  987.    for (uint32 i = RecordStart; i < Index; i++) checksum += Buf()[i];
  988.    PutByte(-checksum);
  989.  
  990.    // Check size limit
  991.    if (GetSize() > 0x407) {
  992.       err.submit(9005);
  993.    }
  994. }
  995.  
  996. void COMFFileBuilder::PutByte(uint8 x) {
  997.    // Put byte into buffer
  998.    Push(&x, 1);
  999.    Index++;
  1000. }
  1001.  
  1002. void COMFFileBuilder::PutWord(uint16 x) {
  1003.    // Put 16 bit word into buffer
  1004.    Push(&x, 2);
  1005.    Index += 2;
  1006. }
  1007.  
  1008. void COMFFileBuilder::PutDword(uint32 x) {
  1009.    // Put 32 bit dword into buffer
  1010.    Push(&x, 4);
  1011.    Index += 4;
  1012. }
  1013.  
  1014. void COMFFileBuilder::PutIndex(uint32 x) {
  1015.    // Put byte or word into buffer (word if > 0x7F)
  1016.    if (x < 0x80) {
  1017.       // One byte
  1018.       PutByte(x);
  1019.    }
  1020.    else {
  1021.       // Two bytes
  1022.       if (x > 0x7fff) {
  1023.          err.submit(2303);             // Index out of range
  1024.       }
  1025.       PutByte((uint8)(x >> 8) | 0x80); // First byte = high byte | 0x80
  1026.       PutByte(uint8(x));               // Second byte = low byte
  1027.    }
  1028. }
  1029.  
  1030. void COMFFileBuilder::PutNumeric(uint32 x) {
  1031.    // Put word or dword into buffer, depending on type being even or odd
  1032.    if (Type & 1) {
  1033.       PutDword(x);                     // Type is odd, put 32 bits
  1034.    }
  1035.    else {
  1036.       if (x > 0xffff) err.submit(2304);// Index out of range
  1037.       PutWord(uint16(x));              // Type is even, put 16 bits
  1038.    }
  1039. }
  1040.  
  1041. void COMFFileBuilder::PutString(const char * s) {
  1042.    // Put ASCII string into buffer, preceded by size
  1043.    uint32 len = (uint32)strlen(s);     // Check length
  1044.    if (len > 255) {
  1045.       // String too long
  1046.       err.submit(1204, s);             // Issue warning
  1047.       len = 255;                       // Truncate string to 255 characters
  1048.    }
  1049.    PutByte(uint8(len));                // Store length
  1050.    Push(s, len);                       // Store len bytes
  1051.    Index += len;                       // Update index
  1052. }
  1053.  
  1054. void COMFFileBuilder::PutBinary(void * p, uint32 Size) {
  1055.    // Put binary data of any length
  1056.    if (Size > 1024) {err.submit(9000); Size = 1024;}  // 1024 bytes size limit
  1057.    Push(p, Size);
  1058.    Index += Size;
  1059. }
  1060.  
  1061. uint32 COMFFileBuilder::GetSize() {
  1062.    // Get size of data added so far
  1063.    if (Index <= RecordStart + 3) return 0;
  1064.    return Index - RecordStart - 3;     // Type and size fields not included in size
  1065. }
  1066.