/// <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); }
/// <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); }
/// <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); } }
/// <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); } }
/// <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); }
/// <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); }
/// <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); }
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()); }
/// <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); }
public SegmentMapEntry(OmfSegment omfSeg, int address) { Segment = omfSeg; Address = address; }