/// <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> /// 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); } }
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); }