mirror of
https://github.com/fadden/6502bench.git
synced 2025-02-18 08:30:28 +00:00
Progress toward OMF file handling
Added parsing of records from OMF segment bodies. These are displayed in the segment viewer window.
This commit is contained in:
parent
d1526e5f25
commit
fa500a2a49
@ -86,6 +86,7 @@
|
|||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Tools\ApplesoftToHtml.cs" />
|
<Compile Include="Tools\ApplesoftToHtml.cs" />
|
||||||
<Compile Include="Tools\Omf\OmfFile.cs" />
|
<Compile Include="Tools\Omf\OmfFile.cs" />
|
||||||
|
<Compile Include="Tools\Omf\OmfRecord.cs" />
|
||||||
<Compile Include="Tools\Omf\OmfSegment.cs" />
|
<Compile Include="Tools\Omf\OmfSegment.cs" />
|
||||||
<Compile Include="Tools\Omf\WpfGui\OmfSegmentViewer.xaml.cs">
|
<Compile Include="Tools\Omf\WpfGui\OmfSegmentViewer.xaml.cs">
|
||||||
<DependentUpon>OmfSegmentViewer.xaml</DependentUpon>
|
<DependentUpon>OmfSegmentViewer.xaml</DependentUpon>
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
using Asm65;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
@ -24,14 +25,18 @@ namespace SourceGen.Tools.Omf {
|
|||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// OMF files are a series of segments. There is no file header or identifying information.
|
/// OMF files are a series of segments. There is no file header or identifying information.
|
||||||
/// In some cases the length is expected to be a multiple of 512 bytes, in others it isn't.
|
/// In some cases the length is expected to be a multiple of 512 bytes, in others it isn't.
|
||||||
|
/// Each segment is comprised of a header, followed by a series of records.
|
||||||
///
|
///
|
||||||
/// There's no structural limitation on mixing and matching segments, whether different
|
/// There's no structural limitation on mixing and matching segments, whether different
|
||||||
/// versions or different types. The file format provides a structure in which various
|
/// versions or different types. The file format provides a structure in which various
|
||||||
/// things may be stored, but does not provide a way to tell an observer what is contained
|
/// things may be stored, but does not provide a way to tell an observer what is contained
|
||||||
/// within (the ProDOS file type is supposed to do that).
|
/// within (the ProDOS file type is supposed to do that). A given file may be a Load
|
||||||
|
/// file (handled by the System Loader), Object file (fed to a linker), Library file
|
||||||
|
/// (also fed to a linker), or Run-Time Library (used by both the linker and the loader).
|
||||||
///
|
///
|
||||||
/// References:
|
/// References:
|
||||||
/// - (OMF "v0" is documented in an Orca/M manual?)
|
/// - IIgs Orca/M 2.0 manual. Appendix B documents OMF v0, v1, and v2.1 Load files.
|
||||||
|
/// (This is included with Opus ][.)
|
||||||
/// - "Apple IIgs Programmer's Workshop Reference". Chapter 7, page 228, describes
|
/// - "Apple IIgs Programmer's Workshop Reference". Chapter 7, page 228, describes
|
||||||
/// OMF v1.0 and v2.0.
|
/// OMF v1.0 and v2.0.
|
||||||
/// - "Apple IIgs GS/OS Reference, for GS/OS System Software Version 5.0 and later".
|
/// - "Apple IIgs GS/OS Reference, for GS/OS System Software Version 5.0 and later".
|
||||||
@ -50,22 +55,6 @@ namespace SourceGen.Tools.Omf {
|
|||||||
public const int MIN_FILE_SIZE = OmfSegment.MIN_HEADER_V0;
|
public const int MIN_FILE_SIZE = OmfSegment.MIN_HEADER_V0;
|
||||||
public const int MAX_FILE_SIZE = (1 << 24) - 1; // cap at 16MB
|
public const int MAX_FILE_SIZE = (1 << 24) - 1; // cap at 16MB
|
||||||
|
|
||||||
// TODO:
|
|
||||||
// - has an overall file type (load, object, RTL)
|
|
||||||
// - determine with a prioritized series of "could this be ____" checks
|
|
||||||
// - holds list of OmfSegment
|
|
||||||
// - has a list of warnings and errors that arose during parsing
|
|
||||||
// - holds on to byte[] with data
|
|
||||||
// OmfSegment:
|
|
||||||
// - header (common data, plus name/value dict with version-specific fields for display)
|
|
||||||
// - ref back to OmfFile for byte[] access?
|
|
||||||
// - list of OmfRecord
|
|
||||||
// - file-type-specific stuff can be generated and cached in second pass, e.g.
|
|
||||||
// generate a full relocation dictionary for load files (can't do this until we
|
|
||||||
// know the overall file type, which we can't know until all segments have been
|
|
||||||
// processed a bit)
|
|
||||||
|
|
||||||
private byte[] mFileData;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Overall file contents, determined by analysis.
|
/// Overall file contents, determined by analysis.
|
||||||
@ -81,6 +70,7 @@ namespace SourceGen.Tools.Omf {
|
|||||||
}
|
}
|
||||||
public FileKind OmfFileKind { get; private set; }
|
public FileKind OmfFileKind { get; private set; }
|
||||||
|
|
||||||
|
private byte[] mFileData;
|
||||||
private bool mIsDamaged;
|
private bool mIsDamaged;
|
||||||
|
|
||||||
private List<OmfSegment> mSegmentList = new List<OmfSegment>();
|
private List<OmfSegment> mSegmentList = new List<OmfSegment>();
|
||||||
@ -102,13 +92,13 @@ namespace SourceGen.Tools.Omf {
|
|||||||
OmfFileKind = FileKind.Unknown;
|
OmfFileKind = FileKind.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Analyze() {
|
public void Analyze(Formatter formatter) {
|
||||||
OmfSegment.ParseResult result = DoAnalyze(false);
|
OmfSegment.ParseResult result = DoAnalyze(formatter, false);
|
||||||
if (result == OmfSegment.ParseResult.IsLibrary ||
|
if (result == OmfSegment.ParseResult.IsLibrary ||
|
||||||
result == OmfSegment.ParseResult.Failure) {
|
result == OmfSegment.ParseResult.Failure) {
|
||||||
// Failed; try again as a library.
|
// Failed; try again as a library.
|
||||||
List<string> firstFail = new List<string>(MessageList);
|
List<string> firstFail = new List<string>(MessageList);
|
||||||
result = DoAnalyze(true);
|
result = DoAnalyze(formatter, true);
|
||||||
if (result == OmfSegment.ParseResult.Failure) {
|
if (result == OmfSegment.ParseResult.Failure) {
|
||||||
// Failed both ways. Report the failures from the non-library attempt.
|
// Failed both ways. Report the failures from the non-library attempt.
|
||||||
MessageList = firstFail;
|
MessageList = firstFail;
|
||||||
@ -116,7 +106,7 @@ namespace SourceGen.Tools.Omf {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private OmfSegment.ParseResult DoAnalyze(bool parseAsLibrary) {
|
private OmfSegment.ParseResult DoAnalyze(Formatter formatter, bool parseAsLibrary) {
|
||||||
bool first = true;
|
bool first = true;
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
int len = mFileData.Length;
|
int len = mFileData.Length;
|
||||||
@ -124,8 +114,15 @@ namespace SourceGen.Tools.Omf {
|
|||||||
List<string> msgs = new List<string>();
|
List<string> msgs = new List<string>();
|
||||||
|
|
||||||
while (len > 0) {
|
while (len > 0) {
|
||||||
OmfSegment.ParseResult result = OmfSegment.ParseSegment(mFileData, offset,
|
OmfSegment.ParseResult result = OmfSegment.ParseHeader(mFileData, offset,
|
||||||
parseAsLibrary, msgs, out OmfSegment seg);
|
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();
|
MessageList.Clear();
|
||||||
foreach (string str in msgs) {
|
foreach (string str in msgs) {
|
||||||
@ -149,6 +146,7 @@ namespace SourceGen.Tools.Omf {
|
|||||||
first = false;
|
first = false;
|
||||||
|
|
||||||
Debug.Assert(seg.FileLength > 0);
|
Debug.Assert(seg.FileLength > 0);
|
||||||
|
|
||||||
mSegmentList.Add(seg);
|
mSegmentList.Add(seg);
|
||||||
offset += seg.FileLength;
|
offset += seg.FileLength;
|
||||||
len -= seg.FileLength;
|
len -= seg.FileLength;
|
||||||
|
505
SourceGen/Tools/Omf/OmfRecord.cs
Normal file
505
SourceGen/Tools/Omf/OmfRecord.cs
Normal file
@ -0,0 +1,505 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 faddenSoft
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
using Asm65;
|
||||||
|
using CommonUtil;
|
||||||
|
|
||||||
|
namespace SourceGen.Tools.Omf {
|
||||||
|
/// <summary>
|
||||||
|
/// Apple IIgs OMF record.
|
||||||
|
/// </summary>
|
||||||
|
public class OmfRecord {
|
||||||
|
private const int NUMLEN = 4; // defined by NUMLEN field in header; always 4 for IIgs
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Total length, in bytes, of this record.
|
||||||
|
/// </summary>
|
||||||
|
public int Length { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Opcode.
|
||||||
|
/// </summary>
|
||||||
|
public Opcode Op { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Opcode, in human-readable form.
|
||||||
|
/// </summary>
|
||||||
|
public string OpName { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Value, in human-readable form.
|
||||||
|
/// </summary>
|
||||||
|
public string Value { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Opcode byte definition.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Nearly all of the 256 possible values are assigned. 5 are unused, 5 are reserved.
|
||||||
|
/// </remarks>
|
||||||
|
public enum Opcode : byte {
|
||||||
|
END = 0x00, // all
|
||||||
|
CONST_start = 0x01, // object
|
||||||
|
CONST_end = 0xdf, // object
|
||||||
|
ALIGN = 0xe0, // object
|
||||||
|
ORG = 0xe1, // object
|
||||||
|
RELOC = 0xe2, // load
|
||||||
|
INTERSEG = 0xe3, // load
|
||||||
|
USING = 0xe4, // object
|
||||||
|
STRONG = 0xe5, // object
|
||||||
|
GLOBAL = 0xe6, // object
|
||||||
|
GEQU = 0xe7, // object
|
||||||
|
MEM = 0xe8, // object ("not needed or supported on the Apple IIgs")
|
||||||
|
unused_e9 = 0xe9,
|
||||||
|
unused_ea = 0xea,
|
||||||
|
EXPR = 0xeb, // object
|
||||||
|
ZEXPR = 0xec, // object
|
||||||
|
BEXPR = 0xed, // object
|
||||||
|
RELEXPR = 0xee, // object
|
||||||
|
LOCAL = 0xef, // object
|
||||||
|
EQU = 0xf0, // object
|
||||||
|
DS = 0xf1, // all
|
||||||
|
LCONST = 0xf2, // all
|
||||||
|
LEXPR = 0xf3, // object
|
||||||
|
ENTRY = 0xf4, // RTL
|
||||||
|
cRELOC = 0xf5, // load
|
||||||
|
cINTERSEG = 0xf6, // load
|
||||||
|
SUPER = 0xf7, // load
|
||||||
|
unused_f8 = 0xf8,
|
||||||
|
unused_f9 = 0xf9,
|
||||||
|
unused_fa = 0xfa,
|
||||||
|
General = 0xfb, // reserved
|
||||||
|
Experimental1 = 0xfc, // reserved
|
||||||
|
Experimental2 = 0xfd, // reserved
|
||||||
|
Experimental3 = 0xfe, // reserved
|
||||||
|
Experimental4 = 0xff, // reserved
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private OmfRecord() { }
|
||||||
|
|
||||||
|
/// <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();
|
||||||
|
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 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);
|
||||||
|
len += count;
|
||||||
|
Value = (count - 1) + " bytes, type=" +
|
||||||
|
formatter.FormatHexValue(data[offset + NUMLEN], 2);
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int GetNum(byte[] data, ref int offset, ref int len) {
|
||||||
|
int val = RawData.GetWord(data, offset, NUMLEN, false);
|
||||||
|
offset += NUMLEN;
|
||||||
|
len += NUMLEN;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetLabel(byte[] data, ref int offset, ref int len, int labLen) {
|
||||||
|
if (labLen == 0) {
|
||||||
|
labLen = data[offset++];
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
string str = Encoding.ASCII.GetString(data, offset, labLen).Trim();
|
||||||
|
offset += labLen;
|
||||||
|
len += labLen;
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Expression operations.
|
||||||
|
/// </summary>
|
||||||
|
private enum ExprOp : byte {
|
||||||
|
End = 0x00,
|
||||||
|
Addition = 0x01,
|
||||||
|
Subtraction = 0x02,
|
||||||
|
Multiplication = 0x03,
|
||||||
|
Division = 0x04,
|
||||||
|
IntegerRemainder = 0x05,
|
||||||
|
UnaryNegation = 0x06,
|
||||||
|
BitShift = 0x07,
|
||||||
|
AND = 0x08,
|
||||||
|
OR = 0x09,
|
||||||
|
EOR = 0x0a,
|
||||||
|
NOT = 0x0b,
|
||||||
|
LessThenEqualTo = 0x0c,
|
||||||
|
GreaterThanEqualTo = 0x0d,
|
||||||
|
NotEqual = 0x0e,
|
||||||
|
LessThan = 0x0f,
|
||||||
|
GreaterThan = 0x10,
|
||||||
|
EqualTo = 0x11,
|
||||||
|
BitAND = 0x12,
|
||||||
|
BitOR = 0x13,
|
||||||
|
BitEOR = 0x14,
|
||||||
|
BitNOT = 0x15,
|
||||||
|
|
||||||
|
PushLocation = 0x80,
|
||||||
|
PushConstant = 0x81,
|
||||||
|
PushLabelWeak = 0x82,
|
||||||
|
PushLabelValue = 0x83,
|
||||||
|
PushLabelLength = 0x84,
|
||||||
|
PushLabelType = 0x85,
|
||||||
|
PushLabelCount = 0x86,
|
||||||
|
PushRelOffset = 0x87,
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly string[] ExprStrs = new string[] {
|
||||||
|
string.Empty, // 0x00 End
|
||||||
|
"+", // 0x01 Addition
|
||||||
|
"-", // 0x02 Subtraction
|
||||||
|
"*", // 0x03 Multiplication
|
||||||
|
"/", // 0x04 Division
|
||||||
|
"%", // 0x05 Integer Remainder
|
||||||
|
"neg", // 0x06 Unary Negation
|
||||||
|
"shift", // 0x07 Bit Shift
|
||||||
|
"&&", // 0x08 AND
|
||||||
|
"||", // 0x09 OR
|
||||||
|
"^^", // 0x0a EOR
|
||||||
|
"!", // 0x0b NOT
|
||||||
|
"<=", // 0x0c LE
|
||||||
|
">=", // 0x0d GE
|
||||||
|
"!=", // 0x0e NE
|
||||||
|
"<", // 0x0f LT
|
||||||
|
">", // 0x10 GT
|
||||||
|
"==", // 0x11 EQ
|
||||||
|
"&", // 0x12 Bit AND
|
||||||
|
"|", // 0x13 Bit OR
|
||||||
|
"^", // 0x14 Bit EOR
|
||||||
|
"~", // 0x15 Bit NOT
|
||||||
|
};
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() {
|
||||||
|
return Length + " " + OpName + " " + Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -15,13 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Specialized;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Input;
|
|
||||||
|
|
||||||
|
using Asm65;
|
||||||
using CommonUtil;
|
using CommonUtil;
|
||||||
|
|
||||||
namespace SourceGen.Tools.Omf {
|
namespace SourceGen.Tools.Omf {
|
||||||
@ -42,7 +39,7 @@ namespace SourceGen.Tools.Omf {
|
|||||||
///
|
///
|
||||||
/// Most IIgs binaries are v1.0 or v2.0.
|
/// Most IIgs binaries are v1.0 or v2.0.
|
||||||
///
|
///
|
||||||
/// You'd hope that parsing a segment would be unambiguous, but that is not the case.
|
/// You'd hope that parsing segments would be unambiguous, but that is not the case.
|
||||||
/// From the same reference:
|
/// From the same reference:
|
||||||
///
|
///
|
||||||
/// "In Version 1.0, [the first] field is described as follows. For object files
|
/// "In Version 1.0, [the first] field is described as follows. For object files
|
||||||
@ -59,7 +56,7 @@ namespace SourceGen.Tools.Omf {
|
|||||||
///
|
///
|
||||||
/// Documentation bugs:
|
/// Documentation bugs:
|
||||||
/// - GS/OS ref: table F-2 says "blockCount" where it should say "SEGNAME", and shows the
|
/// - GS/OS ref: table F-2 says "blockCount" where it should say "SEGNAME", and shows the
|
||||||
/// offset of tempOrg as $2a (should be $2c).
|
/// offset of "tempOrg" as $2a (should be $2c).
|
||||||
/// - GS/OS ref: appendix F refers to a "REVISION" field, which does not seem to exist.
|
/// - GS/OS ref: appendix F refers to a "REVISION" field, which does not seem to exist.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public class OmfSegment {
|
public class OmfSegment {
|
||||||
@ -70,7 +67,7 @@ namespace SourceGen.Tools.Omf {
|
|||||||
public const int MIN_HEADER_V1 = MIN_HEADER_V0 + 8 + LOAD_NAME_LEN;
|
public const int MIN_HEADER_V1 = MIN_HEADER_V0 + 8 + LOAD_NAME_LEN;
|
||||||
// v2.0: Updated IIgs OMF format. Removes LCBANK, redefines KIND, and embraces BYTECNT.
|
// v2.0: Updated IIgs OMF format. Removes LCBANK, redefines KIND, and embraces BYTECNT.
|
||||||
public const int MIN_HEADER_V2 = MIN_HEADER_V1 + 4;
|
public const int MIN_HEADER_V2 = MIN_HEADER_V1 + 4;
|
||||||
// v2.1: adds tempORG and a couple of attribute flags. No "min" constant needed.
|
// v2.1: adds TEMPORG and a couple of attribute flags. No "min" constant needed.
|
||||||
|
|
||||||
// Length of LOADNAME field.
|
// Length of LOADNAME field.
|
||||||
private const int LOAD_NAME_LEN = 10;
|
private const int LOAD_NAME_LEN = 10;
|
||||||
@ -122,15 +119,17 @@ namespace SourceGen.Tools.Omf {
|
|||||||
Dynamic = 0x8000 //
|
Dynamic = 0x8000 //
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private byte[] mFileData;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Header fields.
|
// Header fields and header-derived values.
|
||||||
//
|
//
|
||||||
|
|
||||||
public int FileOffset { get; private set; }
|
public int FileOffset { get; private set; }
|
||||||
public int FileLength { get; private set; } // from BLKCNT or BYTECNT
|
public int FileLength { get; private set; } // from BLKCNT or BYTECNT
|
||||||
|
|
||||||
public int ResSpc { get; private set; }
|
public int ResSpc { get; private set; }
|
||||||
public int Length { get; private set; }
|
public int Length { get; private set; }
|
||||||
public int Type { get; private set; }
|
|
||||||
public int LabLen { get; private set; }
|
public int LabLen { get; private set; }
|
||||||
public SegmentVersion Version { get; private set; }
|
public SegmentVersion Version { get; private set; }
|
||||||
public int BankSize { get; private set; }
|
public int BankSize { get; private set; }
|
||||||
@ -141,7 +140,8 @@ namespace SourceGen.Tools.Omf {
|
|||||||
public int LcBank { get; private set; } // v1.0 only
|
public int LcBank { get; private set; } // v1.0 only
|
||||||
public int SegNum { get; private set; }
|
public int SegNum { get; private set; }
|
||||||
public int Entry { get; private set; }
|
public int Entry { get; private set; }
|
||||||
public int TempOrg { get; private set; } // v2.1 only
|
public int DispData { get; private set; }
|
||||||
|
public int TempOrg { get; private set; } // v2.1; only used by MPW IIgs
|
||||||
public string LoadName { get; private set; } // unused in load segments
|
public string LoadName { get; private set; } // unused in load segments
|
||||||
public string SegName { get; private set; }
|
public string SegName { get; private set; }
|
||||||
|
|
||||||
@ -155,6 +155,10 @@ namespace SourceGen.Tools.Omf {
|
|||||||
// "The BANKSIZE and align restrictions are enforced by the linker, and violations
|
// "The BANKSIZE and align restrictions are enforced by the linker, and violations
|
||||||
// of them are unlikely in a load file."
|
// of them are unlikely in a load file."
|
||||||
|
|
||||||
|
public List<OmfRecord> Records = new List<OmfRecord>();
|
||||||
|
|
||||||
|
|
||||||
|
// Constructor is private; use ParseHeader() to create an instance.
|
||||||
private OmfSegment() { }
|
private OmfSegment() { }
|
||||||
|
|
||||||
public enum ParseResult {
|
public enum ParseResult {
|
||||||
@ -165,7 +169,7 @@ namespace SourceGen.Tools.Omf {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Parses an OMF segment header.
|
/// Parses an OMF segment header. If successful, a new OmfSegment object is created.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="data">File data.</param>
|
/// <param name="data">File data.</param>
|
||||||
/// <param name="offset">Offset at which to start parsing.</param>
|
/// <param name="offset">Offset at which to start parsing.</param>
|
||||||
@ -174,7 +178,7 @@ namespace SourceGen.Tools.Omf {
|
|||||||
/// <param name="msgs">Notes and errors generated by the parser.</param>
|
/// <param name="msgs">Notes and errors generated by the parser.</param>
|
||||||
/// <param name="segResult">Completed object, or null on failure.</param>
|
/// <param name="segResult">Completed object, or null on failure.</param>
|
||||||
/// <returns>Result code.</returns>
|
/// <returns>Result code.</returns>
|
||||||
public static ParseResult ParseSegment(byte[] data, int offset, bool parseAsLibrary,
|
public static ParseResult ParseHeader(byte[] data, int offset, bool parseAsLibrary,
|
||||||
List<string> msgs, out OmfSegment segResult) {
|
List<string> msgs, out OmfSegment segResult) {
|
||||||
segResult = null;
|
segResult = null;
|
||||||
|
|
||||||
@ -188,6 +192,7 @@ namespace SourceGen.Tools.Omf {
|
|||||||
}
|
}
|
||||||
|
|
||||||
OmfSegment newSeg = new OmfSegment();
|
OmfSegment newSeg = new OmfSegment();
|
||||||
|
newSeg.mFileData = data;
|
||||||
newSeg.FileOffset = offset;
|
newSeg.FileOffset = offset;
|
||||||
|
|
||||||
// Start with the version number. The meaning of everything else depends on this.
|
// Start with the version number. The meaning of everything else depends on this.
|
||||||
@ -229,20 +234,20 @@ namespace SourceGen.Tools.Omf {
|
|||||||
newSeg.Org = RawData.GetWord(data, offset + 0x18, 4, false);
|
newSeg.Org = RawData.GetWord(data, offset + 0x18, 4, false);
|
||||||
newSeg.Align = RawData.GetWord(data, offset + 0x1c, 4, false);
|
newSeg.Align = RawData.GetWord(data, offset + 0x1c, 4, false);
|
||||||
int numSex = data[offset + 0x20];
|
int numSex = data[offset + 0x20];
|
||||||
int dispName, dispData;
|
int dispName;
|
||||||
if (newSeg.Version == SegmentVersion.v0_0) {
|
if (newSeg.Version == SegmentVersion.v0_0) {
|
||||||
dispName = 0x24;
|
dispName = 0x24;
|
||||||
if (newSeg.LabLen == 0) {
|
if (newSeg.LabLen == 0) {
|
||||||
dispData = dispName + data[offset + dispName];
|
newSeg.DispData = dispName + data[offset + dispName];
|
||||||
} else {
|
} else {
|
||||||
dispData = dispName + LOAD_NAME_LEN;
|
newSeg.DispData = dispName + LOAD_NAME_LEN;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
newSeg.LcBank = data[offset + 0x21];
|
newSeg.LcBank = data[offset + 0x21];
|
||||||
newSeg.SegNum = RawData.GetWord(data, offset + 0x22, 2, false);
|
newSeg.SegNum = RawData.GetWord(data, offset + 0x22, 2, false);
|
||||||
newSeg.Entry = RawData.GetWord(data, offset + 0x24, 4, false);
|
newSeg.Entry = RawData.GetWord(data, offset + 0x24, 4, false);
|
||||||
dispName = RawData.GetWord(data, offset + 0x28, 2, false);
|
dispName = RawData.GetWord(data, offset + 0x28, 2, false);
|
||||||
dispData = RawData.GetWord(data, offset + 0x2a, 2, false);
|
newSeg.DispData = RawData.GetWord(data, offset + 0x2a, 2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The only way to detect a v2.1 segment is by checking DISPNAME.
|
// The only way to detect a v2.1 segment is by checking DISPNAME.
|
||||||
@ -349,8 +354,9 @@ namespace SourceGen.Tools.Omf {
|
|||||||
expectedDispName + ", segLen=" + segLen + ")");
|
expectedDispName + ", segLen=" + segLen + ")");
|
||||||
return ParseResult.Failure;
|
return ParseResult.Failure;
|
||||||
}
|
}
|
||||||
if (dispData < expectedDispName + LOAD_NAME_LEN || dispData > (segLen - 1)) {
|
if (newSeg.DispData < expectedDispName + LOAD_NAME_LEN ||
|
||||||
AddErrorMsg(msgs, offset, "invalid DISPDATA " + dispData + " (expected " +
|
newSeg.DispData > (segLen - 1)) {
|
||||||
|
AddErrorMsg(msgs, offset, "invalid DISPDATA " + newSeg.DispData + " (expected " +
|
||||||
(expectedDispName + LOAD_NAME_LEN) + ", segLen=" + segLen + ")");
|
(expectedDispName + LOAD_NAME_LEN) + ", segLen=" + segLen + ")");
|
||||||
return ParseResult.Failure;
|
return ParseResult.Failure;
|
||||||
}
|
}
|
||||||
@ -463,9 +469,9 @@ namespace SourceGen.Tools.Omf {
|
|||||||
newSeg.AddRaw("SEGNUM", newSeg.SegNum, 2, string.Empty);
|
newSeg.AddRaw("SEGNUM", newSeg.SegNum, 2, string.Empty);
|
||||||
newSeg.AddRaw("ENTRY", newSeg.Entry, 4, string.Empty);
|
newSeg.AddRaw("ENTRY", newSeg.Entry, 4, string.Empty);
|
||||||
newSeg.AddRaw("DISPNAME", dispName, 2, string.Empty);
|
newSeg.AddRaw("DISPNAME", dispName, 2, string.Empty);
|
||||||
newSeg.AddRaw("DISPDATA", dispData, 2, string.Empty);
|
newSeg.AddRaw("DISPDATA", newSeg.DispData, 2, string.Empty);
|
||||||
if (newSeg.Version >= SegmentVersion.v2_1) {
|
if (newSeg.Version >= SegmentVersion.v2_1) {
|
||||||
newSeg.AddRaw("tempORG", newSeg.TempOrg, 4, string.Empty);
|
newSeg.AddRaw("TEMPORG", newSeg.TempOrg, 4, string.Empty);
|
||||||
}
|
}
|
||||||
newSeg.AddRaw("LOADNAME", loadName, 10, string.Empty);
|
newSeg.AddRaw("LOADNAME", loadName, 10, string.Empty);
|
||||||
}
|
}
|
||||||
@ -475,6 +481,38 @@ namespace SourceGen.Tools.Omf {
|
|||||||
return ParseResult.Success;
|
return ParseResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool ParseBody(Formatter formatter, List<string> msgs) {
|
||||||
|
int offset = FileOffset + DispData;
|
||||||
|
while (true) {
|
||||||
|
bool result = OmfRecord.ParseRecord(mFileData, offset, Version, LabLen,
|
||||||
|
formatter, msgs, out OmfRecord omfRec);
|
||||||
|
if (!result) {
|
||||||
|
// Parsing failure. Bail out.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (offset + omfRec.Length > FileOffset + FileLength) {
|
||||||
|
// Overrun.
|
||||||
|
AddErrorMsg(msgs, offset, "record ran off end of file (" + omfRec + ")");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (omfRec.Op == OmfRecord.Opcode.END) {
|
||||||
|
// v0/v1 pad to 512-byte block boundaries, so this is expected there, but v2.x
|
||||||
|
// should be snug. Doesn't have to be, but might indicate a parsing error.
|
||||||
|
int remaining = (FileOffset + FileLength) - (offset + omfRec.Length);
|
||||||
|
Debug.Assert(remaining >= 0);
|
||||||
|
Debug.WriteLine("END record found, remaining space=" + remaining);
|
||||||
|
if (remaining >= 512 || (Version >= SegmentVersion.v2_0 && remaining != 0)) {
|
||||||
|
AddInfoMsg(msgs, offset, "found " + remaining + " bytes past END record");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Records.Add(omfRec);
|
||||||
|
offset += omfRec.Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Helper functions.
|
// Helper functions.
|
||||||
//
|
//
|
||||||
@ -485,10 +523,10 @@ namespace SourceGen.Tools.Omf {
|
|||||||
}
|
}
|
||||||
RawValues.Add(new NameValueNote(name, value, width, note));
|
RawValues.Add(new NameValueNote(name, value, width, note));
|
||||||
}
|
}
|
||||||
private static void AddInfoMsg(List<string> msgs, int offset, string msg) {
|
public static void AddInfoMsg(List<string> msgs, int offset, string msg) {
|
||||||
msgs.Add("Note (+" + offset.ToString("x6") + "): " + msg);
|
msgs.Add("Note (+" + offset.ToString("x6") + "): " + msg);
|
||||||
}
|
}
|
||||||
private static void AddErrorMsg(List<string> msgs, int offset, string msg) {
|
public static void AddErrorMsg(List<string> msgs, int offset, string msg) {
|
||||||
msgs.Add("Error (+" + offset.ToString("x6") + "): " + msg);
|
msgs.Add("Error (+" + offset.ToString("x6") + "): " + msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ limitations under the License.
|
|||||||
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
|
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
|
||||||
|
|
||||||
<system:String x:Key="str_FileOffsetLenFmt">File offset {0}, length {1} ({2})</system:String>
|
<system:String x:Key="str_FileOffsetLenFmt">File offset {0}, length {1} ({2})</system:String>
|
||||||
|
<system:String x:Key="str_RecordHeaderFmt">Records ({0}):</system:String>
|
||||||
</Window.Resources>
|
</Window.Resources>
|
||||||
|
|
||||||
<Grid Margin="8">
|
<Grid Margin="8">
|
||||||
@ -44,7 +45,7 @@ limitations under the License.
|
|||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<TextBlock Grid.Row="0" Text="{Binding FileOffsetLen, FallbackValue=File Offset / Length}" Margin="0,8,0,0"/>
|
<TextBlock Grid.Row="0" Text="{Binding FileOffsetLenStr, FallbackValue=File Offset / Length}" Margin="0,8,0,0"/>
|
||||||
|
|
||||||
<TextBlock Grid.Row="1" Text="Header fields:" Margin="0,8,0,0"/>
|
<TextBlock Grid.Row="1" Text="Header fields:" Margin="0,8,0,0"/>
|
||||||
<DataGrid Name="headerList" Grid.Row="2" Height="130" Margin="0,8,0,0"
|
<DataGrid Name="headerList" Grid.Row="2" Height="130" Margin="0,8,0,0"
|
||||||
@ -73,7 +74,7 @@ limitations under the License.
|
|||||||
</DataGrid.Columns>
|
</DataGrid.Columns>
|
||||||
</DataGrid>
|
</DataGrid>
|
||||||
|
|
||||||
<TextBlock Grid.Row="3" Text="Records {N}:" Margin="0,8,0,0"/>
|
<TextBlock Grid.Row="3" Text="{Binding RecordHeaderStr, FallbackValue=Records (123):}" Margin="0,8,0,0"/>
|
||||||
<DataGrid Name="recordList" Grid.Row="4" Height="130" Margin="0,8,0,0"
|
<DataGrid Name="recordList" Grid.Row="4" Height="130" Margin="0,8,0,0"
|
||||||
IsReadOnly="True"
|
IsReadOnly="True"
|
||||||
ItemsSource="{Binding RecordItems}"
|
ItemsSource="{Binding RecordItems}"
|
||||||
@ -94,9 +95,9 @@ limitations under the License.
|
|||||||
Color="{x:Static SystemColors.HighlightTextColor}"/>
|
Color="{x:Static SystemColors.HighlightTextColor}"/>
|
||||||
</DataGrid.Resources>
|
</DataGrid.Resources>
|
||||||
<DataGrid.Columns>
|
<DataGrid.Columns>
|
||||||
<DataGridTextColumn Header="Type" Width="100" Binding="{Binding Type}"/>
|
<DataGridTextColumn Header="OpName" Width="80" Binding="{Binding OpName}"/>
|
||||||
<DataGridTextColumn Header="Len" Width="40" Binding="{Binding Len}"/>
|
<DataGridTextColumn Header="Length" Width="80" Binding="{Binding Length}"/>
|
||||||
<DataGridTextColumn Header="Value" Width="300" Binding="{Binding Value}"/>
|
<DataGridTextColumn Header="Value" Width="380" Binding="{Binding Value}"/>
|
||||||
</DataGrid.Columns>
|
</DataGrid.Columns>
|
||||||
</DataGrid>
|
</DataGrid>
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ namespace SourceGen.Tools.Omf.WpfGui {
|
|||||||
/// Apple IIgs OMF segment viewer.
|
/// Apple IIgs OMF segment viewer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class OmfSegmentViewer : Window, INotifyPropertyChanged {
|
public partial class OmfSegmentViewer : Window, INotifyPropertyChanged {
|
||||||
private OmfFile mOmfFile;
|
//private OmfFile mOmfFile;
|
||||||
private OmfSegment mOmfSeg;
|
private OmfSegment mOmfSeg;
|
||||||
private Formatter mFormatter;
|
private Formatter mFormatter;
|
||||||
|
|
||||||
@ -36,10 +36,16 @@ namespace SourceGen.Tools.Omf.WpfGui {
|
|||||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||||
}
|
}
|
||||||
|
|
||||||
private string mFileOffsetLen;
|
private string mFileOffsetLenStr;
|
||||||
public string FileOffsetLen {
|
public string FileOffsetLenStr {
|
||||||
get { return mFileOffsetLen; }
|
get { return mFileOffsetLenStr; }
|
||||||
set { mFileOffsetLen = value; OnPropertyChanged(); }
|
set { mFileOffsetLenStr = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
private string mRecordHeaderStr;
|
||||||
|
public string RecordHeaderStr {
|
||||||
|
get { return mRecordHeaderStr; }
|
||||||
|
set { mRecordHeaderStr = value; OnPropertyChanged(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class HeaderItem {
|
public class HeaderItem {
|
||||||
@ -55,12 +61,7 @@ namespace SourceGen.Tools.Omf.WpfGui {
|
|||||||
}
|
}
|
||||||
public List<HeaderItem> HeaderItems { get; private set; } = new List<HeaderItem>();
|
public List<HeaderItem> HeaderItems { get; private set; } = new List<HeaderItem>();
|
||||||
|
|
||||||
public class RecordItem {
|
public List<OmfRecord> RecordItems { get; private set; }
|
||||||
public string Type { get; private set; }
|
|
||||||
public string Len { get; private set; }
|
|
||||||
public string Value { get; private set; }
|
|
||||||
}
|
|
||||||
public List<RecordItem> RecordItems { get; private set; } = new List<RecordItem>();
|
|
||||||
|
|
||||||
public class RelocItem {
|
public class RelocItem {
|
||||||
public string Offset { get; private set; }
|
public string Offset { get; private set; }
|
||||||
@ -84,17 +85,22 @@ namespace SourceGen.Tools.Omf.WpfGui {
|
|||||||
Owner = owner;
|
Owner = owner;
|
||||||
DataContext = this;
|
DataContext = this;
|
||||||
|
|
||||||
mOmfFile = omfFile;
|
//mOmfFile = omfFile;
|
||||||
mOmfSeg = omfSeg;
|
mOmfSeg = omfSeg;
|
||||||
mFormatter = formatter;
|
mFormatter = formatter;
|
||||||
|
|
||||||
string fmt = (string)FindResource("str_FileOffsetLenFmt");
|
string fmt = (string)FindResource("str_FileOffsetLenFmt");
|
||||||
FileOffsetLen = string.Format(fmt,
|
FileOffsetLenStr = string.Format(fmt,
|
||||||
mFormatter.FormatOffset24(omfSeg.FileOffset),
|
mFormatter.FormatOffset24(omfSeg.FileOffset),
|
||||||
omfSeg.FileLength,
|
omfSeg.FileLength,
|
||||||
mFormatter.FormatHexValue(omfSeg.FileLength, 4));
|
mFormatter.FormatHexValue(omfSeg.FileLength, 4));
|
||||||
|
|
||||||
GenerateHeaderItems();
|
GenerateHeaderItems();
|
||||||
|
|
||||||
|
RecordItems = omfSeg.Records;
|
||||||
|
|
||||||
|
fmt = (string)FindResource("str_RecordHeaderFmt");
|
||||||
|
RecordHeaderStr = string.Format(fmt, RecordItems.Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GenerateHeaderItems() {
|
private void GenerateHeaderItems() {
|
||||||
|
@ -75,7 +75,7 @@ limitations under the License.
|
|||||||
</DataGrid.Columns>
|
</DataGrid.Columns>
|
||||||
</DataGrid>
|
</DataGrid>
|
||||||
|
|
||||||
<TextBlock Grid.Row="3" Text="Notes and errors:" Margin="0,8,0,0"/>
|
<TextBlock Grid.Row="3" Text="Notes and error messages:" Margin="0,8,0,0"/>
|
||||||
<TextBox Grid.Row="4" Margin="0,4,0,0" Height="60"
|
<TextBox Grid.Row="4" Margin="0,4,0,0" Height="60"
|
||||||
Text="{Binding MessageStrings}"
|
Text="{Binding MessageStrings}"
|
||||||
IsReadOnly="True" VerticalScrollBarVisibility="Auto">
|
IsReadOnly="True" VerticalScrollBarVisibility="Auto">
|
||||||
|
@ -105,7 +105,7 @@ namespace SourceGen.Tools.Omf.WpfGui {
|
|||||||
mFormatter = formatter;
|
mFormatter = formatter;
|
||||||
|
|
||||||
mOmfFile = new OmfFile(data);
|
mOmfFile = new OmfFile(data);
|
||||||
mOmfFile.Analyze();
|
mOmfFile.Analyze(mFormatter);
|
||||||
|
|
||||||
foreach (OmfSegment omfSeg in mOmfFile.SegmentList) {
|
foreach (OmfSegment omfSeg in mOmfFile.SegmentList) {
|
||||||
SegmentListItems.Add(new SegmentListItem(omfSeg));
|
SegmentListItems.Add(new SegmentListItem(omfSeg));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user