예제 #1
0
        /// <summary>
        /// Prepares the loaded form of the binary and the disassembly project.
        /// </summary>
        public bool Prepare()
        {
            if (!CreateMap())
            {
                mSegmentMap = null;
                return(false);
            }

            Debug.WriteLine("Segment map:");
            for (int i = 0; i < mSegmentMap.Count; i++)
            {
                SegmentMapEntry ent = mSegmentMap[i];
                if (ent == null)
                {
                    Debug.Assert(i == 0 || i == 1);     // initial hole and optional ~ExpressLoad
                    continue;
                }
                OmfSegment omfSeg = ent.Segment;
                Debug.WriteLine(i + " " + ent.Address.ToString("x6") + " SegNum=" + omfSeg.SegNum +
                                " '" + omfSeg.SegName + "'");

                Debug.Assert(i == ent.Segment.SegNum);
            }

            if (!GenerateDataAndProject())
            {
                mSegmentMap = null;
                return(false);
            }

            return(true);
        }
예제 #2
0
        /// <summary>
        /// Analyzes the contents of an OMF file as a library or non-library.
        /// </summary>
        private OmfSegment.ParseResult DoAnalyze(Formatter formatter, bool parseAsLibrary)
        {
            bool first  = true;
            int  offset = 0;
            int  len    = mFileData.Length;

            List <string> msgs = new List <string>();

            while (len > 0)
            {
                OmfSegment.ParseResult result = OmfSegment.ParseHeader(mFileData, offset,
                                                                       parseAsLibrary, msgs, out OmfSegment seg);
                if (result == OmfSegment.ParseResult.Success)
                {
                    if (!seg.ParseBody(formatter, msgs))
                    {
                        OmfSegment.AddErrorMsg(msgs, offset, "parsing of segment " +
                                               seg.SegNum + " '" + seg.SegName + "' incomplete");
                        //result = OmfSegment.ParseResult.Failure;
                    }
                }

                MessageList.Clear();
                foreach (string str in msgs)
                {
                    MessageList.Add(str);
                }

                if (result == OmfSegment.ParseResult.IsLibrary)
                {
                    // Need to start over in library mode.
                    Debug.WriteLine("Restarting in library mode");
                    return(result);
                }
                else if (result == OmfSegment.ParseResult.Failure)
                {
                    // Could be a library we failed to parse, could be a totally bad file.
                    // If we were on the first segment, fail immediately so we can retry as
                    // library.  If not, it's probably not a library (assuming the Library
                    // Dictionary segment appears first), but rather a partially-bad OMF.
                    if (first)
                    {
                        return(result);
                    }
                    break;
                }
                first = false;

                Debug.Assert(seg.FileLength > 0);

                SegmentList.Add(seg);
                offset += seg.FileLength;
                len    -= seg.FileLength;
                Debug.Assert(len >= 0);
            }

            Debug.WriteLine("Num segments = " + SegmentList.Count);
            return(OmfSegment.ParseResult.Success);
        }
예제 #3
0
 /// <summary>
 /// Adds one or more OmfReloc instances to the list to represent the provided record.
 /// </summary>
 /// <param name="omfSeg">Segment that contains the record.</param>
 /// <param name="omfRec">Record to add.</param>
 /// <param name="data">File data.</param>
 /// <param name="relocs">List of relocations.  New entries will be appended.</param>
 /// <returns>True on success.</returns>
 public static bool GenerateRelocs(OmfSegment omfSeg, OmfRecord omfRec, byte[] data,
                                   List <OmfReloc> relocs)
 {
     try {
         return(DoGenerateRelocs(omfSeg, omfRec, data, relocs));
     } catch (IndexOutOfRangeException ioore) {
         Debug.WriteLine("Caught IOORE during reloc gen (" + omfRec.Op + "): " +
                         ioore.Message);
         return(false);
     }
 }
예제 #4
0
 /// <summary>
 /// Creates a new OmfRecord instance from the data at the specified offset.
 /// </summary>
 /// <remarks>
 /// This does not catch segment boundary overruns, unless they happen to overrun
 /// the buffer entirely.  The caller should either pass in a buffer that holds the
 /// exact segment data, or check the return value for excess length.
 /// </remarks>
 /// <param name="data">Data to analyze.</param>
 /// <param name="offset">Offset of start of record.</param>
 /// <param name="version">OMF segment version number.</param>
 /// <param name="labLen">Label length, defined in OMF segment header.</param>
 /// <param name="msgs">Output message holder.</param>
 /// <param name="omfRec">New record instance.</param>
 /// <returns>True on success.</returns>
 public static bool ParseRecord(byte[] data, int offset,
                                OmfSegment.SegmentVersion version, int labLen, Formatter formatter,
                                List <string> msgs, out OmfRecord omfRec)
 {
     omfRec            = new OmfRecord();
     omfRec.FileOffset = offset;
     try {
         return(omfRec.DoParseRecord(data, offset, version, labLen, formatter, msgs));
     } catch (IndexOutOfRangeException ioore) {
         OmfSegment.AddErrorMsg(msgs, offset, "buffer overrun while parsing record");
         Debug.WriteLine("Exception thrown decoding record: " + ioore.Message);
         return(false);
     }
 }
예제 #5
0
        /// <summary>
        /// Parses an OMF segment header.  If successful, a new OmfSegment object is created.
        /// </summary>
        /// <param name="data">File data.</param>
        /// <param name="offset">Offset at which to start parsing.</param>
        /// <param name="parseAsLibrary">Set to true to parse the header as if it were part
        ///   of a library file.  Affects parsing of v1 headers.</param>
        /// <param name="msgs">Notes and errors generated by the parser.</param>
        /// <param name="segResult">Completed object, or null on failure.</param>
        /// <returns>Result code.</returns>
        public static ParseResult ParseHeader(byte[] data, int offset, bool parseAsLibrary,
                                              List <string> msgs, out OmfSegment segResult)
        {
            segResult = null;

            //Debug.WriteLine("PARSE offset=" + offset);

            Debug.Assert(offset < data.Length);
            if (data.Length - offset < MIN_HEADER_V0)
            {
                // Definitely too small.
                AddErrorMsg(msgs, offset, "remaining file space too small to hold segment");
                return(ParseResult.Failure);
            }

            OmfSegment newSeg = new OmfSegment();

            newSeg.mFileData  = data;
            newSeg.FileOffset = offset;

            // Start with the version number.  The meaning of everything else depends on this.
            int minLen, expectedDispName;

            switch (data[offset + 0x0f])
            {
            case 0:
                newSeg.Version   = SegmentVersion.v0_0;
                minLen           = MIN_HEADER_V0;
                expectedDispName = 0x24;
                break;

            case 1:
                newSeg.Version   = SegmentVersion.v1_0;
                minLen           = MIN_HEADER_V1;
                expectedDispName = 0x2c;
                break;

            case 2:
                newSeg.Version   = SegmentVersion.v2_0;
                minLen           = MIN_HEADER_V2;
                expectedDispName = 0x2c;
                break;

            default:
                // invalid version, this is probably not OMF
                AddErrorMsg(msgs, offset, "invalid segment type " + data[offset + 0x0f]);
                return(ParseResult.Failure);
            }
            if (data.Length - offset < minLen)
            {
                // Too small for this version of the header.
                AddErrorMsg(msgs, offset, "remaining file space too small to hold " +
                            newSeg.Version + " segment");
                return(ParseResult.Failure);
            }

            int blkByteCnt = RawData.GetWord(data, offset + 0x00, 4, false);

            newSeg.ResSpc = RawData.GetWord(data, offset + 0x04, 4, false);
            newSeg.Length = RawData.GetWord(data, offset + 0x08, 4, false);
            newSeg.LabLen = data[offset + 0x0d];
            int numLen = data[offset + 0x0e];

            newSeg.BankSize = RawData.GetWord(data, offset + 0x10, 4, false);
            int numSex, dispName;

            if (newSeg.Version == SegmentVersion.v0_0)
            {
                newSeg.Org   = RawData.GetWord(data, offset + 0x14, 4, false);
                newSeg.Align = RawData.GetWord(data, offset + 0x18, 4, false);
                numSex       = data[offset + 0x1c];
                // 7 unused bytes follow
                dispName = 0x24;
                if (newSeg.LabLen == 0)
                {
                    newSeg.DispData = dispName + data[offset + dispName];
                }
                else
                {
                    newSeg.DispData = dispName + LOAD_NAME_LEN;
                }
            }
            else
            {
                newSeg.BankSize = RawData.GetWord(data, offset + 0x10, 4, false);
                newSeg.Org      = RawData.GetWord(data, offset + 0x18, 4, false);
                newSeg.Align    = RawData.GetWord(data, offset + 0x1c, 4, false);
                numSex          = data[offset + 0x20];
                newSeg.LcBank   = data[offset + 0x21];  // v1.0 only
                newSeg.SegNum   = RawData.GetWord(data, offset + 0x22, 2, false);
                newSeg.Entry    = RawData.GetWord(data, offset + 0x24, 4, false);
                dispName        = RawData.GetWord(data, offset + 0x28, 2, false);
                newSeg.DispData = RawData.GetWord(data, offset + 0x2a, 2, false);
            }

            // The only way to detect a v2.1 segment is by checking DISPNAME.
            if (newSeg.Version == SegmentVersion.v2_0 && dispName > 0x2c)
            {
                newSeg.Version    = SegmentVersion.v2_1;
                expectedDispName += 4;

                if (data.Length - offset < minLen + 4)
                {
                    AddErrorMsg(msgs, offset, "remaining file space too small to hold " +
                                newSeg.Version + " segment");
                    return(ParseResult.Failure);
                }
                newSeg.TempOrg = RawData.GetWord(data, offset + 0x2c, 4, false);
            }

            // Extract Kind and its attributes.  The Orca/M 2.0 manual refers to the 1-byte
            // field in v0/v1 as "TYPE" and the 2-byte field as "KIND", but we're generally
            // following the GS/OS reference nomenclature.
            int kindByte, kindWord;

            if (newSeg.Version <= SegmentVersion.v1_0)
            {
                kindByte = data[offset + 0x0c];
                if (!Enum.IsDefined(typeof(SegmentKind), kindByte & 0x1f))
                {
                    // Example: Moria GS has a kind of $1F for its GLOBALS segment.
                    AddErrorMsg(msgs, offset, "invalid segment kind $" + kindByte.ToString("x2"));
                    return(ParseResult.Failure);
                }
                newSeg.Kind = (SegmentKind)(kindByte & 0x1f);

                int kindAttrs = 0;
                if ((kindByte & 0x20) != 0)
                {
                    kindAttrs |= (int)SegmentAttribute.PosnIndep;
                }
                if ((kindByte & 0x40) != 0)
                {
                    kindAttrs |= (int)SegmentAttribute.Private;
                }
                if ((kindByte & 0x80) != 0)
                {
                    kindAttrs |= (int)SegmentAttribute.Dynamic;
                }
                newSeg.Attrs = (SegmentAttribute)kindAttrs;
            }
            else
            {
                // Yank all the attribute bits out at once.  Don't worry about v2.0 vs. v2.1.
                kindWord = RawData.GetWord(data, offset + 0x14, 2, false);
                if (!Enum.IsDefined(typeof(SegmentKind), kindWord & 0x001f))
                {
                    AddErrorMsg(msgs, offset, "invalid segment kind $" + kindWord.ToString("x4"));
                    return(ParseResult.Failure);
                }
                newSeg.Kind  = (SegmentKind)(kindWord & 0x001f);
                newSeg.Attrs = (SegmentAttribute)(kindWord & 0xff00);
            }

            // If we found a library dictionary segment, and we're not currently handling the
            // file as a library, reject this and try again.
            if (newSeg.Kind == SegmentKind.LibraryDict && !parseAsLibrary)
            {
                AddInfoMsg(msgs, offset, "found Library Dictionary segment, retrying as library");
                return(ParseResult.IsLibrary);
            }

            // We've got the basic pieces.  Handle the block-vs-byte debacle.
            int  segLen;
            bool asBlocks = false;

            if (newSeg.Version == SegmentVersion.v0_0)
            {
                // Always block count.
                segLen   = blkByteCnt * DISK_BLOCK_SIZE;
                asBlocks = true;
            }
            else if (newSeg.Version >= SegmentVersion.v2_0)
            {
                // Always byte count.
                segLen = blkByteCnt;
            }
            else   /*v1.0*/
            {
                // Only Library files should treat the field as bytes.  We can eliminate Load
                // files by checking for a nonzero SegNum field, but there's no reliable way
                // to tell the difference between Object and Library while looking at a segment
                // in isolation.
                if (parseAsLibrary)
                {
                    segLen = blkByteCnt;
                }
                else
                {
                    segLen   = blkByteCnt * DISK_BLOCK_SIZE;
                    asBlocks = true;
                }
            }
            newSeg.RawFileLength = newSeg.FileLength = segLen;

            //
            // Perform validity checks.  If any of these fail, we're probably reading something
            // that isn't OMF (or, if this isn't the first segment, we might have gone off the
            // rails at some point).
            //

            if (numLen != 4)
            {
                AddErrorMsg(msgs, offset, "NUMLEN must be 4, was " + numLen);
                return(ParseResult.Failure);
            }
            if (numSex != 0)
            {
                AddErrorMsg(msgs, offset, "NUMSEX must be 0, was " + numSex);
                return(ParseResult.Failure);
            }
            if (offset + segLen > data.Length)
            {
                if (asBlocks && offset + segLen - data.Length < DISK_BLOCK_SIZE)
                {
                    // I have found a few examples (e.g. BRIDGE.S16 in Davex v1.23, SYSTEM:START
                    // on an old Paintworks GS disk) where the file's length doesn't fill out
                    // the last block in the file.  If we continue, and the segment actually
                    // does pass EOF, we'll fail while reading the records.
                    AddInfoMsg(msgs, offset,
                               "file EOF is not a multiple of 512; last segment may be truncated");
                    newSeg.FileLength = data.Length - offset;
                }
                else
                {
                    // Segment is longer than the file.  (This can happen easily in a static lib if
                    // we're not parsing it as such.)
                    AddErrorMsg(msgs, offset, "segment file length exceeds EOF (segLen=" + segLen +
                                ", remaining=" + (data.Length - offset) + ")");
                    return(ParseResult.Failure);
                }
            }
            if (dispName < expectedDispName || dispName > (segLen - LOAD_NAME_LEN))
            {
                AddErrorMsg(msgs, offset, "invalid DISPNAME " + dispName + " (expected " +
                            expectedDispName + ", segLen=" + segLen + ")");
                return(ParseResult.Failure);
            }
            if (newSeg.DispData < expectedDispName + LOAD_NAME_LEN ||
                newSeg.DispData > (segLen - 1))
            {
                AddErrorMsg(msgs, offset, "invalid DISPDATA " + newSeg.DispData + " (expected " +
                            (expectedDispName + LOAD_NAME_LEN) + ", segLen=" + segLen + ")");
                return(ParseResult.Failure);
            }
            if (newSeg.BankSize > 0x00010000)
            {
                AddErrorMsg(msgs, offset, "invalid BANKSIZE $" + newSeg.BankSize.ToString("x"));
                return(ParseResult.Failure);
            }
            if (newSeg.Align > 0x00010000)
            {
                AddErrorMsg(msgs, offset, "invalid ALIGN $" + newSeg.Align.ToString("x"));
                return(ParseResult.Failure);
            }

            if (newSeg.BankSize != 0x00010000 && newSeg.BankSize != 0)
            {
                // This is fine, just a little weird.
                AddInfoMsg(msgs, offset, "unusual BANKSIZE $" + newSeg.BankSize.ToString("x6"));
            }
            if (newSeg.Align != 0 && newSeg.Align != 0x0100 && newSeg.Align != 0x00010000)
            {
                // Unexpected; the loader will round up.
                AddInfoMsg(msgs, offset, "unusual ALIGN $" + newSeg.Align.ToString("x6"));
            }
            if (newSeg.Entry != 0 && newSeg.Entry >= newSeg.Length)
            {
                // This is invalid, but if we got this far we might as well keep going.
                AddInfoMsg(msgs, offset, "invalid ENTRY $" + newSeg.Entry.ToString("x6"));
            }

            // Extract LOADNAME.  Fixed-width field, padded with spaces.  Except for the
            // times when it's filled with zeroes instead.
            string loadName     = string.Empty;
            int    segNameStart = dispName;

            if (newSeg.Version != SegmentVersion.v0_0)
            {
                loadName      = ExtractString(data, offset + dispName, LOAD_NAME_LEN);
                segNameStart += LOAD_NAME_LEN;
            }

            // Extract SEGNAME.  May be fixed- or variable-width.
            string segName;

            if (newSeg.LabLen == 0)
            {
                // string preceded by length byte
                int segNameLen = data[offset + segNameStart];
                if (segNameStart + 1 + segNameLen > segLen)
                {
                    AddInfoMsg(msgs, offset, "var-width SEGNAME ran off end of segment (len=" +
                               segNameLen + ", segLen=" + segLen + ")");
                    return(ParseResult.Failure);
                }
                segName = Encoding.ASCII.GetString(data, offset + segNameStart + 1, segNameLen);
            }
            else
            {
                // fixed-width string
                if (segNameStart + newSeg.LabLen > segLen)
                {
                    AddInfoMsg(msgs, offset, "fixed-width SEGNAME ran off end of segment (LABLEN=" +
                               newSeg.LabLen + ", segLen=" + segLen + ")");
                    return(ParseResult.Failure);
                }
                segName = ExtractString(data, offset + segNameStart, newSeg.LabLen);
            }

            //AddInfoMsg(msgs, offset, "GOT LOADNAME='" + loadName + "' SEGNAME='" + segName + "'");

            newSeg.LoadName = loadName;
            newSeg.SegName  = segName;

            //
            // Populate the "raw data" table.  We add the fields shown in the specification in
            // the order in which they appear.
            //

            if (newSeg.Version == SegmentVersion.v0_0 ||
                (newSeg.Version == SegmentVersion.v1_0 && !parseAsLibrary))
            {
                newSeg.AddRaw("BLKCNT", blkByteCnt, 4, "blocks");
            }
            else
            {
                newSeg.AddRaw("BYTECNT", blkByteCnt, 4, "bytes");
            }
            newSeg.AddRaw("RESSPC", newSeg.ResSpc, 4, string.Empty);
            newSeg.AddRaw("LENGTH", newSeg.Length, 4, string.Empty);
            if (newSeg.Version <= SegmentVersion.v1_0)
            {
                string attrStr = AttrsToString(newSeg.Attrs);
                if (!string.IsNullOrEmpty(attrStr))
                {
                    attrStr = " -" + attrStr;
                }
                newSeg.AddRaw("KIND", data[offset + 0x0c], 1,
                              KindToString(newSeg.Kind) + attrStr);
            }
            else
            {
                newSeg.AddRaw("undefined", data[offset + 0x0c], 1, string.Empty);
            }
            newSeg.AddRaw("LABLEN", newSeg.LabLen, 1,
                          (newSeg.LabLen == 0 ? "variable length" : "fixed length"));
            newSeg.AddRaw("NUMLEN", numLen, 1, "must be 4");
            newSeg.AddRaw("VERSION", data[offset + 0x0f], 1, VersionToString(newSeg.Version));
            newSeg.AddRaw("BANKSIZE", newSeg.BankSize, 4, string.Empty);
            if (newSeg.Version >= SegmentVersion.v2_0)
            {
                string attrStr = AttrsToString(newSeg.Attrs);
                if (!string.IsNullOrEmpty(attrStr))
                {
                    attrStr = " -" + attrStr;
                }
                newSeg.AddRaw("KIND", RawData.GetWord(data, offset + 0x14, 2, false), 2,
                              KindToString(newSeg.Kind) + attrStr);
                newSeg.AddRaw("undefined", RawData.GetWord(data, offset + 0x16, 2, false), 2,
                              string.Empty);
            }
            else
            {
                newSeg.AddRaw("undefined", RawData.GetWord(data, offset + 0x14, 4, false), 4,
                              string.Empty);
            }
            newSeg.AddRaw("ORG", newSeg.Org, 4, (newSeg.Org != 0 ? "" : "relocatable"));
            // alignment is rounded up to page/bank
            string alignStr;

            if (newSeg.Align == 0)
            {
                alignStr = "no alignment";
            }
            else if (newSeg.Align <= 0x0100)
            {
                alignStr = "align to page";
            }
            else
            {
                alignStr = "align to bank";
            }
            newSeg.AddRaw("ALIGN", newSeg.Align, 4, alignStr);
            newSeg.AddRaw("NUMSEX", numSex, 1, "must be 0");
            if (newSeg.Version == SegmentVersion.v1_0)
            {
                newSeg.AddRaw("LCBANK", newSeg.LcBank, 1, string.Empty);
            }
            else
            {
                newSeg.AddRaw("undefined", data[offset + 0x21], 1, string.Empty);
            }
            if (newSeg.Version >= SegmentVersion.v1_0)
            {
                newSeg.AddRaw("SEGNUM", newSeg.SegNum, 2, string.Empty);
                newSeg.AddRaw("ENTRY", newSeg.Entry, 4, string.Empty);
                newSeg.AddRaw("DISPNAME", dispName, 2, string.Empty);
                newSeg.AddRaw("DISPDATA", newSeg.DispData, 2, string.Empty);
                if (newSeg.Version >= SegmentVersion.v2_1)
                {
                    newSeg.AddRaw("TEMPORG", newSeg.TempOrg, 4, string.Empty);
                }
                newSeg.AddRaw("LOADNAME", loadName, 10, string.Empty);
            }
            newSeg.AddRaw("SEGNAME", segName, 0, string.Empty);

            segResult = newSeg;
            return(ParseResult.Success);
        }
예제 #6
0
        /// <summary>
        /// Generates a series of relocation items for a SUPER record.
        /// </summary>
        private static bool GenerateRelocForSuper(OmfSegment omfSeg, OmfRecord omfRec, byte[] data,
                                                  List <OmfReloc> relocs)
        {
            int offset    = omfRec.FileOffset;
            int remaining = RawData.GetWord(data, offset + 1, 4, false);
            int type      = data[offset + 5];

            offset += 6;        // we've consumed 6 bytes
            remaining--;        // ...but only 1 counts against the SUPER length

            int  width, shift, fileNum, segNum;
            bool needSegNum = false;

            if (type == 0)
            {
                // SUPER RELOC2
                width   = 2;
                shift   = 0;
                fileNum = segNum = -1;
            }
            else if (type == 1)
            {
                // SUPER RELOC3
                width   = 3;
                shift   = 0;
                fileNum = segNum = -1;
            }
            else if (type >= 2 && type <= 13)
            {
                // SUPER INTERSEG1 - SUPER INTERSEG12
                width      = 3;
                shift      = 0;
                fileNum    = type - 1;
                segNum     = -100;
                needSegNum = true;
            }
            else if (type >= 14 && type <= 25)
            {
                // SUPER INTERSEG13 - SUPER INTERSEG24
                width   = 2;
                shift   = 0;
                fileNum = 1;
                segNum  = type - 13;
            }
            else if (type >= 26 && type <= 37)
            {
                // SUPER INTERSEG25 - SUPER INTERSEG36
                width   = 2;
                shift   = -16;      // right shift
                fileNum = 1;
                segNum  = type - 25;
            }
            else
            {
                return(false);
            }

            int page = 0;

            while (remaining > 0)
            {
                int patchCount = data[offset++];
                remaining--;

                if ((patchCount & 0x80) != 0)
                {
                    // high bit set, this is a skip-count
                    page += (patchCount & 0x7f);
                    continue;
                }
                patchCount++;       // zero means one patch
                while (patchCount-- != 0)
                {
                    int patchOff = data[offset++];
                    remaining--;

                    int relocOff = page * 256 + patchOff;

                    byte[] constData   = omfSeg.GetConstData();
                    int    relocRelOff = RawData.GetWord(constData, relocOff, 2, false);
                    if (needSegNum)
                    {
                        segNum = constData[relocOff + 2];
                    }

                    relocs.Add(new OmfReloc(width, shift, relocOff, relocRelOff,
                                            fileNum, segNum, type));
                }

                page++;
            }

            if (remaining < 0)
            {
                Debug.WriteLine("Ran off end of SUPER record");
                Debug.Assert(false);
                return(false);
            }

            return(true);
        }
예제 #7
0
        /// <summary>
        /// Adds one or more OmfReloc instances to the list to represent the provided record.
        /// </summary>
        private static bool DoGenerateRelocs(OmfSegment omfSeg, OmfRecord omfRec, byte[] data,
                                             List <OmfReloc> relocs)
        {
            int offset = omfRec.FileOffset;

            Debug.Assert(data[offset] == (int)omfRec.Op);
            switch (omfRec.Op)
            {
            case OmfRecord.Opcode.RELOC: {
                byte  width  = data[offset + 1];
                sbyte shift  = (sbyte)data[offset + 2];
                int   off    = RawData.GetWord(data, offset + 3, 4, false);
                int   relOff = RawData.GetWord(data, offset + 7, 4, false);
                relocs.Add(new OmfReloc(width, shift, off, relOff, -1));
            }
            break;

            case OmfRecord.Opcode.cRELOC: {
                byte  width  = data[offset + 1];
                sbyte shift  = (sbyte)data[offset + 2];
                int   off    = RawData.GetWord(data, offset + 3, 2, false);
                int   relOff = RawData.GetWord(data, offset + 5, 2, false);
                relocs.Add(new OmfReloc(width, shift, off, relOff, -1));
            }
            break;

            case OmfRecord.Opcode.INTERSEG: {
                byte  width   = data[offset + 1];
                sbyte shift   = (sbyte)data[offset + 2];
                int   off     = RawData.GetWord(data, offset + 3, 4, false);
                int   fileNum = RawData.GetWord(data, offset + 7, 2, false);
                int   segNum  = RawData.GetWord(data, offset + 9, 2, false);
                int   relOff  = RawData.GetWord(data, offset + 11, 4, false);
                relocs.Add(new OmfReloc(width, shift, off, relOff, fileNum, segNum, -1));
            }
            break;

            case OmfRecord.Opcode.cINTERSEG: {
                byte  width   = data[offset + 1];
                sbyte shift   = (sbyte)data[offset + 2];
                int   off     = RawData.GetWord(data, offset + 3, 2, false);
                int   fileNum = 1;
                int   segNum  = data[offset + 5];
                int   relOff  = RawData.GetWord(data, offset + 6, 2, false);
                relocs.Add(new OmfReloc(width, shift, off, relOff, fileNum, segNum, -1));
            }
            break;

            case OmfRecord.Opcode.SUPER:
                if (!GenerateRelocForSuper(omfSeg, omfRec, data, relocs))
                {
                    return(false);
                }
                break;

            default:
                Debug.Assert(false);
                return(false);
            }

            return(true);
        }
예제 #8
0
        private static string GetExpression(byte[] data, ref int offset, ref int len, int labLen,
                                            Formatter formatter, List <string> msgs)
        {
            StringBuilder sb = new StringBuilder();

            bool done = false;

            while (!done)
            {
                byte operVal = data[offset++];
                len++;

                // Generate an operand string, if appropriate.
                if (operVal > 0 && operVal < ExprStrs.Length)
                {
                    sb.Append(' ');
                    sb.Append(ExprStrs[operVal]);
                }
                else
                {
                    ExprOp oper = (ExprOp)operVal;
                    switch (oper)
                    {
                    case ExprOp.End:
                        done = true;
                        break;

                    case ExprOp.PushLocation:
                        sb.Append(" [loc]");
                        break;

                    case ExprOp.PushConstant: {
                        int val = GetNum(data, ref offset, ref len);
                        sb.Append(' ');
                        sb.Append(formatter.FormatHexValue(val, 4));
                    }
                    break;

                    case ExprOp.PushLabelWeak: {
                        string label = GetLabel(data, ref offset, ref len, labLen);
                        sb.Append(" weak:'");
                        sb.Append(label);
                        sb.Append("'");
                    }
                    break;

                    case ExprOp.PushLabelValue: {
                        string label = GetLabel(data, ref offset, ref len, labLen);
                        sb.Append(" '");
                        sb.Append(label);
                        sb.Append("'");
                    }
                    break;

                    case ExprOp.PushLabelLength: {
                        string label = GetLabel(data, ref offset, ref len, labLen);
                        sb.Append(" len:'");
                        sb.Append(label);
                        sb.Append("'");
                    }
                    break;

                    case ExprOp.PushLabelType: {
                        string label = GetLabel(data, ref offset, ref len, labLen);
                        sb.Append(" typ:'");
                        sb.Append(label);
                        sb.Append("'");
                    }
                    break;

                    case ExprOp.PushLabelCount: {
                        string label = GetLabel(data, ref offset, ref len, labLen);
                        sb.Append(" cnt:'");
                        sb.Append(label);
                        sb.Append("'");
                    }
                    break;

                    case ExprOp.PushRelOffset: {
                        int adj = GetNum(data, ref offset, ref len);
                        sb.Append(" rel:");
                        sb.Append(formatter.FormatAdjustment(adj));
                    }
                    break;

                    default:
                        OmfSegment.AddErrorMsg(msgs, offset,
                                               "Found unexpected expression operator " +
                                               formatter.FormatHexValue((int)oper, 2));
                        sb.Append("???");
                        break;
                    }
                }
            }

            if (sb.Length > 0)
            {
                sb.Remove(0, 1);        // remove leading space
            }
            return(sb.ToString());
        }
예제 #9
0
        /// <summary>
        /// Parses OMF record data.
        /// </summary>
        /// <param name="data">Data to analyze.</param>
        /// <param name="offset">Offset of start of record.</param>
        /// <param name="version">OMF segment version number.</param>
        /// <param name="labLen">Label length, defined in OMF segment header.</param>
        /// <param name="msgs">Output message holder.</param>
        /// <returns>Parse result code.</returns>
        private bool DoParseRecord(byte[] data, int offset,
                                   OmfSegment.SegmentVersion version, int labLen, Formatter formatter,
                                   List <string> msgs)
        {
            int len = 1;    // 1 byte for the opcode

            Opcode opcode = Op = (Opcode)data[offset++];

            OpName = opcode.ToString();
            Value  = string.Empty;

            if (opcode >= Opcode.CONST_start && opcode <= Opcode.CONST_end)
            {
                // length determined by opcode value
                int count = (int)opcode;
                len   += count;
                OpName = "CONST";
                Value  = count + " bytes of data";
            }
            else
            {
                switch (opcode)
                {
                case Opcode.END:
                    break;

                case Opcode.ALIGN: {
                    int val = GetNum(data, ref offset, ref len);
                    Value = formatter.FormatHexValue(val, 6);
                }
                break;

                case Opcode.ORG: {
                    int val = GetNum(data, ref offset, ref len);
                    Value = "loc " + formatter.FormatAdjustment(val);
                }
                break;

                case Opcode.RELOC: {
                    len += 1 + 1 + 4 + 4;                   // 10
                    int width      = data[offset];
                    int operandOff = RawData.GetWord(data, offset + 2, 4, false);
                    Value = width + " bytes @" + formatter.FormatHexValue(operandOff, 4);
                }
                break;

                case Opcode.INTERSEG: {
                    len += 1 + 1 + 4 + 2 + 2 + 4;           // 14
                    int width      = data[offset];
                    int operandOff = RawData.GetWord(data, offset + 2, 4, false);
                    int segNum     = RawData.GetWord(data, offset + 8, 2, false);
                    Value = width + " bytes @" + formatter.FormatHexValue(operandOff, 4) +
                            " (seg " + segNum + ")";
                }
                break;

                case Opcode.USING:
                case Opcode.STRONG: {
                    string label = GetLabel(data, ref offset, ref len, labLen);
                    Value = "'" + label + "'";
                }
                break;

                case Opcode.GLOBAL:
                case Opcode.LOCAL: {
                    string label = GetLabel(data, ref offset, ref len, labLen);
                    int    bytes;
                    byte   type;
                    byte   priv = 0;
                    if (version == OmfSegment.SegmentVersion.v0_0)
                    {
                        bytes   = data[offset];
                        type    = data[offset + 1];
                        offset += 2;
                        len    += 2;
                    }
                    else if (version == OmfSegment.SegmentVersion.v1_0)
                    {
                        bytes   = data[offset];
                        type    = data[offset + 1];
                        priv    = data[offset + 2];
                        offset += 3;
                        len    += 3;
                    }
                    else
                    {
                        bytes   = RawData.GetWord(data, offset, 2, false);
                        type    = data[offset + 2];
                        priv    = data[offset + 3];
                        offset += 4;
                        len    += 4;
                    }
                    Value = (char)type + " '" + label + "' " +
                            formatter.FormatHexValue(bytes, 4) +
                            ((priv == 0) ? "" : " private");
                }
                break;

                case Opcode.GEQU:
                case Opcode.EQU: {
                    string label = GetLabel(data, ref offset, ref len, labLen);
                    int    bytes;
                    byte   type;
                    byte   priv = 0;
                    if (version == OmfSegment.SegmentVersion.v0_0)
                    {
                        bytes   = data[offset];
                        type    = data[offset + 1];
                        offset += 2;
                        len    += 2;
                    }
                    else if (version == OmfSegment.SegmentVersion.v1_0)
                    {
                        bytes   = data[offset];
                        type    = data[offset + 1];
                        priv    = data[offset + 2];
                        offset += 3;
                        len    += 3;
                    }
                    else
                    {
                        bytes   = RawData.GetWord(data, offset, 2, false);
                        type    = data[offset + 2];
                        priv    = data[offset + 3];
                        offset += 4;
                        len    += 4;
                    }
                    string expr = GetExpression(data, ref offset, ref len, labLen,
                                                formatter, msgs);
                    Value = (char)type + " '" + label + "' " +
                            formatter.FormatHexValue(bytes, 4) +
                            ((priv == 0) ? "" : " private") + " = " + expr;
                }
                break;

                case Opcode.MEM: {
                    int addr1 = GetNum(data, ref offset, ref len);
                    int addr2 = GetNum(data, ref offset, ref len);
                    Value = formatter.FormatHexValue(addr1, 4) + ", " +
                            formatter.FormatHexValue(addr2, 4);
                }
                break;

                case Opcode.EXPR:
                case Opcode.ZEXPR:
                case Opcode.BEXPR:
                case Opcode.LEXPR: {
                    int cap = data[offset++];
                    len++;
                    string expr = GetExpression(data, ref offset, ref len, labLen,
                                                formatter, msgs);
                    Value = "(" + cap + ") " + expr;
                }
                break;

                case Opcode.RELEXPR: {
                    int cap = data[offset++];
                    len++;
                    int    rel  = GetNum(data, ref offset, ref len);
                    string expr = GetExpression(data, ref offset, ref len, labLen,
                                                formatter, msgs);
                    Value = "(" + cap + ") " + formatter.FormatAdjustment(rel) + " " + expr;
                }
                break;

                case Opcode.DS: {
                    int count = GetNum(data, ref offset, ref len);
                    Value = count + " bytes of $00";
                }
                break;

                case Opcode.LCONST: {
                    int count = GetNum(data, ref offset, ref len);
                    len  += count;
                    Value = count + " bytes of data";
                }
                break;

                case Opcode.cRELOC: {
                    len += 1 + 1 + 2 + 2;                   // 6
                    int width      = data[offset];
                    int operandOff = RawData.GetWord(data, offset + 2, 2, false);
                    Value = width + " bytes @" + formatter.FormatHexValue(operandOff, 4);
                }
                break;

                case Opcode.cINTERSEG: {
                    len += 1 + 1 + 2 + 1 + 2;               // 7
                    int width      = data[offset];
                    int operandOff = RawData.GetWord(data, offset + 2, 2, false);
                    int segNum     = data[offset + 4];
                    Value = width + " bytes @" + formatter.FormatHexValue(operandOff, 4) +
                            " (seg " + segNum + ")";
                }
                break;

                case Opcode.SUPER: {
                    int count = GetNum(data, ref offset, ref len);
                    int type  = data[offset];
                    len  += count;          // count includes type byte
                    Value = (count - 1) + " bytes, type=" +
                            formatter.FormatHexValue(type, 2);

                    if (type > 37)
                    {
                        OmfSegment.AddErrorMsg(msgs, offset,
                                               "found SUPER record with bogus type=$" + type.ToString("x2"));
                        // the length field allows us to skip it, so keep going
                    }
                }
                break;

                case Opcode.General:
                case Opcode.Experimental1:
                case Opcode.Experimental2:
                case Opcode.Experimental3:
                case Opcode.Experimental4: {
                    OmfSegment.AddInfoMsg(msgs, offset, "found unusual record type " +
                                          formatter.FormatHexValue((int)opcode, 2));
                    int count = GetNum(data, ref offset, ref len);
                    len += count;
                }
                break;

                case Opcode.unused_e9:
                case Opcode.unused_ea:
                case Opcode.unused_f8:
                case Opcode.unused_f9:
                case Opcode.unused_fa:
                // These are undefined, can't be parsed.
                default:
                    Debug.Assert(false);
                    return(false);
                }
            }
            Length = len;
            //Debug.WriteLine("REC +" + (offset-1).ToString("x6") + " " + this);

            return(true);
        }
예제 #10
0
 public SegmentMapEntry(OmfSegment omfSeg, int address)
 {
     Segment = omfSeg;
     Address = address;
 }